2020
2121using node::kAllowedInEnvvar ;
2222using node::kDisallowedInEnvvar ;
23+ using v8::AllocationProfile;
2324using v8::Array;
2425using v8::ArrayBuffer;
2526using v8::Boolean;
@@ -32,6 +33,7 @@ using v8::Float64Array;
3233using v8::FunctionCallbackInfo;
3334using v8::FunctionTemplate;
3435using v8::HandleScope;
36+ using v8::HeapProfiler;
3537using v8::HeapStatistics;
3638using v8::Integer;
3739using v8::Isolate;
@@ -1031,6 +1033,169 @@ void Worker::StopCpuProfile(const FunctionCallbackInfo<Value>& args) {
10311033 }
10321034}
10331035
1036+ class WorkerHeapProfileTaker final : public AsyncWrap {
1037+ public:
1038+ WorkerHeapProfileTaker (Environment* env, Local<Object> obj)
1039+ : AsyncWrap(env, obj, AsyncWrap::PROVIDER_WORKERHEAPPROFILE) {}
1040+
1041+ SET_NO_MEMORY_INFO ()
1042+ SET_MEMORY_INFO_NAME (WorkerHeapProfileTaker)
1043+ SET_SELF_SIZE (WorkerHeapProfileTaker)
1044+ };
1045+
1046+ void Worker::StartHeapProfile (const FunctionCallbackInfo<Value>& args) {
1047+ Worker* w;
1048+ ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
1049+ Environment* env = w->env ();
1050+
1051+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (w);
1052+ Local<Object> wrap;
1053+ if (!env->worker_heap_profile_taker_template ()
1054+ ->NewInstance (env->context ())
1055+ .ToLocal (&wrap)) {
1056+ return ;
1057+ }
1058+
1059+ BaseObjectPtr<WorkerHeapProfileTaker> taker =
1060+ MakeDetachedBaseObject<WorkerHeapProfileTaker>(env, wrap);
1061+
1062+ bool scheduled = w->RequestInterrupt ([taker = std::move (taker),
1063+ env](Environment* worker_env) mutable {
1064+ v8::HeapProfiler* profiler = worker_env->isolate ()->GetHeapProfiler ();
1065+ bool success = profiler->StartSamplingHeapProfiler ();
1066+ env->SetImmediateThreadsafe (
1067+ [taker = std::move (taker),
1068+ success = success](Environment* env) mutable {
1069+ Isolate* isolate = env->isolate ();
1070+ HandleScope handle_scope (isolate);
1071+ Context::Scope context_scope (env->context ());
1072+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (taker.get ());
1073+ Local<Value> argv[] = {
1074+ Null (isolate), // error
1075+ };
1076+ if (!success) {
1077+ argv[0 ] = ERR_HEAP_PROFILE_HAVE_BEEN_STARTED (
1078+ isolate, " heap profiler have been started" );
1079+ }
1080+ taker->MakeCallback (env->ondone_string (), arraysize (argv), argv);
1081+ },
1082+ CallbackFlags::kUnrefed );
1083+ });
1084+
1085+ if (scheduled) {
1086+ args.GetReturnValue ().Set (wrap);
1087+ }
1088+ }
1089+
1090+ static void buildHeapProfileNode (Isolate* isolate,
1091+ const AllocationProfile::Node* node,
1092+ JSONWriter* writer) {
1093+ size_t selfSize = 0 ;
1094+ for (const auto & allocation : node->allocations )
1095+ selfSize += allocation.size * allocation.count ;
1096+
1097+ writer->json_keyvalue (" selfSize" , selfSize);
1098+ writer->json_keyvalue (" id" , node->node_id );
1099+ writer->json_objectstart (" callFrame" );
1100+ writer->json_keyvalue (" scriptId" , node->script_id );
1101+ writer->json_keyvalue (" lineNumber" , node->line_number - 1 );
1102+ writer->json_keyvalue (" columnNumber" , node->column_number - 1 );
1103+ node::Utf8Value name (isolate, node->name );
1104+ node::Utf8Value script_name (isolate, node->script_name );
1105+ writer->json_keyvalue (" functionName" , *name);
1106+ writer->json_keyvalue (" url" , *script_name);
1107+ writer->json_objectend ();
1108+
1109+ writer->json_arraystart (" children" );
1110+ for (const auto * child : node->children ) {
1111+ writer->json_start ();
1112+ buildHeapProfileNode (isolate, child, writer);
1113+ writer->json_end ();
1114+ }
1115+ writer->json_arrayend ();
1116+ }
1117+
1118+ static bool serializeProfile (Isolate* isolate, std::ostringstream& out_stream) {
1119+ HandleScope scope (isolate);
1120+ HeapProfiler* profiler = isolate->GetHeapProfiler ();
1121+ std::unique_ptr<AllocationProfile> profile (profiler->GetAllocationProfile ());
1122+ if (!profile) {
1123+ return false ;
1124+ }
1125+ JSONWriter writer (out_stream, false );
1126+ writer.json_start ();
1127+
1128+ writer.json_arraystart (" samples" );
1129+ for (const auto & sample : profile->GetSamples ()) {
1130+ writer.json_start ();
1131+ writer.json_keyvalue (" size" , sample.size * sample.count );
1132+ writer.json_keyvalue (" nodeId" , sample.node_id );
1133+ writer.json_keyvalue (" ordinal" , static_cast <double >(sample.sample_id ));
1134+ writer.json_end ();
1135+ }
1136+ writer.json_arrayend ();
1137+
1138+ writer.json_objectstart (" head" );
1139+ buildHeapProfileNode (isolate, profile->GetRootNode (), &writer);
1140+ writer.json_objectend ();
1141+
1142+ writer.json_end ();
1143+ profiler->StopSamplingHeapProfiler ();
1144+ return true ;
1145+ }
1146+
1147+ void Worker::StopHeapProfile (const FunctionCallbackInfo<Value>& args) {
1148+ Worker* w;
1149+ ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
1150+
1151+ Environment* env = w->env ();
1152+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (w);
1153+ Local<Object> wrap;
1154+ if (!env->worker_heap_profile_taker_template ()
1155+ ->NewInstance (env->context ())
1156+ .ToLocal (&wrap)) {
1157+ return ;
1158+ }
1159+
1160+ BaseObjectPtr<WorkerHeapProfileTaker> taker =
1161+ MakeDetachedBaseObject<WorkerHeapProfileTaker>(env, wrap);
1162+
1163+ bool scheduled = w->RequestInterrupt ([taker = std::move (taker),
1164+ env](Environment* worker_env) mutable {
1165+ std::ostringstream out_stream;
1166+ bool success = serializeProfile (worker_env->isolate (), out_stream);
1167+ env->SetImmediateThreadsafe (
1168+ [taker = std::move (taker),
1169+ out_stream = std::move (out_stream),
1170+ success = success](Environment* env) mutable {
1171+ Isolate* isolate = env->isolate ();
1172+ HandleScope handle_scope (isolate);
1173+ Context::Scope context_scope (env->context ());
1174+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (taker.get ());
1175+ Local<Value> argv[] = {
1176+ Null (isolate), // error
1177+ Undefined (isolate), // profile
1178+ };
1179+ if (success) {
1180+ Local<Value> result;
1181+ if (!ToV8Value (env->context (), out_stream.str (), isolate)
1182+ .ToLocal (&result)) {
1183+ return ;
1184+ }
1185+ argv[1 ] = result;
1186+ } else {
1187+ argv[0 ] = ERR_HEAP_PROFILE_NOT_STARTED (isolate,
1188+ " heap profile not started" );
1189+ }
1190+ taker->MakeCallback (env->ondone_string (), arraysize (argv), argv);
1191+ },
1192+ CallbackFlags::kUnrefed );
1193+ });
1194+
1195+ if (scheduled) {
1196+ args.GetReturnValue ().Set (wrap);
1197+ }
1198+ }
10341199class WorkerHeapStatisticsTaker : public AsyncWrap {
10351200 public:
10361201 WorkerHeapStatisticsTaker (Environment* env, Local<Object> obj)
@@ -1328,6 +1493,8 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
13281493 SetProtoMethod (isolate, w, " cpuUsage" , Worker::CpuUsage);
13291494 SetProtoMethod (isolate, w, " startCpuProfile" , Worker::StartCpuProfile);
13301495 SetProtoMethod (isolate, w, " stopCpuProfile" , Worker::StopCpuProfile);
1496+ SetProtoMethod (isolate, w, " startHeapProfile" , Worker::StartHeapProfile);
1497+ SetProtoMethod (isolate, w, " stopHeapProfile" , Worker::StopHeapProfile);
13311498
13321499 SetConstructorFunction (isolate, target, " Worker" , w);
13331500 }
@@ -1387,6 +1554,20 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
13871554 wst->InstanceTemplate ());
13881555 }
13891556
1557+ {
1558+ Local<FunctionTemplate> wst = NewFunctionTemplate (isolate, nullptr );
1559+
1560+ wst->InstanceTemplate ()->SetInternalFieldCount (
1561+ WorkerHeapProfileTaker::kInternalFieldCount );
1562+ wst->Inherit (AsyncWrap::GetConstructorTemplate (isolate_data));
1563+
1564+ Local<String> wst_string =
1565+ FIXED_ONE_BYTE_STRING (isolate, " WorkerHeapProfileTaker" );
1566+ wst->SetClassName (wst_string);
1567+ isolate_data->set_worker_heap_profile_taker_template (
1568+ wst->InstanceTemplate ());
1569+ }
1570+
13901571 SetMethod (isolate, target, " getEnvMessagePort" , GetEnvMessagePort);
13911572}
13921573
@@ -1466,6 +1647,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
14661647 registry->Register (Worker::CpuUsage);
14671648 registry->Register (Worker::StartCpuProfile);
14681649 registry->Register (Worker::StopCpuProfile);
1650+ registry->Register (Worker::StartHeapProfile);
1651+ registry->Register (Worker::StopHeapProfile);
14691652}
14701653
14711654} // anonymous namespace
0 commit comments