Skip to content

Commit f4cee17

Browse files
and-oliDevtools-frontend LUCI CQ
authored andcommitted
[Perf] Parse UserTiming::Measure event
The event was added recently [1] and allows us to keep track of the call to performance.measure, since the event we were dispatching (and parsing) has it's timestamp and duration overriden to match the values of the timing measured with the performance.measure API. The event can be connected to its corresponding performance measure event with a common traceId. [1] https://chromium-review.googlesource.com/c/chromium/src/+/6187334 Bug: 395845218 Change-Id: Ie5324100d32928edd1962eb309f730740796a509 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6252783 Reviewed-by: Nancy Li <[email protected]> Auto-Submit: Andres Olivares <[email protected]> Commit-Queue: Andres Olivares <[email protected]> Commit-Queue: Nancy Li <[email protected]>
1 parent 789ff02 commit f4cee17

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

front_end/models/trace/handlers/UserTimingsHandler.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
// found in the LICENSE file.
44

55
import {describeWithEnvironment} from '../../../testing/EnvironmentHelpers.js';
6+
import {
7+
makeCompleteEvent,
8+
} from '../../../testing/TraceHelpers.js';
69
import {TraceLoader} from '../../../testing/TraceLoader.js';
710
import * as Trace from '../trace.js';
811

@@ -180,4 +183,17 @@ describeWithEnvironment('UserTimingsHandler', function() {
180183
});
181184
});
182185
});
186+
187+
describe('UserTiming::Measure events parsing', function() {
188+
it('stores user timing events by trace id', async function() {
189+
const userTimingMeasure = makeCompleteEvent(Trace.Types.Events.Name.USER_TIMING_MEASURE, 0, 100, 'cat', 0, 0) as
190+
Trace.Types.Events.UserTimingMeasure;
191+
userTimingMeasure.args.traceId = 1;
192+
Trace.Handlers.ModelHandlers.UserTimings.handleEvent(userTimingMeasure);
193+
await Trace.Handlers.ModelHandlers.UserTimings.finalize();
194+
const data = Trace.Handlers.ModelHandlers.UserTimings.data();
195+
assert.lengthOf(data.measureTraceByTraceId, 1);
196+
assert.deepEqual([...data.measureTraceByTraceId.entries()][0], [1, userTimingMeasure]);
197+
});
198+
});
183199
});

front_end/models/trace/handlers/UserTimingsHandler.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ import * as Types from '../types/types.js';
1111
* UserTimings and the trace events we parse currently.
1212
**/
1313
let syntheticEvents: Types.Events.SyntheticEventPair<Types.Events.PairableAsync>[] = [];
14+
15+
// There are two events dispatched for performance.measure calls: one to
16+
// represent the measured timing in the tracing clock (which we type as
17+
// PerformanceMeasure) and another one for the call itself (which we
18+
// type as UserTimingMeasure). The two events corresponding to the same
19+
// call are linked together by a common trace_id. The reason two events
20+
// are dispatched is because the first was originally added with the
21+
// implementation of the performance.measure API and it uses an
22+
// overridden timestamp and duration. To prevent breaking potential deps
23+
// created since then, a second event was added instead of changing the
24+
// params of the first.
25+
const measureTraceByTraceId: Map<number, Types.Events.UserTimingMeasure> = new Map();
1426
const performanceMeasureEvents: Types.Events.PerformanceMeasure[] = [];
1527
const performanceMarkEvents: Types.Events.PerformanceMark[] = [];
1628

@@ -40,6 +52,11 @@ export interface UserTimingsData {
4052
* https://developer.mozilla.org/en-US/docs/Web/API/console/timeStamp
4153
*/
4254
timestampEvents: readonly Types.Events.ConsoleTimeStamp[];
55+
/**
56+
* Events triggered to trace the call to performance.measure itself,
57+
* cached by trace_id.
58+
*/
59+
measureTraceByTraceId: Map<number, Types.Events.UserTimingMeasure>;
4360
}
4461

4562
export function reset(): void {
@@ -48,6 +65,7 @@ export function reset(): void {
4865
performanceMarkEvents.length = 0;
4966
consoleTimings.length = 0;
5067
timestampEvents.length = 0;
68+
measureTraceByTraceId.clear();
5169
}
5270

5371
const resourceTimingNames = [
@@ -142,7 +160,9 @@ export function handleEvent(event: Types.Events.Event): void {
142160
if (ignoredNames.includes(event.name)) {
143161
return;
144162
}
145-
163+
if (Types.Events.isUserTimingMeasure(event)) {
164+
measureTraceByTraceId.set(event.args.traceId, event);
165+
}
146166
if (Types.Events.isPerformanceMeasure(event)) {
147167
performanceMeasureEvents.push(event);
148168
return;
@@ -172,5 +192,6 @@ export function data(): UserTimingsData {
172192
// TODO(crbug/41484172): UserTimingsHandler.test.ts fails if this is not copied.
173193
performanceMarks: [...performanceMarkEvents],
174194
timestampEvents: [...timestampEvents],
195+
measureTraceByTraceId: new Map(measureTraceByTraceId),
175196
};
176197
}

front_end/models/trace/types/TraceEvents.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,7 @@ export interface PerformanceMeasureBegin extends PairableUserTiming {
13871387
detail?: string,
13881388
stackTrace?: CallFrame[],
13891389
callTime?: Micro,
1390+
traceId?: number,
13901391
};
13911392
ph: Phase.ASYNC_NESTABLE_START;
13921393
}
@@ -1439,6 +1440,16 @@ export interface SyntheticConsoleTimeStamp extends Event, SyntheticBased {
14391440
ph: Phase.COMPLETE;
14401441
}
14411442

1443+
export interface UserTimingMeasure extends Event {
1444+
cat: 'devtools.timeline';
1445+
ph: Phase.COMPLETE;
1446+
name: Name.USER_TIMING_MEASURE;
1447+
args: Args&{
1448+
sampleTraceId: number,
1449+
traceId: number,
1450+
};
1451+
}
1452+
14421453
/** ChromeFrameReporter args for PipelineReporter event.
14431454
Matching proto: https://source.chromium.org/chromium/chromium/src/+/main:third_party/perfetto/protos/perfetto/trace/track_event/chrome_frame_reporter.proto
14441455
*/
@@ -2284,6 +2295,10 @@ export function isConsoleTimeStamp(event: Event): event is ConsoleTimeStamp {
22842295
return event.ph === Phase.COMPLETE && event.name === Name.CONSOLE_TIME_STAMP;
22852296
}
22862297

2298+
export function isUserTimingMeasure(event: Event): event is UserTimingMeasure {
2299+
return event.name === Name.USER_TIMING_MEASURE;
2300+
}
2301+
22872302
export function isParseHTML(event: Event): event is ParseHTML {
22882303
return event.name === 'ParseHTML';
22892304
}
@@ -2998,7 +3013,8 @@ export const enum Name {
29983013
ANIMATION_FRAME = 'AnimationFrame',
29993014
ANIMATION_FRAME_PRESENTATION = 'AnimationFrame::Presentation',
30003015

3001-
SYNTHETIC_NETWORK_REQUEST = 'SyntheticNetworkRequest'
3016+
SYNTHETIC_NETWORK_REQUEST = 'SyntheticNetworkRequest',
3017+
USER_TIMING_MEASURE = 'UserTiming::Measure',
30023018
}
30033019

30043020
// NOT AN EXHAUSTIVE LIST: just some categories we use and refer

front_end/testing/TraceHelpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ export function getBaseTraceParseModelData(overrides: Partial<ParsedTrace> = {})
690690
performanceMarks: [],
691691
performanceMeasures: [],
692692
timestampEvents: [],
693+
measureTraceByTraceId: new Map(),
693694
},
694695
LargestImagePaint: {lcpRequestByNavigation: new Map()},
695696
LargestTextPaint: new Map(),

0 commit comments

Comments
 (0)