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