Skip to content

Commit f7def75

Browse files
and-oliDevtools-frontend LUCI CQ
authored andcommitted
[RPP] Update sample trace id parsing
As of https://crrev.com/c/6397026 the shape of trace id in CPU profile changed to a traceid -> node id mapping (before it was sample index -> traceid). This allows us to simplify their parsing as they are we no longer need to get the stack data (node id) via the sample index, effectively removing a level of indirection and preventing bugs due to the samples order being altered in the frontend (see attached bug). Fixed: 403628855 Change-Id: I1d56ce8aa6414798a95a20b5dbcd9ecb871043f7 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6394268 Reviewed-by: Paul Irish <[email protected]> Commit-Queue: Andres Olivares <[email protected]>
1 parent a175b3f commit f7def75

File tree

3 files changed

+28
-22
lines changed

3 files changed

+28
-22
lines changed

front_end/models/cpu_profile/CPUProfileDataModel.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,5 +557,13 @@ export type ExtendedProfileNode = Protocol.Profiler.ProfileNode&{parent?: number
557557
export type ExtendedProfile = Protocol.Profiler.Profile&{
558558
nodes: Protocol.Profiler.ProfileNode[] | ExtendedProfileNode[],
559559
lines?: number[],
560+
/**
561+
* A sample can be manually collected with v8::CpuProfiler::collectSample.
562+
* When this is done an id (trace id) can be passed to the API to
563+
* identify the collected sample in the resulting CPU profile. We
564+
* do this for several trace events, to efficiently calculate their
565+
* stack trace and improve the JS flamechart we build. This property
566+
* contains the mapping of the trace ids with the shape traceId -> nodeId
567+
*/
560568
traceIds?: Record<string, number>,
561569
};

front_end/models/trace/helpers/SamplesIntegrator.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ describeWithEnvironment('SamplesIntegrator', function() {
243243
{id: 5, callFrame: {functionName: 'sheep', scriptId, url, lineNumber, columnNumber}},
244244
],
245245
samples: [3, 3, 3, 5],
246-
traceIds: {3: traceId},
246+
traceIds: {[traceId]: 5},
247247
timeDeltas: new Array(4).fill(100),
248248
};
249249

front_end/models/trace/helpers/SamplesIntegrator.ts

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,6 @@ export class SamplesIntegrator {
7070
* in the stack before the event came.
7171
*/
7272
#lockedJsStackDepth: number[] = [];
73-
/**
74-
* For samples with a trace id, creates a profile call and keeps it
75-
* in a record keyed by that id. The value is typed as an union with
76-
* undefined to avoid nullish accesses when a key is not present.
77-
*/
78-
#callsByTraceIds: Record<number, Types.Events.SyntheticProfileCall|undefined> = {};
7973
/**
8074
* Used to keep track when samples should be integrated even if they
8175
* are not children of invocation trace events. This is useful in
@@ -237,7 +231,6 @@ export class SamplesIntegrator {
237231
callsFromProfileSamples(): Types.Events.SyntheticProfileCall[] {
238232
const samples = this.#profileModel.samples;
239233
const timestamps = this.#profileModel.timestamps;
240-
const debugModeEnabled = this.#engineConfig.debugMode;
241234
if (!samples) {
242235
return [];
243236
}
@@ -249,16 +242,10 @@ export class SamplesIntegrator {
249242
if (!node) {
250243
continue;
251244
}
252-
const maybeTraceId = this.#profileModel.traceIds?.[i];
253245
const call = makeProfileCall(node, this.#profileId, i, timestamp, this.#processId, this.#threadId);
254-
// Separate samples with trace ids so that they are only used when
255-
// processing the owner event.
256-
if (maybeTraceId === undefined) {
257-
calls.push(call);
258-
} else {
259-
this.#callsByTraceIds[maybeTraceId] = call;
260-
}
261-
if (debugModeEnabled) {
246+
calls.push(call);
247+
248+
if (this.#engineConfig.debugMode) {
262249
const traceId = this.#profileModel.traceIds?.[i];
263250
this.jsSampleEvents.push(this.#makeJSSampleEvent(call, timestamp, traceId));
264251
}
@@ -322,6 +309,19 @@ export class SamplesIntegrator {
322309
return callFrames;
323310
}
324311

312+
#getStackForSampleTraceId(traceId: number, timestamp: Types.Timing.Micro): Types.Events.SyntheticProfileCall[]|null {
313+
const nodeId = this.#profileModel.traceIds?.[traceId];
314+
const node = nodeId && this.#profileModel.nodeById(nodeId);
315+
const maybeCallForTraceId =
316+
node && makeProfileCall(node, this.#profileId, -1, timestamp, this.#processId, this.#threadId);
317+
if (!maybeCallForTraceId) {
318+
return null;
319+
}
320+
if (this.#engineConfig.debugMode) {
321+
this.jsSampleEvents.push(this.#makeJSSampleEvent(maybeCallForTraceId, timestamp, traceId));
322+
}
323+
return this.#makeProfileCallsForStack(maybeCallForTraceId);
324+
}
325325
/**
326326
* Update tracked stack using this event's call stack.
327327
*/
@@ -331,11 +331,9 @@ export class SamplesIntegrator {
331331
stackTrace = this.#makeProfileCallsForStack(event);
332332
}
333333
const traceId = extractSampleTraceId(event);
334-
if (traceId !== null) {
335-
const maybeCallForTraceId = this.#callsByTraceIds[traceId];
336-
if (maybeCallForTraceId) {
337-
stackTrace = this.#makeProfileCallsForStack(maybeCallForTraceId, event.ts);
338-
}
334+
const maybeCallForTraceId = traceId && this.#getStackForSampleTraceId(traceId, event.ts);
335+
if (maybeCallForTraceId) {
336+
stackTrace = maybeCallForTraceId;
339337
}
340338

341339
SamplesIntegrator.filterStackFrames(stackTrace, this.#engineConfig);

0 commit comments

Comments
 (0)