From 5268a0b3efa126ae36bf5c17945cc50c16798732 Mon Sep 17 00:00:00 2001 From: Nicolas Savoire Date: Fri, 23 Feb 2024 14:15:48 +0100 Subject: [PATCH 1/2] Rename special frames * Rename `(garbage collector)` to `Garbage Collection` * Rename `(non-JS threads)` to `(Non JS threads activity)` * Place these frame under a `Node.js` parent frame --- ts/src/profile-serializer.ts | 96 +++++++++++++++++++++++++++-------- ts/src/time-profiler.ts | 7 ++- ts/test/profiles-for-tests.ts | 4 +- 3 files changed, 82 insertions(+), 25 deletions(-) diff --git a/ts/src/profile-serializer.ts b/ts/src/profile-serializer.ts index f63d48ff..6fb71777 100644 --- a/ts/src/profile-serializer.ts +++ b/ts/src/profile-serializer.ts @@ -40,7 +40,8 @@ import { TimeProfileNode, } from './v8-types'; -export const NON_JS_THREADS_FUNCTION_NAME = '(non-JS threads)'; +export const NON_JS_THREADS_FUNCTION_NAME = 'Non JS threads activity'; +export const GARBAGE_COLLECTION_FUNCTION_NAME = 'Garbage Collection'; /** * A stack of function IDs. @@ -110,7 +111,6 @@ function serialize( if (ignoreSamplesPath && node.scriptName.indexOf(ignoreSamplesPath) > -1) { continue; } - if (node.name === '(idle)' || node.name === '(program)') continue; const stack = entry.stack; const location = getLocation(node, sourceMapper); stack.unshift(location.id as number); @@ -262,6 +262,75 @@ function computeTotalHitCount(root: TimeProfileNode): number { ); } +/** Perform some modifications on time profile: + * - Add non-JS thread activity node if available + * - Remove `(idle)` and `(program)` nodes + * - Convert `(garbage collector)` node to `Garbage Collection` + * - Put `non-JS thread activity` node and `Garbage Collection` under a top level `Node.js` node + * This function does not change the input profile. + */ +function updateTimeProfile(prof: TimeProfile): TimeProfile { + const newTopLevelChildren: TimeProfileNode[] = []; + + let runtimeNode: TimeProfileNode | undefined; + + function getRuntimeNode(): TimeProfileNode { + if (!runtimeNode) { + runtimeNode = { + name: 'Node.js', + scriptName: '', + scriptId: 0, + lineNumber: 0, + columnNumber: 0, + children: [], + hitCount: 0, + }; + newTopLevelChildren.push(runtimeNode); + } + return runtimeNode; + } + + for (const child of prof.topDownRoot.children as TimeProfileNode[]) { + if (child.name === '(idle)' || child.name === '(program)') { + continue; + } + if (child.name === '(garbage collector)') { + // Create a new node to avoid modifying the input one + const newChild: TimeProfileNode = { + ...child, + name: GARBAGE_COLLECTION_FUNCTION_NAME, + }; + getRuntimeNode().children.push(newChild); + } else { + newTopLevelChildren.push(child); + } + } + + if (prof.hasCpuTime && prof.nonJSThreadsCpuTime) { + const node: TimeProfileNode = { + name: NON_JS_THREADS_FUNCTION_NAME, + scriptName: '', + scriptId: 0, + lineNumber: 0, + columnNumber: 0, + children: [], + hitCount: 0, // 0 because this should not be accounted for wall time + contexts: [ + { + context: {}, + timestamp: BigInt(0), + cpuTime: prof.nonJSThreadsCpuTime, + }, + ], + }; + getRuntimeNode().children.push(node); + } + return { + ...prof, + topDownRoot: {...prof.topDownRoot, children: newTopLevelChildren}, + }; +} + /** * Converts v8 time profile into into a profile proto. * (https://github.com/google/pprof/blob/master/proto/profile.proto) @@ -360,28 +429,11 @@ export function serializeTimeProfile( period: intervalNanos, }; - if (prof.hasCpuTime && prof.nonJSThreadsCpuTime) { - const node: TimeProfileNode = { - name: NON_JS_THREADS_FUNCTION_NAME, - scriptName: '', - scriptId: 0, - lineNumber: 0, - columnNumber: 0, - children: [], - hitCount: 0, // 0 because this should not be accounted for wall time - contexts: [ - { - context: {}, - timestamp: BigInt(0), - cpuTime: prof.nonJSThreadsCpuTime, - }, - ], - }; - prof.topDownRoot.children.push(node); - } + const updatedProf = updateTimeProfile(prof); + serialize( profile, - prof.topDownRoot, + updatedProf.topDownRoot, appendTimeEntryToSamples, stringTable, undefined, diff --git a/ts/src/time-profiler.ts b/ts/src/time-profiler.ts index 6aa242a4..5d1defd1 100644 --- a/ts/src/time-profiler.ts +++ b/ts/src/time-profiler.ts @@ -18,6 +18,7 @@ import delay from 'delay'; import { serializeTimeProfile, + GARBAGE_COLLECTION_FUNCTION_NAME, NON_JS_THREADS_FUNCTION_NAME, } from './profile-serializer'; import {SourceMapper} from './sourcemapper/sourcemapper'; @@ -171,5 +172,9 @@ export function v8ProfilerStuckEventLoopDetected() { return gV8ProfilerStuckEventLoopDetected; } -export const constants = {kSampleCount, NON_JS_THREADS_FUNCTION_NAME}; +export const constants = { + kSampleCount, + GARBAGE_COLLECTION_FUNCTION_NAME, + NON_JS_THREADS_FUNCTION_NAME, +}; export {getNativeThreadId}; diff --git a/ts/test/profiles-for-tests.ts b/ts/test/profiles-for-tests.ts index cb978614..cdb10f81 100644 --- a/ts/test/profiles-for-tests.ts +++ b/ts/test/profiles-for-tests.ts @@ -84,7 +84,7 @@ const timeNode2 = { children: [timeLeaf3], }; -const timeRoot = { +const timeRoot = Object.freeze({ name: '(root)', scriptName: 'root', scriptId: 0, @@ -92,7 +92,7 @@ const timeRoot = { columnNumber: 0, hitCount: 0, children: [timeNode1, timeNode2], -}; +}); export const v8TimeProfile: TimeProfile = Object.freeze({ startTime: 0, From c7f4a35c1feacc3709a4489bf41fc5586c7276be Mon Sep 17 00:00:00 2001 From: Nicolas Savoire Date: Fri, 23 Feb 2024 14:17:04 +0100 Subject: [PATCH 2/2] Fix typo --- ts/test/test-profile-serializer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/test/test-profile-serializer.ts b/ts/test/test-profile-serializer.ts index 9673198a..c93619e2 100644 --- a/ts/test/test-profile-serializer.ts +++ b/ts/test/test-profile-serializer.ts @@ -192,7 +192,7 @@ describe('profile-serializer', () => { const heapProfileOut = serializeHeapProfile(v8HeapProfile, 0, 512 * 1024); assert.deepEqual(heapProfileOut, heapProfile); }); - it('should produce expected profile when there is anyonmous function', () => { + it('should produce expected profile when there is anonymous function', () => { const heapProfileOut = serializeHeapProfile( v8AnonymousFunctionHeapProfile, 0,