Skip to content

Commit

Permalink
src: enable more detailed memory tracking
Browse files Browse the repository at this point in the history
This will enable more detailed heap snapshots based on
a newer V8 API.

This commit itself is not tied to that API and could
be backported.

PR-URL: #21742
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
addaleax authored and targos committed Jul 14, 2018
1 parent f46536b commit 712809e
Show file tree
Hide file tree
Showing 46 changed files with 566 additions and 91 deletions.
2 changes: 2 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,8 @@
'src/node_revert.h',
'src/node_i18n.h',
'src/node_worker.h',
'src/memory_tracker.h',
'src/memory_tracker-inl.h',
'src/pipe_wrap.h',
'src/tty_wrap.h',
'src/tcp_wrap.h',
Expand Down
21 changes: 17 additions & 4 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,22 @@ class RetainedAsyncInfo: public RetainedObjectInfo {
private:
const char* label_;
const AsyncWrap* wrap_;
const int length_;
const size_t length_;
};


static int OwnMemory(AsyncWrap* async_wrap) {
MemoryTracker tracker;
tracker.set_track_only_self(true);
tracker.Track(async_wrap);
return tracker.accumulated_size();
}


RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap)
: label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]),
wrap_(wrap),
length_(wrap->self_size()) {
length_(OwnMemory(wrap)) {
}


Expand Down Expand Up @@ -147,7 +155,9 @@ struct AsyncWrapObject : public AsyncWrap {
inline AsyncWrapObject(Environment* env, Local<Object> object,
ProviderType type) : AsyncWrap(env, object, type) {}

inline size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};


Expand Down Expand Up @@ -252,7 +262,10 @@ class PromiseWrap : public AsyncWrap {
: AsyncWrap(env, object, PROVIDER_PROMISE, -1, silent) {
MakeWeak();
}
size_t self_size() const override { return sizeof(*this); }

void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

static constexpr int kPromiseField = 1;
static constexpr int kIsChainedPromiseField = 2;
Expand Down
1 change: 0 additions & 1 deletion src/async_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ class AsyncWrap : public BaseObject {
int argc,
v8::Local<v8::Value>* argv);

virtual size_t self_size() const = 0;
virtual std::string diagnostic_name() const;

static void WeakCallback(const v8::WeakCallbackInfo<DestroyParam> &info);
Expand Down
10 changes: 2 additions & 8 deletions src/base_object-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ Persistent<v8::Object>& BaseObject::persistent() {
}


v8::Local<v8::Object> BaseObject::object() {
v8::Local<v8::Object> BaseObject::object() const {
return PersistentToLocal(env_->isolate(), persistent_handle_);
}

v8::Local<v8::Object> BaseObject::object(v8::Isolate* isolate) {
v8::Local<v8::Object> BaseObject::object(v8::Isolate* isolate) const {
v8::Local<v8::Object> handle = object();
#ifdef DEBUG
CHECK_EQ(handle->CreationContext()->GetIsolate(), isolate);
Expand All @@ -91,12 +91,6 @@ T* BaseObject::FromJSObject(v8::Local<v8::Object> object) {
}


void BaseObject::DeleteMe(void* data) {
BaseObject* self = static_cast<BaseObject*>(data);
delete self;
}


void BaseObject::MakeWeak() {
persistent_handle_.SetWeak(
this,
Expand Down
13 changes: 9 additions & 4 deletions src/base_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "node_persistent.h"
#include "memory_tracker-inl.h"
#include "v8.h"
#include <type_traits> // std::remove_reference

namespace node {

class Environment;

class BaseObject {
class BaseObject : public MemoryRetainer {
public:
// Associates this object with `object`. It uses the 0th internal field for
// that, and in particular aborts if there is no such field.
Expand All @@ -41,11 +42,11 @@ class BaseObject {

// Returns the wrapped object. Returns an empty handle when
// persistent.IsEmpty() is true.
inline v8::Local<v8::Object> object();
inline v8::Local<v8::Object> object() const;

// Same as the above, except it additionally verifies that this object
// is associated with the passed Isolate in debug mode.
inline v8::Local<v8::Object> object(v8::Isolate* isolate);
inline v8::Local<v8::Object> object(v8::Isolate* isolate) const;

inline Persistent<v8::Object>& persistent();

Expand Down Expand Up @@ -75,14 +76,18 @@ class BaseObject {
private:
BaseObject();

static inline void DeleteMe(void* data);
v8::Local<v8::Object> WrappedObject() const override;
bool IsRootNode() const override;
static void DeleteMe(void* data);

// persistent_handle_ needs to be at a fixed offset from the start of the
// class because it is used by src/node_postmortem_metadata.cc to calculate
// offsets and generate debug symbols for BaseObject, which assumes that the
// position of members in memory are predictable. For more information please
// refer to `doc/guides/node-postmortem-support.md`
friend int GenDebugSymbols();
friend class Environment;

Persistent<v8::Object> persistent_handle_;
Environment* env_;
};
Expand Down
77 changes: 59 additions & 18 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,12 @@ inline const char* ToErrorCodeString(int status) {

class ChannelWrap;

struct node_ares_task {
struct node_ares_task : public MemoryRetainer {
ChannelWrap* channel;
ares_socket_t sock;
uv_poll_t poll_watcher;

void MemoryInfo(MemoryTracker* tracker) const override;
};

struct TaskHash {
Expand Down Expand Up @@ -167,7 +169,12 @@ class ChannelWrap : public AsyncWrap {
inline int active_query_count() { return active_query_count_; }
inline node_ares_task_list* task_list() { return &task_list_; }

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
if (timer_handle_ != nullptr)
tracker->TrackFieldWithSize("timer handle", sizeof(*timer_handle_));
tracker->TrackField("task list", task_list_);
}

static void AresTimeout(uv_timer_t* handle);

Expand All @@ -181,6 +188,11 @@ class ChannelWrap : public AsyncWrap {
node_ares_task_list task_list_;
};

void node_ares_task::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackThis(this);
tracker->TrackField("channel", channel);
}

ChannelWrap::ChannelWrap(Environment* env,
Local<Object> object)
: AsyncWrap(env, object, PROVIDER_DNSCHANNEL),
Expand Down Expand Up @@ -209,7 +221,10 @@ class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
Local<Object> req_wrap_obj,
bool verbatim);

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

bool verbatim() const { return verbatim_; }

private:
Expand All @@ -228,7 +243,9 @@ class GetNameInfoReqWrap : public ReqWrap<uv_getnameinfo_t> {
public:
GetNameInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};

GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env,
Expand Down Expand Up @@ -270,13 +287,13 @@ void ares_poll_cb(uv_poll_t* watcher, int status, int events) {

void ares_poll_close_cb(uv_poll_t* watcher) {
node_ares_task* task = ContainerOf(&node_ares_task::poll_watcher, watcher);
free(task);
delete task;
}


/* Allocates and returns a new node_ares_task */
node_ares_task* ares_task_create(ChannelWrap* channel, ares_socket_t sock) {
auto task = node::UncheckedMalloc<node_ares_task>(1);
auto task = new node_ares_task();

if (task == nullptr) {
/* Out of memory. */
Expand Down Expand Up @@ -1172,7 +1189,9 @@ class QueryAnyWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1349,7 +1368,9 @@ class QueryAWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1393,7 +1414,9 @@ class QueryAaaaWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1437,7 +1460,9 @@ class QueryCnameWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1468,7 +1493,9 @@ class QueryMxWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1499,7 +1526,9 @@ class QueryNsWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1530,7 +1559,9 @@ class QueryTxtWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1560,7 +1591,9 @@ class QuerySrvWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1589,7 +1622,9 @@ class QueryPtrWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1620,7 +1655,9 @@ class QueryNaptrWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1650,7 +1687,9 @@ class QuerySoaWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(unsigned char* buf, int len) override {
Expand Down Expand Up @@ -1729,7 +1768,9 @@ class GetHostByAddrWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

protected:
void Parse(struct hostent* host) override {
Expand Down
4 changes: 3 additions & 1 deletion src/connect_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ class ConnectWrap : public ReqWrap<uv_connect_t> {
v8::Local<v8::Object> req_wrap_obj,
AsyncWrap::ProviderType provider);

size_t self_size() const override { return sizeof(*this); }
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}
};

} // namespace node
Expand Down
14 changes: 14 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -653,4 +653,18 @@ void Environment::stop_sub_worker_contexts() {
}
}

// Not really any better place than env.cc at this moment.
void BaseObject::DeleteMe(void* data) {
BaseObject* self = static_cast<BaseObject*>(data);
delete self;
}

Local<Object> BaseObject::WrappedObject() const {
return object();
}

bool BaseObject::IsRootNode() const {
return !persistent_handle_.IsWeak();
}

} // namespace node
5 changes: 4 additions & 1 deletion src/fs_event_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ class FSEventWrap: public HandleWrap {
static void New(const FunctionCallbackInfo<Value>& args);
static void Start(const FunctionCallbackInfo<Value>& args);
static void GetInitialized(const FunctionCallbackInfo<Value>& args);
size_t self_size() const override { return sizeof(*this); }

void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackThis(this);
}

private:
static const encoding kDefaultEncoding = UTF8;
Expand Down
Loading

0 comments on commit 712809e

Please sign in to comment.