1
1
#include " env-inl.h"
2
+ #include " stream_base-inl.h"
2
3
3
4
using v8::Array;
4
5
using v8::Boolean ;
5
6
using v8::Context;
6
7
using v8::EmbedderGraph;
7
8
using v8::EscapableHandleScope;
8
9
using v8::FunctionCallbackInfo;
10
+ using v8::FunctionTemplate;
9
11
using v8::HandleScope;
10
12
using v8::HeapSnapshot;
11
13
using v8::Isolate;
@@ -14,6 +16,7 @@ using v8::Local;
14
16
using v8::MaybeLocal;
15
17
using v8::Number;
16
18
using v8::Object;
19
+ using v8::ObjectTemplate;
17
20
using v8::String;
18
21
using v8::Value;
19
22
@@ -231,27 +234,220 @@ class BufferOutputStream : public v8::OutputStream {
231
234
std::unique_ptr<JSString> buffer_;
232
235
};
233
236
234
- void CreateHeapDump (const FunctionCallbackInfo<Value>& args) {
237
+ namespace {
238
+ class FileOutputStream : public v8 ::OutputStream {
239
+ public:
240
+ explicit FileOutputStream (FILE* stream) : stream_(stream) {}
241
+
242
+ int GetChunkSize () override {
243
+ return 65536 ; // big chunks == faster
244
+ }
245
+
246
+ void EndOfStream () override {}
247
+
248
+ WriteResult WriteAsciiChunk (char * data, int size) override {
249
+ const size_t len = static_cast <size_t >(size);
250
+ size_t off = 0 ;
251
+
252
+ while (off < len && !feof (stream_) && !ferror (stream_))
253
+ off += fwrite (data + off, 1 , len - off, stream_);
254
+
255
+ return off == len ? kContinue : kAbort ;
256
+ }
257
+
258
+ private:
259
+ FILE* stream_;
260
+ };
261
+
262
+ class HeapSnapshotStream : public AsyncWrap ,
263
+ public StreamBase,
264
+ public v8::OutputStream {
265
+ public:
266
+ HeapSnapshotStream (
267
+ Environment* env,
268
+ const HeapSnapshot* snapshot,
269
+ v8::Local<v8::Object> obj) :
270
+ AsyncWrap (env, obj, AsyncWrap::PROVIDER_HEAPSNAPSHOT),
271
+ StreamBase (env),
272
+ snapshot_ (snapshot) {
273
+ MakeWeak ();
274
+ StreamBase::AttachToObject (GetObject ());
275
+ }
276
+
277
+ ~HeapSnapshotStream () override {
278
+ Cleanup ();
279
+ }
280
+
281
+ int GetChunkSize () override {
282
+ return 65536 ; // big chunks == faster
283
+ }
284
+
285
+ void EndOfStream () override {
286
+ EmitRead (UV_EOF);
287
+ Cleanup ();
288
+ }
289
+
290
+ WriteResult WriteAsciiChunk (char * data, int size) override {
291
+ int len = size;
292
+ while (len != 0 ) {
293
+ uv_buf_t buf = EmitAlloc (size);
294
+ ssize_t avail = len;
295
+ if (static_cast <ssize_t >(buf.len ) < avail)
296
+ avail = buf.len ;
297
+ memcpy (buf.base , data, avail);
298
+ data += avail;
299
+ len -= avail;
300
+ EmitRead (size, buf);
301
+ }
302
+ return kContinue ;
303
+ }
304
+
305
+ int ReadStart () override {
306
+ CHECK_NE (snapshot_, nullptr );
307
+ snapshot_->Serialize (this , HeapSnapshot::kJSON );
308
+ return 0 ;
309
+ }
310
+
311
+ int ReadStop () override {
312
+ return 0 ;
313
+ }
314
+
315
+ int DoShutdown (ShutdownWrap* req_wrap) override {
316
+ UNREACHABLE ();
317
+ return 0 ;
318
+ }
319
+
320
+ int DoWrite (WriteWrap* w,
321
+ uv_buf_t * bufs,
322
+ size_t count,
323
+ uv_stream_t * send_handle) override {
324
+ UNREACHABLE ();
325
+ return 0 ;
326
+ }
327
+
328
+ bool IsAlive () override { return snapshot_ != nullptr ; }
329
+ bool IsClosing () override { return snapshot_ == nullptr ; }
330
+ AsyncWrap* GetAsyncWrap () override { return this ; }
331
+
332
+ void MemoryInfo (MemoryTracker* tracker) const override {
333
+ if (snapshot_ != nullptr ) {
334
+ tracker->TrackFieldWithSize (
335
+ " snapshot" , sizeof (*snapshot_), " HeapSnapshot" );
336
+ }
337
+ }
338
+
339
+ SET_MEMORY_INFO_NAME (HeapSnapshotStream)
340
+ SET_SELF_SIZE (HeapSnapshotStream)
341
+
342
+ private:
343
+ void Cleanup () {
344
+ if (snapshot_ != nullptr ) {
345
+ const_cast <HeapSnapshot*>(snapshot_)->Delete ();
346
+ snapshot_ = nullptr ;
347
+ }
348
+ }
349
+
350
+
351
+ const HeapSnapshot* snapshot_;
352
+ };
353
+
354
+ inline void TakeSnapshot (Isolate* isolate, v8::OutputStream* out) {
355
+ const HeapSnapshot* const snapshot =
356
+ isolate->GetHeapProfiler ()->TakeHeapSnapshot ();
357
+ snapshot->Serialize (out, HeapSnapshot::kJSON );
358
+ const_cast <HeapSnapshot*>(snapshot)->Delete ();
359
+ }
360
+
361
+ inline bool WriteSnapshot (Isolate* isolate, const char * filename) {
362
+ FILE* fp = fopen (filename, " w" );
363
+ if (fp == nullptr )
364
+ return false ;
365
+ FileOutputStream stream (fp);
366
+ TakeSnapshot (isolate, &stream);
367
+ fclose (fp);
368
+ return true ;
369
+ }
370
+
371
+ } // namespace
372
+
373
+ void CreateHeapSnapshot (const FunctionCallbackInfo<Value>& args) {
235
374
Isolate* isolate = args.GetIsolate ();
236
- const HeapSnapshot* snapshot = isolate->GetHeapProfiler ()->TakeHeapSnapshot ();
237
375
BufferOutputStream out;
238
- snapshot->Serialize (&out, HeapSnapshot::kJSON );
239
- const_cast <HeapSnapshot*>(snapshot)->Delete ();
376
+ TakeSnapshot (isolate, &out);
240
377
Local<Value> ret;
241
378
if (JSON::Parse (isolate->GetCurrentContext (),
242
379
out.ToString (isolate)).ToLocal (&ret)) {
243
380
args.GetReturnValue ().Set (ret);
244
381
}
245
382
}
246
383
384
+ void CreateHeapSnapshotStream (const FunctionCallbackInfo<Value>& args) {
385
+ Environment* env = Environment::GetCurrent (args);
386
+ HandleScope scope (env->isolate ());
387
+ const HeapSnapshot* const snapshot =
388
+ env->isolate ()->GetHeapProfiler ()->TakeHeapSnapshot ();
389
+ CHECK_NOT_NULL (snapshot);
390
+ Local<Object> obj;
391
+ if (!env->streambaseoutputstream_constructor_template ()
392
+ ->NewInstance (env->context ())
393
+ .ToLocal (&obj)) {
394
+ return ;
395
+ }
396
+ HeapSnapshotStream* out = new HeapSnapshotStream (env, snapshot, obj);
397
+ args.GetReturnValue ().Set (out->object ());
398
+ }
399
+
400
+ void TriggerHeapSnapshot (const FunctionCallbackInfo<Value>& args) {
401
+ Environment* env = Environment::GetCurrent (args);
402
+ Isolate* isolate = args.GetIsolate ();
403
+
404
+ Local<Value> filename_v = args[0 ];
405
+
406
+ if (filename_v->IsUndefined ()) {
407
+ DiagnosticFilename name (env, " Heap" , " heapsnapshot" );
408
+ if (!WriteSnapshot (isolate, *name))
409
+ return ;
410
+ if (String::NewFromUtf8 (isolate, *name, v8::NewStringType::kNormal )
411
+ .ToLocal (&filename_v)) {
412
+ args.GetReturnValue ().Set (filename_v);
413
+ }
414
+ return ;
415
+ }
416
+
417
+ BufferValue path (isolate, filename_v);
418
+ CHECK_NOT_NULL (*path);
419
+ if (!WriteSnapshot (isolate, *path))
420
+ return ;
421
+ return args.GetReturnValue ().Set (filename_v);
422
+ }
423
+
247
424
void Initialize (Local<Object> target,
248
425
Local<Value> unused,
249
426
Local<Context> context,
250
427
void * priv) {
251
428
Environment* env = Environment::GetCurrent (context);
252
429
253
- env->SetMethodNoSideEffect (target, " buildEmbedderGraph" , BuildEmbedderGraph);
254
- env->SetMethodNoSideEffect (target, " createHeapDump" , CreateHeapDump);
430
+ env->SetMethodNoSideEffect (target,
431
+ " buildEmbedderGraph" ,
432
+ BuildEmbedderGraph);
433
+ env->SetMethodNoSideEffect (target,
434
+ " createHeapSnapshot" ,
435
+ CreateHeapSnapshot);
436
+ env->SetMethodNoSideEffect (target,
437
+ " triggerHeapSnapshot" ,
438
+ TriggerHeapSnapshot);
439
+ env->SetMethodNoSideEffect (target,
440
+ " createHeapSnapshotStream" ,
441
+ CreateHeapSnapshotStream);
442
+
443
+ // Create FunctionTemplate for HeapSnapshotStream
444
+ Local<FunctionTemplate> os = FunctionTemplate::New (env->isolate ());
445
+ os->Inherit (AsyncWrap::GetConstructorTemplate (env));
446
+ Local<ObjectTemplate> ost = os->InstanceTemplate ();
447
+ ost->SetInternalFieldCount (StreamBase::kStreamBaseField + 1 );
448
+ os->SetClassName (FIXED_ONE_BYTE_STRING (env->isolate (), " HeapSnapshotStream" ));
449
+ StreamBase::AddMethods (env, os);
450
+ env->set_streambaseoutputstream_constructor_template (ost);
255
451
}
256
452
257
453
} // namespace heap
0 commit comments