@@ -33,6 +33,7 @@ namespace v8_utils {
33
33
using v8::Array;
34
34
using v8::Context;
35
35
using v8::FunctionCallbackInfo;
36
+ using v8::FunctionTemplate;
36
37
using v8::HandleScope;
37
38
using v8::HeapCodeStatistics;
38
39
using v8::HeapSpaceStatistics;
@@ -210,6 +211,184 @@ void SetFlagsFromString(const FunctionCallbackInfo<Value>& args) {
210
211
V8::SetFlagsFromString (*flags, static_cast <size_t >(flags.length ()));
211
212
}
212
213
214
+ static const char * GetGCTypeName (v8::GCType gc_type) {
215
+ switch (gc_type) {
216
+ case v8::GCType::kGCTypeScavenge :
217
+ return " Scavenge" ;
218
+ case v8::GCType::kGCTypeMarkSweepCompact :
219
+ return " MarkSweepCompact" ;
220
+ case v8::GCType::kGCTypeIncrementalMarking :
221
+ return " IncrementalMarking" ;
222
+ case v8::GCType::kGCTypeProcessWeakCallbacks :
223
+ return " ProcessWeakCallbacks" ;
224
+ default :
225
+ return " Unknown" ;
226
+ }
227
+ }
228
+
229
+ static void SetHeapStatistics (JSONWriter* writer, Isolate* isolate) {
230
+ HeapStatistics heap_statistics;
231
+ isolate->GetHeapStatistics (&heap_statistics);
232
+ writer->json_objectstart (" heapStatistics" );
233
+ writer->json_keyvalue (" totalHeapSize" , heap_statistics.total_heap_size ());
234
+ writer->json_keyvalue (" totalHeapSizeExecutable" ,
235
+ heap_statistics.total_heap_size_executable ());
236
+ writer->json_keyvalue (" totalPhysicalSize" ,
237
+ heap_statistics.total_physical_size ());
238
+ writer->json_keyvalue (" totalAvailableSize" ,
239
+ heap_statistics.total_available_size ());
240
+ writer->json_keyvalue (" totalGlobalHandlesSize" ,
241
+ heap_statistics.total_global_handles_size ());
242
+ writer->json_keyvalue (" usedGlobalHandlesSize" ,
243
+ heap_statistics.used_global_handles_size ());
244
+ writer->json_keyvalue (" usedHeapSize" , heap_statistics.used_heap_size ());
245
+ writer->json_keyvalue (" heapSizeLimit" , heap_statistics.heap_size_limit ());
246
+ writer->json_keyvalue (" mallocedMemory" , heap_statistics.malloced_memory ());
247
+ writer->json_keyvalue (" externalMemory" , heap_statistics.external_memory ());
248
+ writer->json_keyvalue (" peakMallocedMemory" ,
249
+ heap_statistics.peak_malloced_memory ());
250
+ writer->json_objectend ();
251
+
252
+ int space_count = isolate->NumberOfHeapSpaces ();
253
+ writer->json_arraystart (" heapSpaceStatistics" );
254
+ for (int i = 0 ; i < space_count; i++) {
255
+ HeapSpaceStatistics heap_space_statistics;
256
+ isolate->GetHeapSpaceStatistics (&heap_space_statistics, i);
257
+ writer->json_start ();
258
+ writer->json_keyvalue (" spaceName" , heap_space_statistics.space_name ());
259
+ writer->json_keyvalue (" spaceSize" , heap_space_statistics.space_size ());
260
+ writer->json_keyvalue (" spaceUsedSize" ,
261
+ heap_space_statistics.space_used_size ());
262
+ writer->json_keyvalue (" spaceAvailableSize" ,
263
+ heap_space_statistics.space_available_size ());
264
+ writer->json_keyvalue (" physicalSpaceSize" ,
265
+ heap_space_statistics.physical_space_size ());
266
+ writer->json_end ();
267
+ }
268
+ writer->json_arrayend ();
269
+ }
270
+
271
+ static void BeforeGCCallback (Isolate* isolate,
272
+ v8::GCType gc_type,
273
+ v8::GCCallbackFlags flags,
274
+ void * data) {
275
+ GCProfiler* profiler = static_cast <GCProfiler*>(data);
276
+ if (profiler->current_gc_type != 0 ) {
277
+ return ;
278
+ }
279
+ JSONWriter* writer = profiler->writer ();
280
+ writer->json_start ();
281
+ writer->json_keyvalue (" gcType" , GetGCTypeName (gc_type));
282
+ writer->json_objectstart (" beforeGC" );
283
+ SetHeapStatistics (writer, isolate);
284
+ writer->json_objectend ();
285
+ profiler->current_gc_type = gc_type;
286
+ profiler->start_time = uv_hrtime ();
287
+ }
288
+
289
+ static void AfterGCCallback (Isolate* isolate,
290
+ v8::GCType gc_type,
291
+ v8::GCCallbackFlags flags,
292
+ void * data) {
293
+ GCProfiler* profiler = static_cast <GCProfiler*>(data);
294
+ if (profiler->current_gc_type != gc_type) {
295
+ return ;
296
+ }
297
+ JSONWriter* writer = profiler->writer ();
298
+ profiler->current_gc_type = 0 ;
299
+ writer->json_keyvalue (" cost" , (uv_hrtime () - profiler->start_time ) / 1e3 );
300
+ profiler->start_time = 0 ;
301
+ writer->json_objectstart (" afterGC" );
302
+ SetHeapStatistics (writer, isolate);
303
+ writer->json_objectend ();
304
+ writer->json_end ();
305
+ }
306
+
307
+ GCProfiler::GCProfiler (Environment* env, Local<Object> object)
308
+ : BaseObject(env, object),
309
+ start_time(0 ),
310
+ current_gc_type(0 ),
311
+ state(GCProfilerState::kInitialized ),
312
+ writer_(out_stream_, false ) {
313
+ MakeWeak ();
314
+ }
315
+
316
+ // This function will be called when
317
+ // 1. StartGCProfile and StopGCProfile are called and
318
+ // JS land does not keep the object anymore.
319
+ // 2. StartGCProfile is called then the env exits before
320
+ // StopGCProfile is called.
321
+ GCProfiler::~GCProfiler () {
322
+ if (state != GCProfiler::GCProfilerState::kInitialized ) {
323
+ env ()->isolate ()->RemoveGCPrologueCallback (BeforeGCCallback, this );
324
+ env ()->isolate ()->RemoveGCEpilogueCallback (AfterGCCallback, this );
325
+ }
326
+ }
327
+
328
+ JSONWriter* GCProfiler::writer () {
329
+ return &writer_;
330
+ }
331
+
332
+ std::ostringstream* GCProfiler::out_stream () {
333
+ return &out_stream_;
334
+ }
335
+
336
+ void GCProfiler::New (const FunctionCallbackInfo<Value>& args) {
337
+ CHECK (args.IsConstructCall ());
338
+ Environment* env = Environment::GetCurrent (args);
339
+ new GCProfiler (env, args.This ());
340
+ }
341
+
342
+ void GCProfiler::Start (const FunctionCallbackInfo<Value>& args) {
343
+ Environment* env = Environment::GetCurrent (args);
344
+ GCProfiler* profiler;
345
+ ASSIGN_OR_RETURN_UNWRAP (&profiler, args.Holder ());
346
+ if (profiler->state != GCProfiler::GCProfilerState::kInitialized ) {
347
+ return ;
348
+ }
349
+ profiler->writer ()->json_start ();
350
+ profiler->writer ()->json_keyvalue (" version" , 1 );
351
+
352
+ uv_timeval64_t ts;
353
+ if (uv_gettimeofday (&ts) == 0 ) {
354
+ profiler->writer ()->json_keyvalue (" startTime" ,
355
+ ts.tv_sec * 1000 + ts.tv_usec / 1000 );
356
+ } else {
357
+ profiler->writer ()->json_keyvalue (" startTime" , 0 );
358
+ }
359
+ profiler->writer ()->json_arraystart (" statistics" );
360
+ env->isolate ()->AddGCPrologueCallback (BeforeGCCallback,
361
+ static_cast <void *>(profiler));
362
+ env->isolate ()->AddGCEpilogueCallback (AfterGCCallback,
363
+ static_cast <void *>(profiler));
364
+ profiler->state = GCProfiler::GCProfilerState::kStarted ;
365
+ }
366
+
367
+ void GCProfiler::Stop (const FunctionCallbackInfo<v8::Value>& args) {
368
+ Environment* env = Environment::GetCurrent (args);
369
+ GCProfiler* profiler;
370
+ ASSIGN_OR_RETURN_UNWRAP (&profiler, args.Holder ());
371
+ if (profiler->state != GCProfiler::GCProfilerState::kStarted ) {
372
+ return ;
373
+ }
374
+ profiler->writer ()->json_arrayend ();
375
+ uv_timeval64_t ts;
376
+ if (uv_gettimeofday (&ts) == 0 ) {
377
+ profiler->writer ()->json_keyvalue (" endTime" ,
378
+ ts.tv_sec * 1000 + ts.tv_usec / 1000 );
379
+ } else {
380
+ profiler->writer ()->json_keyvalue (" endTime" , 0 );
381
+ }
382
+ profiler->writer ()->json_end ();
383
+ profiler->state = GCProfiler::GCProfilerState::kStopped ;
384
+ auto string = profiler->out_stream ()->str ();
385
+ args.GetReturnValue ().Set (String::NewFromUtf8 (env->isolate (),
386
+ string.data (),
387
+ v8::NewStringType::kNormal ,
388
+ string.size ())
389
+ .ToLocalChecked ());
390
+ }
391
+
213
392
void Initialize (Local<Object> target,
214
393
Local<Value> unused,
215
394
Local<Context> context,
@@ -272,6 +451,14 @@ void Initialize(Local<Object> target,
272
451
273
452
// Export symbols used by v8.setFlagsFromString()
274
453
SetMethod (context, target, " setFlagsFromString" , SetFlagsFromString);
454
+
455
+ // GCProfiler
456
+ Local<FunctionTemplate> t =
457
+ NewFunctionTemplate (env->isolate (), GCProfiler::New);
458
+ t->InstanceTemplate ()->SetInternalFieldCount (BaseObject::kInternalFieldCount );
459
+ SetProtoMethod (env->isolate (), t, " start" , GCProfiler::Start);
460
+ SetProtoMethod (env->isolate (), t, " stop" , GCProfiler::Stop);
461
+ SetConstructorFunction (context, target, " GCProfiler" , t);
275
462
}
276
463
277
464
void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
@@ -281,6 +468,9 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
281
468
registry->Register (UpdateHeapSpaceStatisticsBuffer);
282
469
registry->Register (SetFlagsFromString);
283
470
registry->Register (SetHeapSnapshotNearHeapLimit);
471
+ registry->Register (GCProfiler::New);
472
+ registry->Register (GCProfiler::Start);
473
+ registry->Register (GCProfiler::Stop);
284
474
}
285
475
286
476
} // namespace v8_utils
0 commit comments