@@ -24,6 +24,7 @@ const Buffer = require('buffer').Buffer;
2424const { spawn } = require ( 'child_process' ) ;
2525const crypto = require ( 'crypto' ) ;
2626const { EventEmitter } = require ( 'events' ) ;
27+ const FS = require ( 'fs' ) ;
2728const http = require ( 'http' ) ;
2829const Path = require ( 'path' ) ;
2930const Repl = require ( 'repl' ) ;
@@ -585,7 +586,7 @@ function createRepl(inspector) {
585586 } ) ;
586587 }
587588
588- const { Debugger, Runtime } = inspector ;
589+ const { Debugger, HeapProfiler , Profiler , Runtime } = inspector ;
589590
590591 let repl ; // eslint-disable-line prefer-const
591592
@@ -676,6 +677,31 @@ function createRepl(inspector) {
676677 }
677678 }
678679
680+ const profiles = [ ] ;
681+ class Profile {
682+ constructor ( data ) {
683+ this . data = data ;
684+ }
685+
686+ static createAndRegister ( { profile } ) {
687+ const p = new Profile ( profile ) ;
688+ profiles . push ( p ) ;
689+ return p ;
690+ }
691+
692+ [ util . inspect . custom ] ( depth , { stylize } ) {
693+ const { startTime, endTime } = this . data ;
694+ return stylize ( `[Profile ${ endTime - startTime } μs]` , 'special' ) ;
695+ }
696+
697+ save ( filename = 'node.cpuprofile' ) {
698+ const absoluteFile = Path . resolve ( filename ) ;
699+ const json = JSON . stringify ( this . data ) ;
700+ FS . writeFileSync ( absoluteFile , json ) ;
701+ print ( 'Saved profile to ' + absoluteFile ) ;
702+ }
703+ }
704+
679705 class SourceSnippet {
680706 constructor ( location , delta , scriptSource ) {
681707 Object . assign ( this , location ) ;
@@ -1113,6 +1139,14 @@ function createRepl(inspector) {
11131139 }
11141140 } ) ;
11151141
1142+ Profiler . on ( 'consoleProfileFinished' , ( { profile } ) => {
1143+ Profile . createAndRegister ( { profile } ) ;
1144+ print ( [
1145+ 'Captured new CPU profile.' ,
1146+ `Access it with profiles[${ profiles . length - 1 } ]`
1147+ ] . join ( '\n' ) ) ;
1148+ } ) ;
1149+
11161150 function initializeContext ( context ) {
11171151 inspector . domainNames . forEach ( ( domain ) => {
11181152 Object . defineProperty ( context , domain , {
@@ -1176,6 +1210,62 @@ function createRepl(inspector) {
11761210 return evalInCurrentContext ( expr ) ;
11771211 } ,
11781212
1213+ get profile ( ) {
1214+ return Profiler . start ( ) ;
1215+ } ,
1216+
1217+ get profileEnd ( ) {
1218+ return Profiler . stop ( )
1219+ . then ( Profile . createAndRegister ) ;
1220+ } ,
1221+
1222+ get profiles ( ) {
1223+ return profiles ;
1224+ } ,
1225+
1226+ takeHeapSnapshot ( filename = 'node.heapsnapshot' ) {
1227+ return new Promise ( ( resolve , reject ) => {
1228+ const absoluteFile = Path . resolve ( filename ) ;
1229+ const writer = FS . createWriteStream ( absoluteFile ) ;
1230+ let totalSize ;
1231+ let sizeWritten = 0 ;
1232+ function onProgress ( { done, total, finished } ) {
1233+ totalSize = total ;
1234+ if ( finished ) {
1235+ print ( 'Heap snaphost prepared.' ) ;
1236+ } else {
1237+ print ( `Heap snapshot: ${ done } /${ total } ` , true ) ;
1238+ }
1239+ }
1240+ function onChunk ( { chunk } ) {
1241+ sizeWritten += chunk . length ;
1242+ writer . write ( chunk ) ;
1243+ print ( `Writing snapshot: ${ sizeWritten } /${ totalSize } ` , true ) ;
1244+ if ( sizeWritten >= totalSize ) {
1245+ writer . end ( ) ;
1246+ teardown ( ) ;
1247+ print ( `Wrote snapshot: ${ absoluteFile } ` ) ;
1248+ resolve ( ) ;
1249+ }
1250+ }
1251+ function teardown ( ) {
1252+ HeapProfiler . removeListener (
1253+ 'reportHeapSnapshotProgress' , onProgress ) ;
1254+ HeapProfiler . removeListener ( 'addHeapSnapshotChunk' , onChunk ) ;
1255+ }
1256+
1257+ HeapProfiler . on ( 'reportHeapSnapshotProgress' , onProgress ) ;
1258+ HeapProfiler . on ( 'addHeapSnapshotChunk' , onChunk ) ;
1259+
1260+ print ( 'Heap snapshot: 0/0' , true ) ;
1261+ HeapProfiler . takeHeapSnapshot ( { reportProgress : true } )
1262+ . then ( null , ( error ) => {
1263+ teardown ( ) ;
1264+ reject ( error ) ;
1265+ } ) ;
1266+ } ) ;
1267+ } ,
1268+
11791269 get watchers ( ) {
11801270 return watchers ( ) ;
11811271 } ,
@@ -1374,7 +1464,7 @@ class NodeInspector {
13741464
13751465 this . client = new ProtocolClient ( options . port , options . host ) ;
13761466
1377- this . domainNames = [ 'Debugger' , 'Runtime' ] ;
1467+ this . domainNames = [ 'Debugger' , 'HeapProfiler' , 'Profiler' , ' Runtime'] ;
13781468 this . domainNames . forEach ( ( domain ) => {
13791469 this [ domain ] = createAgentProxy ( domain , this . client ) ;
13801470 } ) ;
0 commit comments