diff --git a/ts/src/profilers/time-profiler.ts b/ts/src/profilers/time-profiler.ts index 6cfa3a5a..f2f52752 100644 --- a/ts/src/profilers/time-profiler.ts +++ b/ts/src/profilers/time-profiler.ts @@ -35,10 +35,20 @@ export class TimeProfiler { * @param durationMillis - time in milliseconds for which to collect profile. */ async profile(durationMillis: number): Promise { + // Node.js contains an undocumented API for reporting idle status to V8. + // This lets the profiler distinguish idle time from time spent in native + // code. Ideally this should be default behavior. Until then, use the + // undocumented API. + // See https://github.com/nodejs/node/issues/19009#issuecomment-403161559. + // tslint:disable-next-line no-any + (process as any)._startProfilerIdleNotifier(); const runName = 'stackdriver-profiler-' + Date.now() + '-' + Math.random(); profiler.startProfiling(runName); await delay(durationMillis); const result = profiler.stopProfiling(runName); - return serializeTimeProfile(result, this.intervalMicros); + // tslint:disable-next-line no-any + (process as any)._stopProfilerIdleNotifier(); + const profile = serializeTimeProfile(result, this.intervalMicros); + return profile; } } diff --git a/ts/test/test-time-profiler.ts b/ts/test/test-time-profiler.ts index 244b6158..18fa62ff 100644 --- a/ts/test/test-time-profiler.ts +++ b/ts/test/test-time-profiler.ts @@ -27,6 +27,17 @@ const v8TimeProfiler = require('bindings')('time_profiler'); describe('TimeProfiler', () => { describe('profile', () => { + it('should detect idle time', async () => { + const durationMillis = 500; + const intervalMicros = 1000; + const profiler = new TimeProfiler(intervalMicros); + const profile = await profiler.profile(durationMillis); + assert.ok(profile.stringTable); + assert.notStrictEqual(profile.stringTable!.indexOf('(idle)'), -1); + }); + }); + + describe('profile (w/ stubs)', () => { const sinonStubs: sinon.SinonStub[] = new Array(); before(() => { sinonStubs.push(sinon.stub(v8TimeProfiler, 'startProfiling'));