Skip to content
Browse files

Prepare to v5.0.0

Now compatible with NodeJS v0.11.13
Added prefixes for cpu and heap files
  (profile.cc -> cpu_profile.cc)
Added Heap_Graph API
Updated Nan dependence to 1.2.0
Rewrited HEAP getHeapStats
  (now receives iterator and callback functions)
Cleared JS API
  • Loading branch information...
1 parent f47b6c5 commit 77b814d1b813e85028613ba5c036fc80694c89db @3y3 3y3 committed Jun 5, 2014
View
13 binding.gyp
@@ -3,16 +3,19 @@
{
'target_name': 'profiler',
'sources': [
+ 'src/profiler.cc',
'src/cpu_profiler.cc',
+ 'src/cpu_profile.cc',
+ 'src/cpu_profile_node.cc',
'src/heap_profiler.cc',
- 'src/profile.cc',
- 'src/profile_node.cc',
- 'src/profiler.cc',
- 'src/snapshot.cc',
+ 'src/heap_snapshot.cc',
+ 'src/heap_output_stream.cc',
+ 'src/heap_graph_node.cc',
+ 'src/heap_graph_edge.cc'
],
'include_dirs' : [
"<!(node -e \"require('nan')\")"
- ],
+ ]
}
]
}
View
2 package.json
@@ -20,6 +20,6 @@
"postinstall": "ln -sf build/Release/profiler.node profiler.node"
},
"dependencies": {
- "nan": "~0.8.0"
+ "nan": "~1.2.0"
}
}
View
105 src/cpu_profile.cc
@@ -0,0 +1,105 @@
+#include "cpu_profile.h"
+#include "cpu_profile_node.h"
+
+namespace nodex {
+ using v8::Array;
+ using v8::CpuProfile;
+ using v8::CpuProfileNode;
+ using v8::Handle;
+ using v8::Number;
+ using v8::Integer;
+ using v8::Local;
+ using v8::Object;
+ using v8::ObjectTemplate;
+ using v8::Persistent;
+ using v8::String;
+ using v8::Function;
+ using v8::Value;
+
+ Persistent<ObjectTemplate> Profile::profile_template_;
+ Persistent<Array> Profile::profiles;
+ uint32_t Profile::uid_counter = 0;
+
+ void Profile::Initialize () {
+ NanScope();
+
+ Local<ObjectTemplate> o = NanNew<ObjectTemplate>();
+ o->SetInternalFieldCount(1);
+ NODE_SET_METHOD(o, "delete", Profile::Delete);
+ NanAssignPersistent(profile_template_, o);
+ }
+
+ NAN_METHOD(Profile::Delete) {
+ NanScope();
+
+ Handle<Object> self = args.This();
+ void* ptr = NanGetInternalFieldPointer(self, 0);
+ Local<Array> profiles = NanNew<Array>(Profile::profiles);
+
+ uint32_t count = profiles->Length();
+ for (uint32_t index = 0; index < count; index++) {
+ if (profiles->Get(index) == args.This()) {
+ Local<Value> argv[2] = {
+ NanNew<Integer>(index),
+ NanNew<Integer>(1)
+ };
+ Handle<Function>::Cast(profiles->Get(NanNew<String>("splice")))->Call(profiles, 2, argv);
+ break;
+ }
+ }
+ static_cast<CpuProfile*>(ptr)->Delete();
+
+ NanReturnUndefined();
+ }
+
+ Handle<Value> Profile::New (const CpuProfile* node) {
+ NanEscapableScope();
+
+ if (profile_template_.IsEmpty()) {
+ Profile::Initialize();
+ }
+
+ uid_counter++;
+
+ Local<Object> profile = NanNew(profile_template_)->NewInstance();
+ NanSetInternalFieldPointer(profile, 0, const_cast<CpuProfile*>(node));
+
+ Local<Value> CPU = NanNew<String>("CPU");
+ Local<Value> uid = NanNew<Integer>(uid_counter);
+ Handle<String> title = node->GetTitle();
+ if (!title->Length()) {
+ char _title[32];
+ sprintf(_title, "Profile %i", uid_counter);
+ title = NanNew<String>(_title);
+ }
+ Handle<Value> head = ProfileNode::New(node->GetTopDownRoot());
+
+ profile->Set(NanNew<String>("typeId"), CPU);
+ profile->Set(NanNew<String>("uid"), uid);
+ profile->Set(NanNew<String>("title"), title);
+ profile->Set(NanNew<String>("head"), head);
+
+#if (NODE_MODULE_VERSION > 0x000B)
+ Local<Value> start_time = NanNew<Number>(node->GetStartTime()/1000000);
+ Local<Value> end_time = NanNew<Number>(node->GetEndTime()/1000000);
+ Local<Array> samples = NanNew<Array>();
+
+ uint32_t count = node->GetSamplesCount();
+ for (uint32_t index = 0; index < count; ++index) {
+ samples->Set(index, ProfileNode::New(node->GetSample(index)));
+ }
+
+ profile->Set(NanNew<String>("startTime"), start_time);
+ profile->Set(NanNew<String>("endTime"), end_time);
+ profile->Set(NanNew<String>("samples"), samples);
+#else
+ Handle<Value> bottom = ProfileNode::New(node->GetBottomUpRoot());
+ profile->Set(NanNew<String>("bottomRoot"), bottom);
+#endif
+
+ Local<Array> profiles = NanNew<Array>(Profile::profiles);
+ profiles->Set(profiles->Length(), profile);
+
+ return NanEscapeScope(profile);
+ }
+}
View
21 src/cpu_profile.h
@@ -0,0 +1,21 @@
+#ifndef NODE_PROFILE_
+#define NODE_PROFILE_
+
+#include "v8-profiler.h"
+#include "nan.h"
+
+namespace nodex {
+
+ class Profile {
+ public:
+ static v8::Handle<v8::Value> New(const v8::CpuProfile* node);
+ static v8::Persistent<v8::Array> profiles;
+ private:
+ static NAN_METHOD(Delete);
+ static void Initialize();
+ static v8::Persistent<v8::ObjectTemplate> profile_template_;
+ static uint32_t uid_counter;
+ };
+
+} //namespace nodex
+#endif // NODE_PROFILE_
View
44 src/cpu_profile_node.cc
@@ -0,0 +1,44 @@
+#include "cpu_profile_node.h"
+
+namespace nodex {
+ using v8::CpuProfileNode;
+ using v8::Handle;
+ using v8::String;
+ using v8::Number;
+ using v8::Integer;
+ using v8::Value;
+ using v8::Local;
+ using v8::Object;
+ using v8::Array;
+
+ Handle<Value> ProfileNode::New (const CpuProfileNode* node) {
+ NanEscapableScope();
+
+ int32_t count = node->GetChildrenCount();
+ Local<Object> profile_node = NanNew<Object>();
+ Local<Array> children = NanNew<Array>(count);
+
+ for (int32_t index = 0; index < count; index++) {
+ children->Set(index, ProfileNode::New(node->GetChild(index)));
+ }
+
+ profile_node->Set(NanNew<String>("functionName"), NanNew<String>(node->GetFunctionName()));
+ profile_node->Set(NanNew<String>("url"), NanNew<String>(node->GetScriptResourceName()));
+ profile_node->Set(NanNew<String>("lineNumber"), NanNew<Integer>(node->GetLineNumber()));
+ profile_node->Set(NanNew<String>("callUID"), NanNew<Number>(node->GetCallUid()));
+#if (NODE_MODULE_VERSION > 0x000B)
+ profile_node->Set(NanNew<String>("bailoutReason"), NanNew<String>(node->GetBailoutReason()));
+ profile_node->Set(NanNew<String>("id"), NanNew<Integer>(node->GetNodeId()));
+ profile_node->Set(NanNew<String>("scriptId"), NanNew<Integer>(node->GetScriptId()));
+ profile_node->Set(NanNew<String>("hitCount"), NanNew<Integer>(node->GetHitCount()));
+#else
+ profile_node->Set(NanNew<String>("totalTime"), NanNew<Integer>(node->GetTotalTime()));
+ profile_node->Set(NanNew<String>("selfTime"), NanNew<Integer>(node->GetSelfTime()));
+ profile_node->Set(NanNew<String>("totalSamplesCount"), NanNew<Integer>(node->GetTotalSamplesCount()));
+ profile_node->Set(NanNew<String>("selfSamplesCount"), NanNew<Integer>(node->GetSelfSamplesCount()));
+#endif
+ profile_node->Set(NanNew<String>("children"), children);
+
+ return NanEscapeScope(profile_node);
+ }
+}
View
15 src/cpu_profile_node.h
@@ -0,0 +1,15 @@
+#ifndef NODE_PROFILE_NODE_
+#define NODE_PROFILE_NODE_
+
+#include "v8-profiler.h"
+#include "nan.h"
+
+namespace nodex {
+
+class ProfileNode {
+ public:
+ static v8::Handle<v8::Value> New(const v8::CpuProfileNode* node);
+};
+
+}
+#endif // NODE_PROFILE_NODE_
View
164 src/cpu_profiler.cc
@@ -1,114 +1,88 @@
#include "cpu_profiler.h"
-#include "profile.h"
+#include "cpu_profile.h"
namespace nodex {
- Persistent<ObjectTemplate> CpuProfiler::cpu_profiler_template_;
+ using v8::CpuProfile;
+ using v8::Handle;
+ using v8::Local;
+ using v8::Object;
+ using v8::Array;
+ using v8::String;
- void CpuProfiler::Initialize(Handle<Object> target) {
- NanScope();
+ CpuProfiler::CpuProfiler () {}
+ CpuProfiler::~CpuProfiler () {}
- Local<ObjectTemplate> tpl = NanNewLocal<ObjectTemplate>(ObjectTemplate::New());
- NanAssignPersistent(ObjectTemplate, cpu_profiler_template_, tpl);
- tpl->SetInternalFieldCount(1);
+ void CpuProfiler::Initialize (Handle<Object> target) {
+ NanScope();
+
+ Local<Object> cpuProfiler = NanNew<Object>();
+ Local<Array> profiles = NanNew<Array>();
+
+ NODE_SET_METHOD(cpuProfiler, "startProfiling", CpuProfiler::StartProfiling);
+ NODE_SET_METHOD(cpuProfiler, "stopProfiling", CpuProfiler::StopProfiling);
+ cpuProfiler->Set(NanNew<String>("profiles"), profiles);
+
+ NanAssignPersistent(Profile::profiles, profiles);
+ target->Set(NanNew<String>("cpu"), cpuProfiler);
+ }
- Local<Object> cpuProfilerObj = tpl->NewInstance();
-
- NODE_SET_METHOD(cpuProfilerObj, "getProfilesCount", CpuProfiler::GetProfilesCount);
- NODE_SET_METHOD(cpuProfilerObj, "getProfile", CpuProfiler::GetProfile);
- NODE_SET_METHOD(cpuProfilerObj, "findProfile", CpuProfiler::FindProfile);
- NODE_SET_METHOD(cpuProfilerObj, "startProfiling", CpuProfiler::StartProfiling);
- NODE_SET_METHOD(cpuProfilerObj, "stopProfiling", CpuProfiler::StopProfiling);
- NODE_SET_METHOD(cpuProfilerObj, "deleteAllProfiles", CpuProfiler::DeleteAllProfiles);
-
- target->Set(String::NewSymbol("cpuProfiler"), cpuProfilerObj);
- }
-
- CpuProfiler::CpuProfiler() {}
- CpuProfiler::~CpuProfiler() {}
-
- NAN_METHOD(CpuProfiler::GetProfilesCount) {
- NanScope();
-#if (NODE_MODULE_VERSION > 0x000B)
- int ret = nan_isolate->GetCpuProfiler()->GetProfileCount();
-#else
- int ret = v8::CpuProfiler::GetProfilesCount();
-#endif
- NanReturnValue(Integer::New(ret));
- }
-
- NAN_METHOD(CpuProfiler::GetProfile) {
- NanScope();
- if (args.Length() < 1) {
- return NanThrowError("No index specified");
- } else if (!args[0]->IsInt32()) {
- return NanThrowError("Argument must be an integer");
+ NAN_METHOD(CpuProfiler::StartProfiling) {
+ NanScope();
+
+ bool recsamples = false;
+ Local<String> title = NanNew<String>("");
+ if (args.Length()) {
+ if (args.Length()>1) {
+ if (args[1]->IsBoolean()) {
+ recsamples = args[1]->ToBoolean()->Value();
+ } else if (!args[1]->IsUndefined()) {
+ return NanThrowTypeError("Wrong argument [1] type (wait Boolean)");
}
- int32_t index = args[0]->Int32Value();
-#if (NODE_MODULE_VERSION > 0x000B)
- const CpuProfile* profile = nan_isolate->GetCpuProfiler()->GetCpuProfile(index);
-#else
- const CpuProfile* profile = v8::CpuProfiler::GetProfile(index);
-#endif
- NanReturnValue(Profile::New(profile));
- }
-
- NAN_METHOD(CpuProfiler::FindProfile) {
- NanScope();
- if (args.Length() < 1) {
- return NanThrowError("No index specified");
- } else if (!args[0]->IsInt32()) {
- return NanThrowError("Argument must be an integer");
+ if (args[0]->IsString()) {
+ title = args[0]->ToString();
+ } else if (!args[0]->IsUndefined()) {
+ return NanThrowTypeError("Wrong argument [0] type (wait String)");
}
- uint32_t uid = args[0]->Uint32Value();
- const CpuProfile* profile;
-
-#if (NODE_MODULE_VERSION > 0x000B)
- bool notFound = true;
- int count = nan_isolate->GetCpuProfiler()->GetProfileCount();
- for (int32_t index = 1; index < count; index++) {
- profile = nan_isolate->GetCpuProfiler()->GetCpuProfile(index);
- if (profile->GetUid() == uid) {
- notFound = false;
- break;
- }
+ } else {
+ if (args[0]->IsString()) {
+ title = args[0]->ToString();
+ } else if (args[0]->IsBoolean()) {
+ recsamples = args[0]->ToBoolean()->Value();
+ } else if (!args[0]->IsUndefined()) {
+ return NanThrowTypeError("Wrong argument [0] type (wait String or Boolean)");
}
- if (notFound) {
- NanReturnNull();
- }
-#else
- profile = v8::CpuProfiler::FindProfile(uid);
-#endif
- NanReturnValue(Profile::New(profile));
+ }
}
-
- NAN_METHOD(CpuProfiler::StartProfiling) {
- NanScope();
- Local<String> title = args.Length() > 0 ? args[0]->ToString() : String::New("");
+
#if (NODE_MODULE_VERSION > 0x000B)
- nan_isolate->GetCpuProfiler()->StartCpuProfiling(title);
+ v8::Isolate::GetCurrent()->GetCpuProfiler()->StartProfiling(title, recsamples);
#else
- v8::CpuProfiler::StartProfiling(title);
+ v8::CpuProfiler::StartProfiling(title);
#endif
- NanReturnUndefined();
- }
- NAN_METHOD(CpuProfiler::StopProfiling) {
- NanScope();
- Local<String> title = args.Length() > 0 ? args[0]->ToString() : String::New("");
-#if (NODE_MODULE_VERSION > 0x000B)
- const CpuProfile* profile = nan_isolate->GetCpuProfiler()->StopCpuProfiling(title);
-#else
- const CpuProfile* profile = v8::CpuProfiler::StopProfiling(title);
-#endif
- NanReturnValue(Profile::New(profile));
- }
+ NanReturnUndefined();
+ }
- NAN_METHOD(CpuProfiler::DeleteAllProfiles) {
+ NAN_METHOD(CpuProfiler::StopProfiling) {
+ NanScope();
+
+ const CpuProfile* profile;
+
+ Local<String> title = NanNew<String>("");
+ if (args.Length()) {
+ if (args[0]->IsString()) {
+ title = args[0]->ToString();
+ } else if (!args[0]->IsUndefined()) {
+ return NanThrowTypeError("Wrong argument [0] type (wait String)");
+ }
+ }
+
#if (NODE_MODULE_VERSION > 0x000B)
- nan_isolate->GetCpuProfiler()->DeleteAllCpuProfiles();
+ profile = v8::Isolate::GetCurrent()->GetCpuProfiler()->StopProfiling(title);
#else
- v8::CpuProfiler::DeleteAllProfiles();
+ profile = v8::CpuProfiler::StopProfiling(title);
#endif
- NanReturnUndefined();
- }
+
+ NanReturnValue(Profile::New(profile));
+ }
} //namespace nodex
View
32 src/cpu_profiler.h
@@ -1,32 +1,22 @@
#ifndef NODE_CPU_PROFILER_
#define NODE_CPU_PROFILER_
-#include <node.h>
-#include <v8-profiler.h>
+#include "v8-profiler.h"
+#include "node.h"
#include "nan.h"
-using namespace v8;
-using namespace node;
-
namespace nodex {
- class CpuProfiler {
- public:
- static void Initialize(Handle<Object> target);
-
- CpuProfiler();
- virtual ~CpuProfiler();
+ class CpuProfiler {
+ public:
+ static void Initialize(v8::Handle<v8::Object> target);
- protected:
- static NAN_METHOD(GetProfilesCount);
- static NAN_METHOD(GetProfile);
- static NAN_METHOD(FindProfile);
- static NAN_METHOD(StartProfiling);
- static NAN_METHOD(StopProfiling);
- static NAN_METHOD(DeleteAllProfiles);
+ CpuProfiler();
+ virtual ~CpuProfiler();
- private:
- static Persistent<ObjectTemplate> cpu_profiler_template_;
- };
+ protected:
+ static NAN_METHOD(StartProfiling);
+ static NAN_METHOD(StopProfiling);
+ };
} //namespace nodex
#endif // NODE_CPU_PROFILER_H
View
55 src/heap_graph_edge.cc
@@ -0,0 +1,55 @@
+#include "heap_graph_node.h"
+#include "heap_graph_edge.h"
+
+namespace nodex {
+ using v8::Handle;
+ using v8::HeapGraphEdge;
+ using v8::Integer;
+ using v8::Local;
+ using v8::Object;
+ using v8::String;
+ using v8::Value;
+
+ Handle<Value> GraphEdge::New(const HeapGraphEdge* node) {
+ NanEscapableScope();
+
+ Local<Object> graph_edge = NanNew<Object>();
+
+ Local<Value> type;
+ switch (node->GetType()) {
+ case HeapGraphEdge::kContextVariable :
+ type = NanNew<String>("ContextVariable");
+ break;
+ case HeapGraphEdge::kElement :
+ type = NanNew<String>("Element");
+ break;
+ case HeapGraphEdge::kProperty :
+ type = NanNew<String>("Property");
+ break;
+ case HeapGraphEdge::kInternal :
+ type = NanNew<String>("Internal");
+ break;
+ case HeapGraphEdge::kHidden :
+ type = NanNew<String>("Hidden");
+ break;
+ case HeapGraphEdge::kShortcut :
+ type = NanNew<String>("Shortcut");
+ break;
+ case HeapGraphEdge::kWeak :
+ type = NanNew<String>("Weak");
+ break;
+ default :
+ type = NanNew<String>("Undefined");
+ }
+ Handle<Value> name = node->GetName();
+ Handle<Value> from = GraphNode::New(node->GetFromNode());
+ Handle<Value> to = GraphNode::New(node->GetToNode());
+
+ graph_edge->Set(NanNew<String>("type"), type);
+ graph_edge->Set(NanNew<String>("name"), name);
+ graph_edge->Set(NanNew<String>("from"), from);
+ graph_edge->Set(NanNew<String>("to"), to);
+
+ return NanEscapeScope(graph_edge);
+ }
+}
View
14 src/heap_graph_edge.h
@@ -0,0 +1,14 @@
+#ifndef NODE_GRAPH_EDGE_
+#define NODE_GRAPH_EDGE_
+
+#include "v8-profiler.h"
+#include "nan.h"
+
+namespace nodex {
+
+ class GraphEdge {
+ public:
+ static v8::Handle<v8::Value> New(const v8::HeapGraphEdge* node);
+ };
+} //namespace nodex
+#endif // NODE_GRAPH_EDGE_
View
118 src/heap_graph_node.cc
@@ -0,0 +1,118 @@
+#include "heap_graph_node.h"
+#include "heap_graph_edge.h"
+
+namespace nodex {
+ using v8::Array;
+ using v8::Handle;
+ using v8::HeapGraphNode;
+ using v8::Number;
+ using v8::Local;
+ using v8::Object;
+ using v8::ObjectTemplate;
+ using v8::Persistent;
+ using v8::String;
+ using v8::Value;
+
+
+ Persistent<ObjectTemplate> GraphNode::graph_node_template_;
+ Persistent<Object> GraphNode::graph_node_cache;
+
+ void GraphNode::Initialize () {
+ NanScope();
+
+ Local<ObjectTemplate> o = NanNew<ObjectTemplate>();
+ Local<Object> _cache = NanNew<Object>();
+ o->SetInternalFieldCount(1);
+ o->SetAccessor(NanNew<String>("children"), GraphNode::GetChildren);
+ NanAssignPersistent(graph_node_template_, o);
+ NanAssignPersistent(graph_node_cache, _cache);
+ }
+
+ NAN_GETTER(GraphNode::GetChildren) {
+ NanScope();
+
+ void* ptr = NanGetInternalFieldPointer(args.This(), 0);
+ HeapGraphNode* node = static_cast<HeapGraphNode*>(ptr);
+ uint32_t count = node->GetChildrenCount();
+ Local<Array> children = NanNew<Array>(count);
+ for (uint32_t index = 0; index < count; ++index) {
+ Handle<Value> child = GraphEdge::New(node->GetChild(index));
+ children->Set(index, child);
+ }
+ args.This()->Set(NanNew<String>("children"), children);
+ NanReturnValue(children);
+ }
+
+ Handle<Value> GraphNode::New(const HeapGraphNode* node) {
+ NanEscapableScope();
+
+ if (graph_node_template_.IsEmpty()) {
+ GraphNode::Initialize();
+ }
+
+ Local<Object> graph_node;
+ Local<Object> _cache = NanNew(graph_node_cache);
+ int32_t _id = node->GetId();
+ if (_cache->Has(_id)) {
+ graph_node = _cache->Get(_id)->ToObject();
+ } else {
+ graph_node = NanNew(graph_node_template_)->NewInstance();
+ NanSetInternalFieldPointer(graph_node, 0, const_cast<HeapGraphNode*>(node));
+
+ Local<Value> type;
+ switch (node->GetType()) {
+ case HeapGraphNode::kArray :
+ type = NanNew<String>("Array");
+ break;
+ case HeapGraphNode::kString :
+ type = NanNew<String>("String");
+ break;
+ case HeapGraphNode::kObject :
+ type = NanNew<String>("Object");
+ break;
+ case HeapGraphNode::kCode :
+ type = NanNew<String>("Code");
+ break;
+ case HeapGraphNode::kClosure :
+ type = NanNew<String>("Closure");
+ break;
+ case HeapGraphNode::kRegExp :
+ type = NanNew<String>("RegExp");
+ break;
+ case HeapGraphNode::kHeapNumber :
+ type = NanNew<String>("HeapNumber");
+ break;
+ case HeapGraphNode::kNative :
+ type = NanNew<String>("Native");
+ break;
+ case HeapGraphNode::kSynthetic :
+ type = NanNew<String>("Synthetic");
+ break;
+#if (NODE_MODULE_VERSION > 0x000B)
+ case HeapGraphNode::kConsString :
+ type = NanNew<String>("ConsString");
+ break;
+ case HeapGraphNode::kSlicedString :
+ type = NanNew<String>("SlicedString");
+ break;
+#endif
+ default :
+ type = NanNew<String>("Hidden");
+ }
+ Handle<Value> name = node->GetName();
+ Local<Value> id = NanNew<Number>(_id);
+ graph_node->Set(NanNew<String>("type"), type);
+ graph_node->Set(NanNew<String>("name"), name);
+ graph_node->Set(NanNew<String>("id"), id);
+
+#if (NODE_MODULE_VERSION > 0x000B)
+ Handle<Value> shallowSize = NanNew<Number>(node->GetShallowSize());
+ graph_node->Set(NanNew<String>("shallowSize"), shallowSize);
+#endif
+
+ _cache->Set(_id, graph_node);
+ }
+
+ return NanEscapeScope(graph_node);
+ }
+}
View
19 src/heap_graph_node.h
@@ -0,0 +1,19 @@
+#ifndef NODE_GRAPH_NODE_
+#define NODE_GRAPH_NODE_
+
+#include "v8-profiler.h"
+#include "nan.h"
+
+namespace nodex {
+
+ class GraphNode {
+ public:
+ static v8::Handle<v8::Value> New(const v8::HeapGraphNode* node);
+ private:
+ static void Initialize();
+ static NAN_GETTER(GetChildren);
+ static v8::Persistent<v8::ObjectTemplate> graph_node_template_;
+ static v8::Persistent<v8::Object> graph_node_cache;
+ };
+} //namespace nodex
+#endif // NODE_GRAPH_NODE_
View
70 src/heap_output_stream.cc
@@ -0,0 +1,70 @@
+#include "heap_output_stream.h"
+
+namespace nodex {
+ using v8::Array;
+ using v8::Handle;
+ using v8::HeapStatsUpdate;
+ using v8::Local;
+ using v8::Value;
+ using v8::String;
+ using v8::OutputStream;
+ using v8::Function;
+ using v8::TryCatch;;
+ using v8::Integer;
+
+ void OutputStreamAdapter::EndOfStream() {
+ TryCatch try_catch;
+ callback->Call(NanGetCurrentContext()->Global(), 0, NULL);
+
+ if (try_catch.HasCaught()) {
+ NanThrowError(try_catch.Exception());
+ }
+ }
+
+ int OutputStreamAdapter::GetChunkSize() {
+ return 10240;
+ }
+
+ OutputStream::WriteResult OutputStreamAdapter::WriteAsciiChunk(char* data, int size) {
+ NanScope();
+
+ Handle<Value> argv[2] = {
+ NanBufferUse(data, size),
+ NanNew<Integer>(size)
+ };
+
+ TryCatch try_catch;
+ abort = iterator->Call(NanGetCurrentContext()->Global(), 2, argv);
+
+ if (try_catch.HasCaught()) {
+ NanThrowError(try_catch.Exception());
+ return kAbort;
+ }
+
+ return abort->IsFalse() ? kAbort : kContinue;
+ }
+
+ OutputStream::WriteResult OutputStreamAdapter::WriteHeapStatsChunk(HeapStatsUpdate* data, int count) {
+ NanScope();
+
+ Local<Array> samples = NanNew<Array>();
+ for (int index = 0; index < count; index++) {
+ int offset = index * 3;
+ samples->Set(offset, NanNew<Integer>(data[index].index));
+ samples->Set(offset+1, NanNew<Integer>(data[index].count));
+ samples->Set(offset+2, NanNew<Integer>(data[index].size));
+ }
+
+ Local<Value> argv[1] = {samples};
+
+ TryCatch try_catch;
+ abort = iterator->Call(NanGetCurrentContext()->Global(), 1, argv);
+
+ if (try_catch.HasCaught()) {
+ NanThrowError(try_catch.Exception());
+ return kAbort;
+ }
+
+ return abort->IsFalse() ? kAbort : kContinue;
+ }
+} //namespace nodex
View
31 src/heap_output_stream.h
@@ -0,0 +1,31 @@
+#ifndef NODE_HEAP_OUTPUT_STREAM_
+#define NODE_HEAP_OUTPUT_STREAM_
+
+#include "v8-profiler.h"
+#include "nan.h"
+
+namespace nodex {
+
+class OutputStreamAdapter : public v8::OutputStream {
+ public:
+ OutputStreamAdapter(
+ v8::Handle<v8::Function> _iterator,
+ v8::Handle<v8::Function> _callback)
+ : iterator(_iterator)
+ , callback(_callback)
+ , abort(NanFalse()) {};
+
+ void EndOfStream();
+
+ int GetChunkSize();
+
+ WriteResult WriteAsciiChunk(char* data, int size);
+
+ WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* data, int count);
+ private:
+ v8::Handle<v8::Value> abort;
+ v8::Handle<v8::Function> iterator;
+ v8::Handle<v8::Function> callback;
+ };
+} //namespace nodex
+#endif // NODE_PROFILE_
View
271 src/heap_profiler.cc
@@ -1,162 +1,147 @@
#include "heap_profiler.h"
-#include "snapshot.h"
+#include "heap_snapshot.h"
+#include "heap_output_stream.h"
namespace nodex {
- Persistent<ObjectTemplate> HeapProfiler::heap_profiler_template_;
-
- class ActivityControlAdapter : public ActivityControl {
- public:
- ActivityControlAdapter(Handle<Value> progress)
- : reportProgress(Handle<Function>::Cast(progress)),
- abort(NanNewLocal<Value>(Boolean::New(false))) {}
-
- ControlOption ReportProgressValue(int done, int total) {
- NanScope();
-
- Local<Value> argv[2] = {
- Integer::New(done),
- Integer::New(total)
- };
-
- TryCatch try_catch;
-
- abort = reportProgress->Call(Context::GetCurrent()->Global(), 2, argv);
-
- if (try_catch.HasCaught()) {
- FatalException(try_catch);
- return kAbort;
- }
-
- fprintf(stderr, "here!\n");
-
- if (abort.IsEmpty() || !abort->IsBoolean()) {
- return kContinue;
- }
-
- return abort->IsTrue() ? kAbort : kContinue;
- }
-
- private:
- Handle<Function> reportProgress;
- Local<Value> abort;
- };
-
- void HeapProfiler::Initialize(Handle<Object> target) {
- NanScope();
-
- Local<ObjectTemplate> tpl = NanNewLocal<ObjectTemplate>(ObjectTemplate::New());
- NanAssignPersistent(ObjectTemplate, heap_profiler_template_, tpl);
- tpl->SetInternalFieldCount(1);
-
- Local<Object> heapProfilerObj = tpl->NewInstance();
-
- NODE_SET_METHOD(heapProfilerObj, "takeSnapshot", HeapProfiler::TakeSnapshot);
- NODE_SET_METHOD(heapProfilerObj, "getSnapshot", HeapProfiler::GetSnapshot);
- NODE_SET_METHOD(heapProfilerObj, "findSnapshot", HeapProfiler::FindSnapshot);
- NODE_SET_METHOD(heapProfilerObj, "getSnapshotsCount", HeapProfiler::GetSnapshotsCount);
- NODE_SET_METHOD(heapProfilerObj, "deleteAllSnapshots", HeapProfiler::DeleteAllSnapshots);
-
- target->Set(String::NewSymbol("heapProfiler"), heapProfilerObj);
- }
-
- HeapProfiler::HeapProfiler() {}
- HeapProfiler::~HeapProfiler() {}
-
- NAN_METHOD(HeapProfiler::GetSnapshotsCount) {
- NanScope();
-#if (NODE_MODULE_VERSION > 0x000B)
- NanReturnValue(Integer::New(nan_isolate->GetHeapProfiler()->GetSnapshotCount()));
-#else
- NanReturnValue(Integer::New(v8::HeapProfiler::GetSnapshotsCount()));
-#endif
- }
-
- NAN_METHOD(HeapProfiler::GetSnapshot) {
- NanScope();
- if (args.Length() < 1) {
- return NanThrowError("No index specified");
- } else if (!args[0]->IsInt32()) {
- return NanThrowError("Argument must be an integer");
+ using v8::ActivityControl;
+ using v8::Array;
+ using v8::Function;
+ using v8::Handle;
+ using v8::HeapSnapshot;
+ using v8::Integer;
+ using v8::Local;
+ using v8::Object;
+ using v8::SnapshotObjectId;
+ using v8::String;
+ using v8::TryCatch;
+ using v8::Value;
+
+ HeapProfiler::HeapProfiler() {}
+ HeapProfiler::~HeapProfiler() {}
+
+ class ActivityControlAdapter : public ActivityControl {
+ public:
+ ActivityControlAdapter(Handle<Value> progress)
+ : reportProgress(Handle<Function>::Cast(progress)),
+ abort(NanFalse())
+ {}
+
+ ControlOption ReportProgressValue(int done, int total) {
+ Local<Value> argv[2] = {
+ NanNew<Integer>(done),
+ NanNew<Integer>(total)
+ };
+
+ TryCatch try_catch;
+ abort = reportProgress->Call(NanGetCurrentContext()->Global(), 2, argv);
+
+ if (try_catch.HasCaught()) {
+ NanThrowError(try_catch.Exception());
+ return kAbort;
}
- int32_t index = args[0]->Int32Value();
-#if (NODE_MODULE_VERSION > 0x000B)
- const v8::HeapSnapshot* snapshot = nan_isolate->GetHeapProfiler()->GetHeapSnapshot(index);
-#else
- const v8::HeapSnapshot* snapshot = v8::HeapProfiler::GetSnapshot(index);
-#endif
- NanReturnValue(Snapshot::New(snapshot));
- }
- NAN_METHOD(HeapProfiler::FindSnapshot) {
- NanScope();
- if (args.Length() < 1) {
- return NanThrowError("No index specified");
- } else if (!args[0]->IsInt32()) {
- return NanThrowError("Argument must be an integer");
+ return abort->IsFalse() ? kAbort : kContinue;
+ }
+
+ private:
+ Handle<Function> reportProgress;
+ Handle<Value> abort;
+ };
+
+ void HeapProfiler::Initialize (Handle<Object> target) {
+ NanScope();
+
+ Local<Object> heapProfiler = NanNew<Object>();
+ Local<Array> snapshots = NanNew<Array>();
+
+ NODE_SET_METHOD(heapProfiler, "takeSnapshot", HeapProfiler::TakeSnapshot);
+ NODE_SET_METHOD(heapProfiler, "startTrackingHeapObjects", HeapProfiler::StartTrackingHeapObjects);
+ NODE_SET_METHOD(heapProfiler, "stopTrackingHeapObjects", HeapProfiler::StopTrackingHeapObjects);
+ NODE_SET_METHOD(heapProfiler, "getHeapStats", HeapProfiler::GetHeapStats);
+ heapProfiler->Set(NanNew<String>("snapshots"), snapshots);
+
+ NanAssignPersistent(Snapshot::snapshots, snapshots);
+ target->Set(NanNew<String>("heap"), heapProfiler);
+ }
+
+ NAN_METHOD(HeapProfiler::TakeSnapshot) {
+ NanScope();
+
+ ActivityControlAdapter* control = NULL;
+ Local<String> title = NanNew<String>("");
+ if (args.Length()) {
+ if (args.Length()>1) {
+ if (args[1]->IsFunction()) {
+ control = new ActivityControlAdapter(args[0]);
+ } else if (!args[1]->IsUndefined()) {
+ return NanThrowTypeError("Wrong argument [1] type (wait Function)");
}
- uint32_t uid = args[0]->Uint32Value();
- const v8::HeapSnapshot* snapshot;
-
-#if (NODE_MODULE_VERSION > 0x000B)
- bool notFound = true;
- int count = nan_isolate->GetHeapProfiler()->GetSnapshotCount();
- for (int32_t index = 1; index < count; index++) {
- snapshot = nan_isolate->GetHeapProfiler()->GetHeapSnapshot(index);
- if (snapshot->GetUid() == uid) {
- notFound = false;
- break;
- }
+ if (args[0]->IsString()) {
+ title = args[0]->ToString();
+ } else if (!args[0]->IsUndefined()) {
+ return NanThrowTypeError("Wrong argument [0] type (wait String)");
}
- if (notFound) {
- NanReturnNull();
+ } else {
+ if (args[0]->IsString()) {
+ title = args[0]->ToString();
+ } else if (args[0]->IsFunction()) {
+ control = new ActivityControlAdapter(args[0]);
+ } else if (!args[0]->IsUndefined()) {
+ return NanThrowTypeError("Wrong argument [0] type (wait String or Function)");
}
+ }
+ }
+
+#if (NODE_MODULE_VERSION > 0x000B)
+ const HeapSnapshot* snapshot = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(title, control);
+#else
+ const HeapSnapshot* snapshot = v8::HeapProfiler::TakeSnapshot(title, HeapSnapshot::kFull, control);
+#endif
+
+ NanReturnValue(Snapshot::New(snapshot));
+ }
+
+ NAN_METHOD(HeapProfiler::StartTrackingHeapObjects) {
+ NanScope();
+
+#if (NODE_MODULE_VERSION > 0x000B)
+ v8::Isolate::GetCurrent()->GetHeapProfiler()->StartTrackingHeapObjects();
#else
- snapshot = v8::HeapProfiler::FindSnapshot(uid);
+ v8::HeapProfiler::StartHeapObjectsTracking();
#endif
- NanReturnValue(Snapshot::New(snapshot));
- }
-
- NAN_METHOD(HeapProfiler::TakeSnapshot) {
- NanScope();
- Local<String> title = String::New("");
- uint32_t len = args.Length();
-
- ActivityControlAdapter *control = NULL;
-
- if (len == 1) {
- if (args[0]->IsString()) {
- title = args[0]->ToString();
- } else if (args[0]->IsFunction()) {
- //control = new ActivityControlAdapter(args[0]);
- }
- }
-
- if (len == 2) {
- if (args[0]->IsString()) {
- title = args[0]->ToString();
- }
-
- if (args[1]->IsFunction()) {
- //control = new ActivityControlAdapter(args[1]);
- }
- }
-
+
+ NanReturnUndefined();
+ }
+
+ NAN_METHOD(HeapProfiler::StopTrackingHeapObjects) {
+ NanScope();
+
#if (NODE_MODULE_VERSION > 0x000B)
- const v8::HeapSnapshot* snapshot = nan_isolate->GetHeapProfiler()->TakeHeapSnapshot(title, control);
+ v8::Isolate::GetCurrent()->GetHeapProfiler()->StopTrackingHeapObjects();
#else
- const v8::HeapSnapshot* snapshot = v8::HeapProfiler::TakeSnapshot(title, HeapSnapshot::kFull, control);
+ v8::HeapProfiler::StopHeapObjectsTracking();
#endif
-
- NanReturnValue(Snapshot::New(snapshot));
+
+ NanReturnUndefined();
+ }
+
+ NAN_METHOD(HeapProfiler::GetHeapStats) {
+ NanScope();
+ if (args.Length() < 2) {
+ return NanThrowError("Invalid number of arguments");
+ } else if (!args[0]->IsFunction() || !args[1]->IsFunction()) {
+ return NanThrowTypeError("Argument must be a function");
}
- NAN_METHOD(HeapProfiler::DeleteAllSnapshots) {
- NanScope();
+ Local<Function> iterator = Local<Function>::Cast(args[0]);
+ Local<Function> callback = Local<Function>::Cast(args[1]);
+
+ OutputStreamAdapter* stream = new OutputStreamAdapter(iterator, callback);
#if (NODE_MODULE_VERSION > 0x000B)
- nan_isolate->GetHeapProfiler()->DeleteAllHeapSnapshots();
+ SnapshotObjectId ID = v8::Isolate::GetCurrent()->GetHeapProfiler()->GetHeapStats(stream);
#else
- v8::HeapProfiler::DeleteAllSnapshots();
+ SnapshotObjectId ID = v8::HeapProfiler::PushHeapObjectsStats(stream);
#endif
- NanReturnUndefined();
- }
+ NanReturnValue(NanNew<Integer>(ID));
+ }
} //namespace nodex
View
31 src/heap_profiler.h
@@ -1,30 +1,23 @@
#ifndef NODE_HEAP_PROFILER_
#define NODE_HEAP_PROFILER_
-#include <node.h>
-#include <v8-profiler.h>
+#include "v8-profiler.h"
+#include "node.h"
#include "nan.h"
-using namespace v8;
-using namespace node;
-
namespace nodex {
- class HeapProfiler {
- public:
- static void Initialize(Handle<Object> target);
-
- HeapProfiler();
- virtual ~HeapProfiler();
+ class HeapProfiler {
+ public:
+ static void Initialize(v8::Handle<v8::Object> target);
- protected:
- static NAN_METHOD(GetSnapshotsCount);
- static NAN_METHOD(GetSnapshot);
- static NAN_METHOD(FindSnapshot);
- static NAN_METHOD(TakeSnapshot);
- static NAN_METHOD(DeleteAllSnapshots);
+ HeapProfiler();
+ virtual ~HeapProfiler();
- private:
- static Persistent<ObjectTemplate> heap_profiler_template_;
+ protected:
+ static NAN_METHOD(TakeSnapshot);
+ static NAN_METHOD(StartTrackingHeapObjects);
+ static NAN_METHOD(StopTrackingHeapObjects);
+ static NAN_METHOD(GetHeapStats);
};
} //namespace nodex
View
140 src/heap_snapshot.cc
@@ -0,0 +1,140 @@
+#include "heap_snapshot.h"
+#include "heap_output_stream.h"
+#include "heap_graph_node.h"
+
+namespace nodex {
+ using v8::Array;
+ using v8::Handle;
+ using v8::HeapSnapshot;
+ using v8::HeapGraphNode;
+ using v8::HeapGraphEdge;
+ using v8::Integer;
+ using v8::Local;
+ using v8::Object;
+ using v8::ObjectTemplate;
+ using v8::Persistent;
+ using v8::String;
+ using v8::Function;
+ using v8::Value;
+
+
+ Persistent<ObjectTemplate> Snapshot::snapshot_template_;
+ Persistent<Array> Snapshot::snapshots;
+
+ void Snapshot::Initialize () {
+ NanScope();
+
+ Local<ObjectTemplate> o = NanNew<ObjectTemplate>();
+ o->SetInternalFieldCount(1);
+ o->SetAccessor(NanNew<String>("root"), Snapshot::GetRoot);
+ NODE_SET_METHOD(o, "getNode", Snapshot::GetNode);
+ NODE_SET_METHOD(o, "delete", Snapshot::Delete);
+ NODE_SET_METHOD(o, "serialize", Snapshot::Serialize);
+ NanAssignPersistent(snapshot_template_, o);
+ }
+
+ NAN_GETTER(Snapshot::GetRoot) {
+ NanScope();
+
+ Handle<Object> _root;
+ if (args.This()->Has(NanNew<String>("_root"))) {
+ NanReturnValue(args.This()->GetHiddenValue(NanNew<String>("_root")));
+ } else {
+ void* ptr = NanGetInternalFieldPointer(args.This(), 0);
+ Handle<Value> _root = GraphNode::New(static_cast<HeapSnapshot*>(ptr)->GetRoot());
+ args.This()->SetHiddenValue(NanNew<String>("_root"), _root);
+ NanReturnValue(_root);
+ }
+ }
+
+ NAN_METHOD(Snapshot::GetNode) {
+ NanScope();
+
+ if (!args.Length()) {
+ NanThrowError("No index specified");
+ NanReturnUndefined();
+ } else if (!args[0]->IsInt32()) {
+ NanThrowTypeError("Argument must be an integer");
+ NanReturnUndefined();
+ }
+
+ int32_t index = args[0]->Int32Value();
+ void* ptr = NanGetInternalFieldPointer(args.This(), 0);
+ NanReturnValue(GraphNode::New(static_cast<HeapSnapshot*>(ptr)->GetNode(index)));
+ }
+
+ NAN_METHOD(Snapshot::Serialize) {
+ NanScope();
+
+ void* ptr = NanGetInternalFieldPointer(args.This(), 0);
+ if (args.Length() < 2) {
+ return NanThrowError("Invalid number of arguments");
+ } else if (!args[0]->IsObject()) {
+ return NanThrowTypeError("Argument must be a function");
+ }
+
+ Local<Function> iterator = Local<Function>::Cast(args[0]);
+ Local<Function> callback = Local<Function>::Cast(args[1]);
+
+ OutputStreamAdapter *stream = new OutputStreamAdapter(iterator, callback);
+ static_cast<HeapSnapshot*>(ptr)->Serialize(stream, HeapSnapshot::kJSON);
+
+ NanReturnUndefined();
+ }
+
+ NAN_METHOD(Snapshot::Delete) {
+ NanScope();
+
+ void* ptr = NanGetInternalFieldPointer(args.Holder(), 0);
+ Local<Array> snapshots = NanNew<Array>(Snapshot::snapshots);
+
+ uint32_t count = snapshots->Length();
+ for (uint32_t index = 0; index < count; index++) {
+ if (snapshots->Get(index) == args.This()) {
+ Local<Value> argv[2] = {
+ NanNew<Integer>(index),
+ NanNew<Integer>(1)
+ };
+ Handle<Function>::Cast(snapshots->Get(NanNew<String>("splice")))->Call(snapshots, 2, argv);
+ break;
+ }
+ }
+ static_cast<HeapSnapshot*>(ptr)->Delete();
+
+ NanReturnUndefined();
+ }
+
+ Handle<Value> Snapshot::New(const HeapSnapshot* node) {
+ NanEscapableScope();
+
+ if (snapshot_template_.IsEmpty()) {
+ Snapshot::Initialize();
+ }
+
+ Local<Object> snapshot = NanNew(snapshot_template_)->NewInstance();
+ NanSetInternalFieldPointer(snapshot, 0, const_cast<HeapSnapshot*>(node));
+
+ Local<Value> HEAP = NanNew<String>("HEAP");
+ uint16_t _uid = node->GetUid();
+ Local<Value> uid = NanNew<Integer>(_uid);
+ Handle<String> title = node->GetTitle();
+ if (!title->Length()) {
+ char _title[32];
+ sprintf(_title, "Snapshot %i", _uid);
+ title = NanNew<String>(_title);
+ }
+ Local<Integer> nodesCount = NanNew<Integer>(node->GetNodesCount());
+ Local<Integer> objectId = NanNew<Integer>(node->GetMaxSnapshotJSObjectId());
+
+ snapshot->Set(NanNew<String>("typeId"), HEAP);
+ snapshot->Set(NanNew<String>("title"), title);
+ snapshot->Set(NanNew<String>("uid"), uid);
+ snapshot->Set(NanNew<String>("nodesCount"), nodesCount);
+ snapshot->Set(NanNew<String>("maxSnapshotJSObjectId"), objectId);
+
+ Local<Array> snapshots = NanNew<Array>(Snapshot::snapshots);
+ snapshots->Set(snapshots->Length(), snapshot);
+
+ return NanEscapeScope(snapshot);
+ }
+}
View
22 src/heap_snapshot.h
@@ -0,0 +1,22 @@
+#ifndef NODE_SNAPSHOT_
+#define NODE_SNAPSHOT_
+
+#include "v8-profiler.h"
+#include "nan.h"
+
+namespace nodex {
+
+ class Snapshot {
+ public:
+ static v8::Handle<v8::Value> New(const v8::HeapSnapshot* node);
+ static v8::Persistent<v8::Array> snapshots;
+ private:
+ static void Initialize();
+ static NAN_GETTER(GetRoot);
+ static NAN_METHOD(GetNode);
+ static NAN_METHOD(Delete);
+ static NAN_METHOD(Serialize);
+ static v8::Persistent<v8::ObjectTemplate> snapshot_template_;
+ };
+} //namespace nodex
+#endif // NODE_SNAPSHOT_
View
84 src/profile.cc
@@ -1,84 +0,0 @@
-#include "profile.h"
-#include "profile_node.h"
-
-using namespace v8;
-
-namespace nodex {
-
-Persistent<ObjectTemplate> Profile::profile_template_;
-
-void Profile::Initialize() {
- Local<ObjectTemplate> tpl = NanNewLocal<ObjectTemplate>(ObjectTemplate::New());
- NanAssignPersistent(ObjectTemplate, profile_template_, tpl);
- tpl->SetInternalFieldCount(1);
- tpl->SetAccessor(String::New("title"), Profile::GetTitle);
- tpl->SetAccessor(String::New("uid"), Profile::GetUid);
- tpl->SetAccessor(String::New("topRoot"), Profile::GetTopRoot);
- tpl->SetAccessor(String::New("bottomRoot"), Profile::GetBottomRoot);
- tpl->Set(String::New("delete"), FunctionTemplate::New(Profile::Delete));
-}
-
-NAN_GETTER(Profile::GetUid) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
-
- uint32_t uid = static_cast<CpuProfile*>(ptr)->GetUid();
- NanReturnValue(Integer::NewFromUnsigned(uid));
-}
-
-
-NAN_GETTER(Profile::GetTitle) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- Handle<String> title = static_cast<CpuProfile*>(ptr)->GetTitle();
- NanReturnValue(title);
-}
-
-NAN_GETTER(Profile::GetTopRoot) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- const CpuProfileNode* node = static_cast<CpuProfile*>(ptr)->GetTopDownRoot();
- NanReturnValue(ProfileNode::New(node));
-}
-
-
-NAN_GETTER(Profile::GetBottomRoot) {
- NanScope();
-#if (NODE_MODULE_VERSION > 0x000B)
- NanReturnUndefined();
-#else
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- const CpuProfileNode* node = static_cast<CpuProfile*>(ptr)->GetBottomUpRoot();
- NanReturnValue(ProfileNode::New(node));
-#endif
-}
-
-NAN_METHOD(Profile::Delete) {
- NanScope();
- Handle<Object> self = args.This();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- static_cast<CpuProfile*>(ptr)->Delete();
- NanReturnUndefined();
-}
-
-Handle<Value> Profile::New(const CpuProfile* profile) {
- NanScope();
-
- if (profile_template_.IsEmpty()) {
- Profile::Initialize();
- }
-
- if(!profile) {
- return Undefined();
- }
- else {
- Local<Object> obj = NanPersistentToLocal(profile_template_)->NewInstance();
- NanSetInternalFieldPointer(obj, 0, const_cast<CpuProfile*>(profile));
- return obj;
- }
-}
-}
View
27 src/profile.h
@@ -1,27 +0,0 @@
-#ifndef NODE_PROFILE_
-#define NODE_PROFILE_
-
-#include <node.h>
-#include <v8-profiler.h>
-#include "nan.h"
-
-using namespace v8;
-
-namespace nodex {
-
-class Profile {
- public:
- static Handle<Value> New(const CpuProfile* profile);
-
- private:
- static NAN_GETTER(GetUid);
- static NAN_GETTER(GetTitle);
- static NAN_GETTER(GetTopRoot);
- static NAN_GETTER(GetBottomRoot);
- static NAN_METHOD(Delete);
- static void Initialize();
- static Persistent<ObjectTemplate> profile_template_;
-};
-
-} //namespace nodex
-#endif // NODE_PROFILE_
View
143 src/profile_node.cc
@@ -1,143 +0,0 @@
-#include "profile_node.h"
-
-using namespace v8;
-
-namespace nodex {
-
-Persistent<ObjectTemplate> ProfileNode::node_template_;
-
-void ProfileNode::Initialize() {
- Local<ObjectTemplate> tpl = NanNewLocal<ObjectTemplate>(ObjectTemplate::New());
- NanAssignPersistent(ObjectTemplate, node_template_, tpl);
- tpl->SetInternalFieldCount(1);
- tpl->SetAccessor(String::New("functionName"), ProfileNode::GetFunctionName);
- tpl->SetAccessor(String::New("scriptName"), ProfileNode::GetScriptName);
- tpl->SetAccessor(String::New("lineNumber"), ProfileNode::GetLineNumber);
- tpl->SetAccessor(String::New("totalTime"), ProfileNode::GetTotalTime);
- tpl->SetAccessor(String::New("selfTime"), ProfileNode::GetSelfTime);
- tpl->SetAccessor(String::New("totalSamplesCount"), ProfileNode::GetTotalSamplesCount);
- tpl->SetAccessor(String::New("selfSamplesCount"), ProfileNode::GetSelfSamplesCount);
- tpl->SetAccessor(String::New("callUid"), ProfileNode::GetCallUid);
- tpl->SetAccessor(String::New("childrenCount"), ProfileNode::GetChildrenCount);
- tpl->Set(String::New("getChild"), FunctionTemplate::New(ProfileNode::GetChild));
-}
-
-NAN_GETTER(ProfileNode::GetFunctionName) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- Handle<String> fname = static_cast<CpuProfileNode*>(ptr)->GetFunctionName();
- NanReturnValue(fname);
-}
-
-NAN_GETTER(ProfileNode::GetScriptName) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- Handle<String> sname = static_cast<CpuProfileNode*>(ptr)->GetScriptResourceName();
- NanReturnValue(sname);
-}
-
-NAN_GETTER(ProfileNode::GetLineNumber) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- int32_t ln = static_cast<CpuProfileNode*>(ptr)->GetLineNumber();
- NanReturnValue(Integer::New(ln));
-}
-
-NAN_GETTER(ProfileNode::GetTotalTime) {
- NanScope();
-#if (NODE_MODULE_VERSION > 0x000B)
- NanReturnUndefined();
-#else
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- double ttime = static_cast<CpuProfileNode*>(ptr)->GetTotalTime();
- NanReturnValue(Number::New(ttime));
-#endif
-}
-
-NAN_GETTER(ProfileNode::GetSelfTime) {
- NanScope();
-#if (NODE_MODULE_VERSION > 0x000B)
- NanReturnUndefined();
-#else
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- double stime = static_cast<CpuProfileNode*>(ptr)->GetSelfTime();
- NanReturnValue(Number::New(stime));
-#endif
-}
-
-NAN_GETTER(ProfileNode::GetTotalSamplesCount) {
- NanScope();
-#if (NODE_MODULE_VERSION > 0x000B)
- NanReturnUndefined();
-#else
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- double samples = static_cast<CpuProfileNode*>(ptr)->GetTotalSamplesCount();
- NanReturnValue(Number::New(samples));
-#endif
-}
-
-NAN_GETTER(ProfileNode::GetSelfSamplesCount) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
-#if (NODE_MODULE_VERSION > 0x000B)
- double samples = static_cast<CpuProfileNode*>(ptr)->GetHitCount();
-#else
- double samples = static_cast<CpuProfileNode*>(ptr)->GetSelfSamplesCount();
-#endif
- NanReturnValue(Number::New(samples));
-}
-
-NAN_GETTER(ProfileNode::GetCallUid) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- uint32_t uid = static_cast<CpuProfileNode*>(ptr)->GetCallUid();
- NanReturnValue(Integer::NewFromUnsigned(uid));
-}
-
-NAN_GETTER(ProfileNode::GetChildrenCount) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- int32_t count = static_cast<CpuProfileNode*>(ptr)->GetChildrenCount();
- NanReturnValue(Integer::New(count));
-}
-
-NAN_METHOD(ProfileNode::GetChild) {
- NanScope();
- if (args.Length() < 1) {
- return NanThrowError("No index specified");
- } else if (!args[0]->IsInt32()) {
- return NanThrowError("Argument must be integer");
- }
- int32_t index = args[0]->Int32Value();
- Handle<Object> self = args.This();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- const CpuProfileNode* node = static_cast<CpuProfileNode*>(ptr)->GetChild(index);
- NanReturnValue(ProfileNode::New(node));
-}
-
-Handle<Value> ProfileNode::New(const CpuProfileNode* node) {
- NanScope();
-
- if (node_template_.IsEmpty()) {
- ProfileNode::Initialize();
- }
-
- if(!node) {
- return Undefined();
- }
- else {
- Local<Object> obj = NanPersistentToLocal(node_template_)->NewInstance();
- NanSetInternalFieldPointer(obj, 0, const_cast<CpuProfileNode*>(node));
- return obj;
- }
-}
-}
View
34 src/profile_node.h
@@ -1,34 +0,0 @@
-
-
-#ifndef NODE_PROFILE_NODE_
-#define NODE_PROFILE_NODE_
-
-#include <node.h>
-#include <v8-profiler.h>
-#include "nan.h"
-
-using namespace v8;
-
-namespace nodex {
-
-class ProfileNode {
- public:
- static Handle<Value> New(const CpuProfileNode* node);
-
- private:
- static NAN_GETTER(GetFunctionName);
- static NAN_GETTER(GetScriptName);
- static NAN_GETTER(GetLineNumber);
- static NAN_GETTER(GetTotalTime);
- static NAN_GETTER(GetSelfTime);
- static NAN_GETTER(GetTotalSamplesCount);
- static NAN_GETTER(GetSelfSamplesCount);
- static NAN_GETTER(GetCallUid);
- static NAN_GETTER(GetChildrenCount);
- static NAN_METHOD(GetChild);
- static void Initialize();
- static Persistent<ObjectTemplate> node_template_;
-};
-
-}
-#endif // NODE_PROFILE_NODE_
View
4 src/profiler.cc
@@ -1,8 +1,10 @@
+#include "node.h"
+#include "nan.h"
#include "heap_profiler.h"
#include "cpu_profiler.h"
namespace nodex {
- void InitializeProfiler(Handle<Object> target) {
+ void InitializeProfiler(v8::Handle<v8::Object> target) {
NanScope();
HeapProfiler::Initialize(target);
CpuProfiler::Initialize(target);
View
176 src/snapshot.cc
@@ -1,176 +0,0 @@
-#include "snapshot.h"
-#include "node.h"
-#include "node_buffer.h"
-
-using namespace v8;
-using namespace node;
-
-namespace nodex {
-
-Persistent<ObjectTemplate> Snapshot::snapshot_template_;
-
-void Snapshot::Initialize() {
- Local<ObjectTemplate> tpl = NanNewLocal<ObjectTemplate>(ObjectTemplate::New());
- NanAssignPersistent(ObjectTemplate, snapshot_template_, tpl);
- tpl->SetInternalFieldCount(1);
- tpl->SetAccessor(String::New("title"), Snapshot::GetTitle);
- tpl->SetAccessor(String::New("uid"), Snapshot::GetUid);
- tpl->SetAccessor(String::New("type"), Snapshot::GetType);
- tpl->Set(String::New("delete"), FunctionTemplate::New(Snapshot::Delete));
- tpl->Set(String::New("serialize"), FunctionTemplate::New(Snapshot::Serialize));
-}
-
-NAN_GETTER(Snapshot::GetTitle) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- Handle<String> title = static_cast<HeapSnapshot*>(ptr)->GetTitle();
- NanReturnValue(title);
-}
-
-NAN_GETTER(Snapshot::GetUid) {
- NanScope();
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- uint32_t uid = static_cast<HeapSnapshot*>(ptr)->GetUid();
- NanReturnValue(Integer::NewFromUnsigned(uid));
-}
-
-NAN_GETTER(Snapshot::GetType) {
- NanScope();
-#if (NODE_MODULE_VERSION > 0x000B)
- NanReturnValue(String::New("Unknown"));
-#else
- Local<Object> self = args.Holder();
- void* ptr = NanGetInternalFieldPointer(self, 0);
-
- HeapSnapshot::Type type = static_cast<HeapSnapshot*>(ptr)->GetType();
- Local<String> t;
-
- switch(type) {
- case HeapSnapshot::kFull:
- t = String::New("Full");
- break;
- default:
- t = String::New("Unknown");
- }
-
- NanReturnValue(t);
-#endif
-}
-
-NAN_METHOD(Snapshot::Delete) {
- NanScope();
- Handle<Object> self = args.This();
- void* ptr = NanGetInternalFieldPointer(self, 0);
- static_cast<HeapSnapshot*>(ptr)->Delete();
- NanReturnUndefined();
-}
-
-Handle<Value> Snapshot::New(const HeapSnapshot* snapshot) {
- NanScope();
-
- if (snapshot_template_.IsEmpty()) {
- Snapshot::Initialize();
- }
-
- if(!snapshot) {
- return Undefined();
- }
- else {
- Local<Object> obj = NanPersistentToLocal(snapshot_template_)->NewInstance();
- NanSetInternalFieldPointer(obj, 0, const_cast<HeapSnapshot*>(snapshot));
- return obj;
- }
-}
-
-class OutputStreamAdapter : public v8::OutputStream {
- public:
- OutputStreamAdapter(Handle<Value> arg) {
- Local<String> onEnd = String::New("onEnd");
- Local<String> onData = String::New("onData");
-
- if (!arg->IsObject()) {
- ThrowException(Exception::TypeError(
- String::New("You must specify an Object as first argument")));
- }
-
- obj = arg->ToObject();
- if (!obj->Has(onEnd) || !obj->Has(onData)) {
- ThrowException(Exception::TypeError(
- String::New("You must specify properties 'onData' and 'onEnd' to invoke this function")));
- }
-
- if (!obj->Get(onEnd)->IsFunction() || !obj->Get(onData)->IsFunction()) {
- ThrowException(Exception::TypeError(
- String::New("Properties 'onData' and 'onEnd' have to be functions")));
- }
-
- onEndFunction = Local<Function>::Cast(obj->Get(onEnd));
- onDataFunction = Local<Function>::Cast(obj->Get(onData));
-
- abort = NanNewLocal(Boolean::New(false));
- }
-
- void EndOfStream() {
- TryCatch try_catch;
- onEndFunction->Call(obj, 0, NULL);
-
- if (try_catch.HasCaught()) {
- FatalException(try_catch);
- }
- }
-
- int GetChunkSize() {
- return 10240;
- }
-
- WriteResult WriteAsciiChunk(char* data, int size) {
- NanScope();
-
- Handle<Value> argv[2] = {
- NanNewBufferHandle(data, size),
- Integer::New(size)
- };
-
- TryCatch try_catch;
- abort = onDataFunction->Call(obj, 2, argv);
-
- if (try_catch.HasCaught()) {
- FatalException(try_catch);
- return kAbort;
- }
-
- if (abort.IsEmpty() || !abort->IsBoolean()) {
- return kContinue;
- }
-
- return abort->IsTrue() ? kAbort : kContinue;
- }
-
- private:
- Local<Value> abort;
- Handle<Object> obj;
- Handle<Function> onEndFunction;
- Handle<Function> onDataFunction;
-};
-
-NAN_METHOD(Snapshot::Serialize) {
- NanScope();
- Handle<Object> self = args.This();
-
- uint32_t argslen = args.Length();
-
- if (argslen == 0) {
- return NanThrowError("You must specify arguments to invoke this function");
- }
-
- OutputStreamAdapter *stream = new OutputStreamAdapter(args[0]);
-
- void* ptr = NanGetInternalFieldPointer(self, 0);
- static_cast<HeapSnapshot*>(ptr)->Serialize(stream, HeapSnapshot::kJSON);
-
- NanReturnUndefined();
-}
-
-} //namespace nodex
View
41 src/snapshot.h
@@ -1,41 +0,0 @@
-
-
-#ifndef NODE_SNAPSHOT_
-#define NODE_SNAPSHOT_
-
-#include <node.h>
-#include <v8-profiler.h>
-#include "nan.h"
-
-using namespace v8;
-
-namespace nodex {
-
-class Snapshot {
- public:
- static Handle<Value> New(const HeapSnapshot* snapshot);
-
- private:
- Snapshot(const v8::HeapSnapshot* snapshot)
- : m_snapshot(snapshot){}
-
- const v8::HeapSnapshot* m_snapshot;
-
- static NAN_GETTER(GetUid);
- static NAN_GETTER(GetTitle);
- static NAN_GETTER(GetMaxSnapshotJSObjectId);
- static NAN_GETTER(GetRoot);
- static NAN_GETTER(GetType);
- static NAN_GETTER(GetNodesCount);
- static NAN_METHOD(GetNodeById);
- static NAN_METHOD(GetNode);
- static NAN_METHOD(Delete);
- static NAN_METHOD(Serialize);
-
- static NAN_METHOD(SnapshotObjectId);
-
- static void Initialize();
- static Persistent<ObjectTemplate> snapshot_template_;
-};
-} //namespace nodex
-#endif // NODE_SNAPSHOT_
View
275 v8-profiler.js
@@ -1,4 +1,5 @@
-var binding = require("./build/Release/profiler");
+var binding = require("./build/Release/profiler"),
+ extend = require('util')._extend;
function Snapshot() {}
@@ -16,56 +17,6 @@ Snapshot.prototype.compare = function (other) {
return diff;
};
-Snapshot.prototype.hotPath = function() {
- var path = [], node = this.root, c, i = 0;
- c = this.children(node);
- while (c.length > 0 && i < 1000) {
- node = c[0].to;
- c = this.children(node);
- path.push(node);
- i++;
- }
- return path;
-};
-
-Snapshot.prototype.children = function(node) {
- var i, children = [];
- for(i = 0; i < node.childrenCount; i++) {
- children[i] = node.getChild(i);
- }
- children.sort(function (a, b){
- return b.to.retainedSize() - a.to.retainedSize();
- });
- return children;
-};
-
-Snapshot.prototype.topDominatorIds = function() {
- var doms = {}, arr;
- this.allNodes().forEach(function(node){
- var dom = node.dominatorNode || { id: "none"};
- if (doms[dom.id]) {
- doms[dom.id] += 1;
- }
- else {
- doms[dom.id] = 1;
- }
- });
- arr = Object.keys(doms).map(function(d){
- return {id: d, count: doms[d]};
- });
- arr.sort(function(a, b) {
- return b.count - a.count;
- });
- return arr;
-};
-
-Snapshot.prototype.topDominators = function() {
- var self = this;
- return this.topDominatorIds().map(function(d){
- return self.getNodeById(+d.id);
- });
-};
-
Snapshot.prototype.allNodes = function() {
var n = this.nodesCount, i, nodes = [];
for (i = 0; i < n; i++) {
@@ -97,149 +48,95 @@ Snapshot.prototype.nodeCounts = function() {
return objects;
};
-//adapted from WebCore/bindings/v8/ScriptHeapSnapshot.cpp
-Snapshot.prototype.stringify = function() {
- var root = this.root, i, j, count_i, count_j, node,
- lowLevels = {}, entries = {}, entry,
- children = {}, child, edge, result = {};
- for (i = 0, count_i = root.childrenCount; i < count_i; i++) {
- node = root.getChild(i).to;
- if (node.type === 'Hidden') {
- lowLevels[node.name] = {
- count: node.instancesCount,
- size: node.size,
- type: node.name
- };
- }
- else if (node.instancesCount > 0) {
- entries[node.name] = {
- constructorName: node.name,
- count: node.instancesCount,
- size: node.size
- };
- }
- // FIXME: the children portion is too slow and bloats the results
- //*
- else {
- entry = {
- constructorName: node.name
- };
- for(j = 0, count_j = node.childrenCount; j < count_j; j++) {
- edge = node.getChild(j);
- child = edge.to;
- entry[child.ptr.toString()] = {
- constructorName: child.name,
- count: parseInt(edge.name, 10)
- };
- }
- children[node.ptr.toString()] = entry;
- }//*/
- }
- result.lowlevels = lowLevels;
- result.entries = entries;
- result.children = children;
- return JSON.stringify(result);
-};
-
function CpuProfile() {}
-function inspectorObjectFor(node) {
- var i, count, child,
- result = {
- functionName: node.functionName,
- url: node.scriptName,
- lineNumber: node.lineNumber,
- totalTime: node.totalTime,
- selfTime: node.selfTime,
- numberOfCalls: 0,
- visible: true,
- callUID: node.callUid,
- children: []
- };
- for(i = 0, count = node.childrenCount; i < count; i++) {
- child = node.getChild(i);
- result.children.push(inspectorObjectFor(child));
+CpuProfile.prototype.getHeader = function() {
+ return {
+ typeId: this.typeId,
+ uid: this.uid,
+ title: this.title
}
- return result;
}
-CpuProfile.prototype.getTopDownRoot = function() {
- return inspectorObjectFor(this.topRoot);
-};
-
-CpuProfile.prototype.getBottomUpRoot = function() {
- return inspectorObjectFor(this.bottomRoot);
-};
-
-var heapCache = [];
-
-exports.takeSnapshot = function(name, control) {
- if (typeof name == 'function') {
- control = name;
- name = '';
- }
-
- if (!name || !name.length) {
- name = 'org.nodejs.profiles.heap.user-initiated.' + (heapCache.length + 1);
- }
-
- var snapshot = binding.heapProfiler.takeSnapshot(name, control);
- snapshot.__proto__ = Snapshot.prototype;
- heapCache.push(snapshot);
-
- return snapshot;
-};
-
-exports.getSnapshot = function(index) {
- return heapCache[index];
-};
-
-exports.findSnapshot = function(uid) {
- return heapCache.filter(function(s) {return s.uid === uid;})[0];
-};
-
-exports.snapshotCount = function() {
- return heapCache.length;
-};
-
-exports.deleteAllSnapshots = function () {
- heapCache = [];
- binding.heapProfiler.deleteAllSnapshots();
-};
-
-var cpuCache = [];
-
-exports.startProfiling = function(name) {
- if (!name || !name.length) {
- name = 'org.nodejs.profiles.cpu.user-initiated.' + (cpuCache.length + 1);
+var profiler = {
+ /*HEAP PROFILER API*/
+
+ get snapshots() { return binding.heap.snapshots; },
+
+ takeSnapshot: function(name, control) {
+ var snapshot = binding.heap.takeSnapshot.apply(null, arguments);
+ snapshot.__proto__ = Snapshot.prototype;
+ return snapshot;
+ },
+
+ getSnapshot: function(index) {
+ var snapshot = binding.heap.snapshots[index];
+ if (!snapshot) {
+ throw new Error('Snapshot at index ' + index + 'not found');
+ }
+ snapshot.__proto__ = Snapshot.prototype;
+ return snapshot;
+ },
+
+ findSnapshot: function(uid) {
+ var snapshot = binding.heap.snapshots.filter(function(snapshot) {
+ return snapshot.uid == uid;
+ })[0];
+ if (!snapshot) {
+ throw new Error('Snapshot at index ' + index + 'not found');
+ }
+ snapshot.__proto__ = Snapshot.prototype;
+ return snapshot;
+ },
+
+ deleteAllSnapshots: function () {
+ binding.heap.snapshots.forEach(function(snapshot) {
+ snapshot.delete();
+ });
+ },
+
+
+ /*CPU PROFILER API*/
+
+ get profiles() { return binding.cpu.profiles; },
+
+ startProfiling: binding.cpu.startProfiling,
+
+ stopProfiling: function(name) {
+ name = name || '';
+ var profile = binding.cpu.stopProfiling(name);
+ profile.__proto__ = CpuProfile.prototype;
+ return profile;
+ },
+
+ getProfile: function(index) {
+ var profile = binding.cpu.profiles[index];
+ if (!profile) {
+ console.log('Profile at index ' + index + 'not found');
+ return;
+ }
+ profile.__proto__ = CpuProfile.prototype;
+ return profile;
+ },
+
+ findProfile: function(uid) {
+ var profile = binding.cpu.profiles.filter(function(profile) {
+ return profile.uid == uid;
+ })[0];
+ if (!profile) {
+ console.log('Profile at uid ' + uid + 'not found');
+ return;
+ }
+ profile.__proto__ = CpuProfile.prototype;
+ return profile;
+ },
+
+ deleteAllProfiles: function() {
+ binding.cpu.profiles.forEach(function(profile) {
+ profile.delete();
+ });
}
-
- binding.cpuProfiler.startProfiling(name);
-};
-
-exports.stopProfiling = function(name) {
- name = name ? name : '';
- var profile = binding.cpuProfiler.stopProfiling(name);
- profile.__proto__ = CpuProfile.prototype;
- cpuCache.push(profile);
- return profile;
-};
-
-exports.getProfile = function(index) {
- return cpuCache[index];
-};
-
-exports.findProfile = function(uid) {
- return cpuCache.filter(function(s) {return s.uid === uid;})[0];
-};
-
-exports.profileCount = function() {
- return cpuCache.length;
-};
-
-exports.deleteAllProfiles = function() {
- cpuCache = [];
- binding.cpuProfiler.deleteAllProfiles();
};
-process.profiler = exports;
+module.exports = profiler;
+process.profiler = profiler;

0 comments on commit 77b814d

Please sign in to comment.
Something went wrong with that request. Please try again.