20
20
21
21
using node::kAllowedInEnvvar ;
22
22
using node::kDisallowedInEnvvar ;
23
+ using v8::AllocationProfile;
23
24
using v8::Array;
24
25
using v8::ArrayBuffer;
25
26
using v8::Boolean;
@@ -32,6 +33,7 @@ using v8::Float64Array;
32
33
using v8::FunctionCallbackInfo;
33
34
using v8::FunctionTemplate;
34
35
using v8::HandleScope;
36
+ using v8::HeapProfiler;
35
37
using v8::HeapStatistics;
36
38
using v8::Integer;
37
39
using v8::Isolate;
@@ -1031,6 +1033,169 @@ void Worker::StopCpuProfile(const FunctionCallbackInfo<Value>& args) {
1031
1033
}
1032
1034
}
1033
1035
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
+ }
1034
1199
class WorkerHeapStatisticsTaker : public AsyncWrap {
1035
1200
public:
1036
1201
WorkerHeapStatisticsTaker (Environment* env, Local<Object> obj)
@@ -1328,6 +1493,8 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
1328
1493
SetProtoMethod (isolate, w, " cpuUsage" , Worker::CpuUsage);
1329
1494
SetProtoMethod (isolate, w, " startCpuProfile" , Worker::StartCpuProfile);
1330
1495
SetProtoMethod (isolate, w, " stopCpuProfile" , Worker::StopCpuProfile);
1496
+ SetProtoMethod (isolate, w, " startHeapProfile" , Worker::StartHeapProfile);
1497
+ SetProtoMethod (isolate, w, " stopHeapProfile" , Worker::StopHeapProfile);
1331
1498
1332
1499
SetConstructorFunction (isolate, target, " Worker" , w);
1333
1500
}
@@ -1387,6 +1554,20 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
1387
1554
wst->InstanceTemplate ());
1388
1555
}
1389
1556
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
+
1390
1571
SetMethod (isolate, target, " getEnvMessagePort" , GetEnvMessagePort);
1391
1572
}
1392
1573
@@ -1466,6 +1647,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1466
1647
registry->Register (Worker::CpuUsage);
1467
1648
registry->Register (Worker::StartCpuProfile);
1468
1649
registry->Register (Worker::StopCpuProfile);
1650
+ registry->Register (Worker::StartHeapProfile);
1651
+ registry->Register (Worker::StopHeapProfile);
1469
1652
}
1470
1653
1471
1654
} // anonymous namespace
0 commit comments