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,176 @@ void Worker::StopCpuProfile(const FunctionCallbackInfo<Value>& args) {
1031
1033
}
1032
1034
}
1033
1035
1036
+
1037
+ class WorkerHeapProfileTaker final : public AsyncWrap {
1038
+ public:
1039
+ WorkerHeapProfileTaker (Environment* env, Local<Object> obj)
1040
+ : AsyncWrap(env, obj, AsyncWrap::PROVIDER_WORKERHEAPPROFILE) {}
1041
+
1042
+ SET_NO_MEMORY_INFO ()
1043
+ SET_MEMORY_INFO_NAME (WorkerHeapProfileTaker)
1044
+ SET_SELF_SIZE (WorkerHeapProfileTaker)
1045
+ };
1046
+
1047
+ void Worker::StartHeapProfile (const FunctionCallbackInfo<Value>& args) {
1048
+ Worker* w;
1049
+ ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
1050
+ Environment* env = w->env ();
1051
+
1052
+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (w);
1053
+ Local<Object> wrap;
1054
+ if (!env->worker_heap_profile_taker_template ()
1055
+ ->NewInstance (env->context ())
1056
+ .ToLocal (&wrap)) {
1057
+ return ;
1058
+ }
1059
+
1060
+ BaseObjectPtr<WorkerHeapProfileTaker> taker =
1061
+ MakeDetachedBaseObject<WorkerHeapProfileTaker>(env, wrap);
1062
+
1063
+ bool scheduled = w->RequestInterrupt ([taker = std::move (taker),
1064
+ env](Environment* worker_env) mutable {
1065
+ v8::HeapProfiler* profiler = worker_env->isolate ()->GetHeapProfiler ();
1066
+ bool success = profiler->StartSamplingHeapProfiler ();
1067
+ env->SetImmediateThreadsafe (
1068
+ [
1069
+ taker = std::move (taker),
1070
+ success = success
1071
+ ](Environment* env) mutable {
1072
+ Isolate* isolate = env->isolate ();
1073
+ HandleScope handle_scope (isolate);
1074
+ Context::Scope context_scope (env->context ());
1075
+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (taker.get ());
1076
+ Local<Value> argv[] = {
1077
+ Null (isolate), // error
1078
+ };
1079
+ if (!success) {
1080
+ argv[0 ] = ERR_HEAP_PROFILE_HAVE_BEEN_STARTED (
1081
+ isolate, " heap profiler have been started" );
1082
+ }
1083
+ taker->MakeCallback (env->ondone_string (), arraysize (argv), argv);
1084
+ },
1085
+ CallbackFlags::kUnrefed );
1086
+ });
1087
+
1088
+ if (scheduled) {
1089
+ args.GetReturnValue ().Set (wrap);
1090
+ }
1091
+ }
1092
+
1093
+ static void buildHeapProfileNode (Isolate* isolate,
1094
+ const AllocationProfile::Node* node,
1095
+ JSONWriter& writer) {
1096
+ size_t selfSize = 0 ;
1097
+ for (const auto & allocation : node->allocations )
1098
+ selfSize += allocation.size * allocation.count ;
1099
+
1100
+ writer.json_keyvalue (" selfSize" , selfSize);
1101
+ writer.json_keyvalue (" id" , node->node_id );
1102
+ writer.json_objectstart (" callFrame" );
1103
+ writer.json_keyvalue (" scriptId" , node->script_id );
1104
+ writer.json_keyvalue (" lineNumber" , node->line_number -1 );
1105
+ writer.json_keyvalue (" columnNumber" , node->column_number -1 );
1106
+ node::Utf8Value name (isolate, node->name );
1107
+ node::Utf8Value script_name (isolate, node->script_name );
1108
+ writer.json_keyvalue (" functionName" , *name);
1109
+ writer.json_keyvalue (" url" , *script_name);
1110
+ writer.json_objectend ();
1111
+
1112
+ writer.json_arraystart (" children" );
1113
+ for (const auto * child : node->children ) {
1114
+ writer.json_start ();
1115
+ buildHeapProfileNode (isolate, child, writer);
1116
+ writer.json_end ();
1117
+ }
1118
+ writer.json_arrayend ();
1119
+ }
1120
+
1121
+ static bool serializeProfile (Isolate* isolate, std::ostringstream& out_stream) {
1122
+ HandleScope scope (isolate);
1123
+ HeapProfiler* profiler = isolate->GetHeapProfiler ();
1124
+ std::unique_ptr<AllocationProfile> profile (profiler->GetAllocationProfile ());
1125
+ if (!profile) {
1126
+ return false ;
1127
+ }
1128
+ JSONWriter writer (out_stream, false );
1129
+ writer.json_start ();
1130
+
1131
+ writer.json_arraystart (" samples" );
1132
+ for (const auto & sample : profile->GetSamples ()) {
1133
+ writer.json_start ();
1134
+ writer.json_keyvalue (" size" , sample.size * sample.count );
1135
+ writer.json_keyvalue (" nodeId" , sample.node_id );
1136
+ writer.json_keyvalue (" ordinal" , static_cast <double >(sample.sample_id ));
1137
+ writer.json_end ();
1138
+ }
1139
+ writer.json_arrayend ();
1140
+
1141
+ writer.json_objectstart (" head" );
1142
+ buildHeapProfileNode (isolate, profile->GetRootNode (), writer);
1143
+ writer.json_objectend ();
1144
+
1145
+ writer.json_end ();
1146
+ profiler->StopSamplingHeapProfiler ();
1147
+ return true ;
1148
+ }
1149
+
1150
+ void Worker::StopHeapProfile (const FunctionCallbackInfo<Value>& args) {
1151
+ Worker* w;
1152
+ ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
1153
+
1154
+ Environment* env = w->env ();
1155
+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (w);
1156
+ Local<Object> wrap;
1157
+ if (!env->worker_heap_profile_taker_template ()
1158
+ ->NewInstance (env->context ())
1159
+ .ToLocal (&wrap)) {
1160
+ return ;
1161
+ }
1162
+
1163
+ BaseObjectPtr<WorkerHeapProfileTaker> taker =
1164
+ MakeDetachedBaseObject<WorkerHeapProfileTaker>(env, wrap);
1165
+
1166
+ bool scheduled = w->RequestInterrupt ([taker = std::move (taker),
1167
+ env](Environment* worker_env) mutable {
1168
+ std::ostringstream out_stream;
1169
+ bool success = serializeProfile (worker_env->isolate (), out_stream);
1170
+ env->SetImmediateThreadsafe (
1171
+ [taker = std::move (taker),
1172
+ out_stream = std::move (out_stream),
1173
+ success = success
1174
+ ](Environment* env) mutable {
1175
+ Isolate* isolate = env->isolate ();
1176
+ HandleScope handle_scope (isolate);
1177
+ Context::Scope context_scope (env->context ());
1178
+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (taker.get ());
1179
+ Local<Value> argv[] = {
1180
+ Null (isolate), // error
1181
+ Undefined (isolate), // profile
1182
+ };
1183
+ if (success) {
1184
+ Local<Value> result;
1185
+ if (!ToV8Value (env->context (),
1186
+ out_stream.str (),
1187
+ isolate)
1188
+ .ToLocal (&result)) {
1189
+ return ;
1190
+ }
1191
+ argv[1 ] = result;
1192
+ } else {
1193
+ argv[0 ] =
1194
+ ERR_HEAP_PROFILE_NOT_STARTED (isolate,
1195
+ " heap profile not started" );
1196
+ }
1197
+ taker->MakeCallback (env->ondone_string (), arraysize (argv), argv);
1198
+ },
1199
+ CallbackFlags::kUnrefed );
1200
+ });
1201
+
1202
+ if (scheduled) {
1203
+ args.GetReturnValue ().Set (wrap);
1204
+ }
1205
+ }
1034
1206
class WorkerHeapStatisticsTaker : public AsyncWrap {
1035
1207
public:
1036
1208
WorkerHeapStatisticsTaker (Environment* env, Local<Object> obj)
@@ -1328,6 +1500,8 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
1328
1500
SetProtoMethod (isolate, w, " cpuUsage" , Worker::CpuUsage);
1329
1501
SetProtoMethod (isolate, w, " startCpuProfile" , Worker::StartCpuProfile);
1330
1502
SetProtoMethod (isolate, w, " stopCpuProfile" , Worker::StopCpuProfile);
1503
+ SetProtoMethod (isolate, w, " startHeapProfile" , Worker::StartHeapProfile);
1504
+ SetProtoMethod (isolate, w, " stopHeapProfile" , Worker::StopHeapProfile);
1331
1505
1332
1506
SetConstructorFunction (isolate, target, " Worker" , w);
1333
1507
}
@@ -1387,6 +1561,20 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
1387
1561
wst->InstanceTemplate ());
1388
1562
}
1389
1563
1564
+ {
1565
+ Local<FunctionTemplate> wst = NewFunctionTemplate (isolate, nullptr );
1566
+
1567
+ wst->InstanceTemplate ()->SetInternalFieldCount (
1568
+ WorkerHeapProfileTaker::kInternalFieldCount );
1569
+ wst->Inherit (AsyncWrap::GetConstructorTemplate (isolate_data));
1570
+
1571
+ Local<String> wst_string =
1572
+ FIXED_ONE_BYTE_STRING (isolate, " WorkerHeapProfileTaker" );
1573
+ wst->SetClassName (wst_string);
1574
+ isolate_data->set_worker_heap_profile_taker_template (
1575
+ wst->InstanceTemplate ());
1576
+ }
1577
+
1390
1578
SetMethod (isolate, target, " getEnvMessagePort" , GetEnvMessagePort);
1391
1579
}
1392
1580
@@ -1466,6 +1654,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1466
1654
registry->Register (Worker::CpuUsage);
1467
1655
registry->Register (Worker::StartCpuProfile);
1468
1656
registry->Register (Worker::StopCpuProfile);
1657
+ registry->Register (Worker::StartHeapProfile);
1658
+ registry->Register (Worker::StopHeapProfile);
1469
1659
}
1470
1660
1471
1661
} // anonymous namespace
0 commit comments