diff --git a/packages/profiling-node/src/cpu_profiler.ts b/packages/profiling-node/src/cpu_profiler.ts index 4897745ededa..ed4ad83e7b31 100644 --- a/packages/profiling-node/src/cpu_profiler.ts +++ b/packages/profiling-node/src/cpu_profiler.ts @@ -172,6 +172,12 @@ class Bindings implements V8CpuProfilerBindings { return; } + if (typeof PrivateCpuProfilerBindings.startProfiling !== 'function') { + DEBUG_BUILD && + logger.log('[Profiling] Native startProfiling function is not available, ignoring call to startProfiling.'); + return; + } + return PrivateCpuProfilerBindings.startProfiling(name); } @@ -187,6 +193,12 @@ class Bindings implements V8CpuProfilerBindings { return null; } + if (typeof PrivateCpuProfilerBindings.stopProfiling !== 'function') { + DEBUG_BUILD && + logger.log('[Profiling] Native stopProfiling function is not available, ignoring call to stopProfiling.'); + return null; + } + return PrivateCpuProfilerBindings.stopProfiling( name, format as unknown as any, diff --git a/packages/profiling-node/src/types.ts b/packages/profiling-node/src/types.ts index 2423ca94651b..9b8f039b3c95 100644 --- a/packages/profiling-node/src/types.ts +++ b/packages/profiling-node/src/types.ts @@ -52,15 +52,15 @@ export interface RawChunkCpuProfile extends BaseProfile { } export interface PrivateV8CpuProfilerBindings { - startProfiling(name: string): void; + startProfiling?: (name: string) => void; - stopProfiling( + stopProfiling?( name: string, format: ProfileFormat.THREAD, threadId: number, collectResources: boolean, ): RawThreadCpuProfile | null; - stopProfiling( + stopProfiling?( name: string, format: ProfileFormat.CHUNK, threadId: number, diff --git a/packages/profiling-node/test/cpu_profiler.test.ts b/packages/profiling-node/test/cpu_profiler.test.ts index 4db0b98891a3..1719b570e28e 100644 --- a/packages/profiling-node/test/cpu_profiler.test.ts +++ b/packages/profiling-node/test/cpu_profiler.test.ts @@ -69,28 +69,28 @@ const assertValidMeasurements = (measurement: RawThreadCpuProfile['measurements' describe('Private bindings', () => { it('does not crash if collect resources is false', async () => { - PrivateCpuProfilerBindings.startProfiling('profiled-program'); + PrivateCpuProfilerBindings.startProfiling!('profiled-program'); await wait(100); expect(() => { - const profile = PrivateCpuProfilerBindings.stopProfiling('profiled-program', 0, 0, false); + const profile = PrivateCpuProfilerBindings.stopProfiling!('profiled-program', 0, 0, false); if (!profile) throw new Error('No profile'); }).not.toThrow(); }); it('throws if invalid format is supplied', async () => { - PrivateCpuProfilerBindings.startProfiling('profiled-program'); + PrivateCpuProfilerBindings.startProfiling!('profiled-program'); await wait(100); expect(() => { - const profile = PrivateCpuProfilerBindings.stopProfiling('profiled-program', Number.MAX_SAFE_INTEGER, 0, false); + const profile = PrivateCpuProfilerBindings.stopProfiling!('profiled-program', Number.MAX_SAFE_INTEGER, 0, false); if (!profile) throw new Error('No profile'); }).toThrow('StopProfiling expects a valid format type as second argument.'); }); it('collects resources', async () => { - PrivateCpuProfilerBindings.startProfiling('profiled-program'); + PrivateCpuProfilerBindings.startProfiling!('profiled-program'); await wait(100); - const profile = PrivateCpuProfilerBindings.stopProfiling('profiled-program', 0, 0, true); + const profile = PrivateCpuProfilerBindings.stopProfiling!('profiled-program', 0, 0, true); if (!profile) throw new Error('No profile'); expect(profile.resources.length).toBeGreaterThan(0); @@ -104,10 +104,10 @@ describe('Private bindings', () => { }); it('does not collect resources', async () => { - PrivateCpuProfilerBindings.startProfiling('profiled-program'); + PrivateCpuProfilerBindings.startProfiling!('profiled-program'); await wait(100); - const profile = PrivateCpuProfilerBindings.stopProfiling('profiled-program', 0, 0, false); + const profile = PrivateCpuProfilerBindings.stopProfiling!('profiled-program', 0, 0, false); if (!profile) throw new Error('No profile'); expect(profile.resources.length).toBe(0); @@ -337,4 +337,27 @@ describe('Profiler bindings', () => { const hasDeoptimizedFrame = profile.frames.some(f => f.deopt_reasons && f.deopt_reasons.length > 0); expect(hasDeoptimizedFrame).toBe(true); }); + + it('does not crash if the native startProfiling function is not available', async () => { + const original = PrivateCpuProfilerBindings.startProfiling; + PrivateCpuProfilerBindings.startProfiling = undefined; + + expect(() => { + CpuProfilerBindings.startProfiling('profiled-program'); + }).not.toThrow(); + + PrivateCpuProfilerBindings.startProfiling = original; + }); + + it('does not crash if the native stopProfiling function is not available', async () => { + // eslint-disable-next-line @typescript-eslint/unbound-method + const original = PrivateCpuProfilerBindings.stopProfiling; + PrivateCpuProfilerBindings.stopProfiling = undefined; + + expect(() => { + CpuProfilerBindings.stopProfiling('profiled-program', 0); + }).not.toThrow(); + + PrivateCpuProfilerBindings.stopProfiling = original; + }); });