Skip to content

Commit d5ffbed

Browse files
authored
[PROF-9187] Rename special frames (#160)
* 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
1 parent 391b56d commit d5ffbed

File tree

4 files changed

+83
-26
lines changed

4 files changed

+83
-26
lines changed

ts/src/profile-serializer.ts

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ import {
4040
TimeProfileNode,
4141
} from './v8-types';
4242

43-
export const NON_JS_THREADS_FUNCTION_NAME = '(non-JS threads)';
43+
export const NON_JS_THREADS_FUNCTION_NAME = 'Non JS threads activity';
44+
export const GARBAGE_COLLECTION_FUNCTION_NAME = 'Garbage Collection';
4445

4546
/**
4647
* A stack of function IDs.
@@ -110,7 +111,6 @@ function serialize<T extends ProfileNode>(
110111
if (ignoreSamplesPath && node.scriptName.indexOf(ignoreSamplesPath) > -1) {
111112
continue;
112113
}
113-
if (node.name === '(idle)' || node.name === '(program)') continue;
114114
const stack = entry.stack;
115115
const location = getLocation(node, sourceMapper);
116116
stack.unshift(location.id as number);
@@ -262,6 +262,75 @@ function computeTotalHitCount(root: TimeProfileNode): number {
262262
);
263263
}
264264

265+
/** Perform some modifications on time profile:
266+
* - Add non-JS thread activity node if available
267+
* - Remove `(idle)` and `(program)` nodes
268+
* - Convert `(garbage collector)` node to `Garbage Collection`
269+
* - Put `non-JS thread activity` node and `Garbage Collection` under a top level `Node.js` node
270+
* This function does not change the input profile.
271+
*/
272+
function updateTimeProfile(prof: TimeProfile): TimeProfile {
273+
const newTopLevelChildren: TimeProfileNode[] = [];
274+
275+
let runtimeNode: TimeProfileNode | undefined;
276+
277+
function getRuntimeNode(): TimeProfileNode {
278+
if (!runtimeNode) {
279+
runtimeNode = {
280+
name: 'Node.js',
281+
scriptName: '',
282+
scriptId: 0,
283+
lineNumber: 0,
284+
columnNumber: 0,
285+
children: [],
286+
hitCount: 0,
287+
};
288+
newTopLevelChildren.push(runtimeNode);
289+
}
290+
return runtimeNode;
291+
}
292+
293+
for (const child of prof.topDownRoot.children as TimeProfileNode[]) {
294+
if (child.name === '(idle)' || child.name === '(program)') {
295+
continue;
296+
}
297+
if (child.name === '(garbage collector)') {
298+
// Create a new node to avoid modifying the input one
299+
const newChild: TimeProfileNode = {
300+
...child,
301+
name: GARBAGE_COLLECTION_FUNCTION_NAME,
302+
};
303+
getRuntimeNode().children.push(newChild);
304+
} else {
305+
newTopLevelChildren.push(child);
306+
}
307+
}
308+
309+
if (prof.hasCpuTime && prof.nonJSThreadsCpuTime) {
310+
const node: TimeProfileNode = {
311+
name: NON_JS_THREADS_FUNCTION_NAME,
312+
scriptName: '',
313+
scriptId: 0,
314+
lineNumber: 0,
315+
columnNumber: 0,
316+
children: [],
317+
hitCount: 0, // 0 because this should not be accounted for wall time
318+
contexts: [
319+
{
320+
context: {},
321+
timestamp: BigInt(0),
322+
cpuTime: prof.nonJSThreadsCpuTime,
323+
},
324+
],
325+
};
326+
getRuntimeNode().children.push(node);
327+
}
328+
return {
329+
...prof,
330+
topDownRoot: {...prof.topDownRoot, children: newTopLevelChildren},
331+
};
332+
}
333+
265334
/**
266335
* Converts v8 time profile into into a profile proto.
267336
* (https://github.com/google/pprof/blob/master/proto/profile.proto)
@@ -360,28 +429,11 @@ export function serializeTimeProfile(
360429
period: intervalNanos,
361430
};
362431

363-
if (prof.hasCpuTime && prof.nonJSThreadsCpuTime) {
364-
const node: TimeProfileNode = {
365-
name: NON_JS_THREADS_FUNCTION_NAME,
366-
scriptName: '',
367-
scriptId: 0,
368-
lineNumber: 0,
369-
columnNumber: 0,
370-
children: [],
371-
hitCount: 0, // 0 because this should not be accounted for wall time
372-
contexts: [
373-
{
374-
context: {},
375-
timestamp: BigInt(0),
376-
cpuTime: prof.nonJSThreadsCpuTime,
377-
},
378-
],
379-
};
380-
prof.topDownRoot.children.push(node);
381-
}
432+
const updatedProf = updateTimeProfile(prof);
433+
382434
serialize(
383435
profile,
384-
prof.topDownRoot,
436+
updatedProf.topDownRoot,
385437
appendTimeEntryToSamples,
386438
stringTable,
387439
undefined,

ts/src/time-profiler.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import delay from 'delay';
1818

1919
import {
2020
serializeTimeProfile,
21+
GARBAGE_COLLECTION_FUNCTION_NAME,
2122
NON_JS_THREADS_FUNCTION_NAME,
2223
} from './profile-serializer';
2324
import {SourceMapper} from './sourcemapper/sourcemapper';
@@ -171,5 +172,9 @@ export function v8ProfilerStuckEventLoopDetected() {
171172
return gV8ProfilerStuckEventLoopDetected;
172173
}
173174

174-
export const constants = {kSampleCount, NON_JS_THREADS_FUNCTION_NAME};
175+
export const constants = {
176+
kSampleCount,
177+
GARBAGE_COLLECTION_FUNCTION_NAME,
178+
NON_JS_THREADS_FUNCTION_NAME,
179+
};
175180
export {getNativeThreadId};

ts/test/profiles-for-tests.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ const timeNode2 = {
8484
children: [timeLeaf3],
8585
};
8686

87-
const timeRoot = {
87+
const timeRoot = Object.freeze({
8888
name: '(root)',
8989
scriptName: 'root',
9090
scriptId: 0,
9191
lineNumber: 0,
9292
columnNumber: 0,
9393
hitCount: 0,
9494
children: [timeNode1, timeNode2],
95-
};
95+
});
9696

9797
export const v8TimeProfile: TimeProfile = Object.freeze({
9898
startTime: 0,

ts/test/test-profile-serializer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ describe('profile-serializer', () => {
192192
const heapProfileOut = serializeHeapProfile(v8HeapProfile, 0, 512 * 1024);
193193
assert.deepEqual(heapProfileOut, heapProfile);
194194
});
195-
it('should produce expected profile when there is anyonmous function', () => {
195+
it('should produce expected profile when there is anonymous function', () => {
196196
const heapProfileOut = serializeHeapProfile(
197197
v8AnonymousFunctionHeapProfile,
198198
0,

0 commit comments

Comments
 (0)