Skip to content

Commit 0601048

Browse files
finnurbrekiDevtools-frontend LUCI CQ
authored andcommitted
Consolidate two UserTimingsHandler sorting functions into one.
BUG: 428939519 Change-Id: Ie72e2697b0aa30fffebe8011e2cf472c63396bcf Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6895484 Reviewed-by: Andres Olivares <andoli@chromium.org> Commit-Queue: Finnur Thorarinsson <finnur@chromium.org>
1 parent 2d61a31 commit 0601048

File tree

2 files changed

+115
-85
lines changed

2 files changed

+115
-85
lines changed

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

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ describeWithEnvironment('UserTimingsHandler', function() {
339339
});
340340
});
341341

342-
describe('sorting functions', () => {
342+
describe('sorting function userTimingComparator', () => {
343343
function makeFakeSyntheticEvent(
344344
ts: number, dur: number, name: string, track: string): Trace.Types.Events.SyntheticEventPair {
345345
const beginEvent = makeCompleteEvent(name, ts, dur, 'blink.user_timing', 0, 0) as unknown as
@@ -364,11 +364,31 @@ describeWithEnvironment('UserTimingsHandler', function() {
364364
return syntheticEvent;
365365
}
366366

367-
function sortAll(events: Trace.Types.Events.SyntheticEventPair[]) {
367+
function makeFakeConsoleTimestampEvent(
368+
start: number, end: number, name: string, track: string): Trace.Types.Events.ConsoleTimeStamp {
369+
return {
370+
cat: 'devtools.timeline',
371+
pid: Trace.Types.Events.ProcessID(2017),
372+
tid: Trace.Types.Events.ThreadID(259),
373+
name: Trace.Types.Events.Name.TIME_STAMP,
374+
args: {
375+
data: {
376+
message: name,
377+
start,
378+
end,
379+
track,
380+
},
381+
},
382+
ts: Trace.Types.Timing.Micro(start),
383+
ph: Trace.Types.Events.Phase.INSTANT,
384+
};
385+
}
386+
387+
function sortAll(events: Array<Trace.Types.Events.SyntheticEventPair|Trace.Types.Events.ConsoleTimeStamp>) {
368388
events.sort((a, b) => Trace.Handlers.ModelHandlers.UserTimings.userTimingComparator(a, b, [...events]));
369389
}
370390

371-
it('userTimingComparator sorts by start time in ASC order', () => {
391+
it('sorts synthetic events by start time in ASC order', () => {
372392
const event1 = makeFakeSyntheticEvent(1, 1, 'E1', 'Track A');
373393
const event2 = makeFakeSyntheticEvent(2, 1, 'E2', 'Track A');
374394
const event3 = makeFakeSyntheticEvent(3, 1, 'E3', 'Track A');
@@ -378,7 +398,7 @@ describeWithEnvironment('UserTimingsHandler', function() {
378398
assert.deepEqual(events, [event1, event2, event3]);
379399
});
380400

381-
it('userTimingComparator sorts by longest duration if start is the same for all', () => {
401+
it('sorts synthetic events by longest duration if start is the same for all', () => {
382402
const event1 = makeFakeSyntheticEvent(1, 1, 'E1', 'Track A');
383403
const event2 = makeFakeSyntheticEvent(1, 2, 'E2', 'Track A');
384404
const event3 = makeFakeSyntheticEvent(1, 3, 'E3', 'Track A');
@@ -388,7 +408,7 @@ describeWithEnvironment('UserTimingsHandler', function() {
388408
assert.deepEqual(events, [event3, event2, event1]);
389409
});
390410

391-
it('userTimingComparator flips if the timestamps are the same', () => {
411+
it('flips synthetic events if the timestamps are the same', () => {
392412
const event1 = makeFakeSyntheticEvent(1, 2, 'E1', 'Track A');
393413
const event2 = makeFakeSyntheticEvent(1, 2, 'E2', 'Track A');
394414
const event3 = makeFakeSyntheticEvent(2, 4, 'E3', 'Track B');
@@ -399,7 +419,7 @@ describeWithEnvironment('UserTimingsHandler', function() {
399419
assert.deepEqual(events, [event2, event1, event4, event3]);
400420
});
401421

402-
it('userTimingComparator wont flip across tracks', () => {
422+
it('wont flip synthetic events across tracks', () => {
403423
const event1 = makeFakeSyntheticEvent(1, 2, 'E1', 'Track A');
404424
const event2 = makeFakeSyntheticEvent(1, 2, 'E2', 'Track B');
405425
const event3 = makeFakeSyntheticEvent(1, 2, 'E3', 'Track C');
@@ -410,7 +430,7 @@ describeWithEnvironment('UserTimingsHandler', function() {
410430
assert.deepEqual(events, [event1, event2, event3, event4]);
411431
});
412432

413-
it('userTimingComparator three identical measure events', () => {
433+
it('sorts three identical synthetic events correctly', () => {
414434
const event1 = makeFakeSyntheticEvent(1, 2, 'E1', 'Track A');
415435
const event2 = makeFakeSyntheticEvent(1, 2, 'E2', 'Track A');
416436
const event3 = makeFakeSyntheticEvent(1, 2, 'E3', 'Track A');
@@ -420,77 +440,86 @@ describeWithEnvironment('UserTimingsHandler', function() {
420440
assert.deepEqual(events, [event3, event2, event1]);
421441
});
422442

423-
function makeFakeConsoleTimestampEvent(
424-
start: number, end: number, name: string, track: string): Trace.Types.Events.ConsoleTimeStamp {
425-
return {
426-
cat: 'devtools.timeline',
427-
pid: Trace.Types.Events.ProcessID(2017),
428-
tid: Trace.Types.Events.ThreadID(259),
429-
name: Trace.Types.Events.Name.TIME_STAMP,
430-
args: {
431-
data: {
432-
message: name,
433-
start,
434-
end,
435-
track,
436-
},
437-
},
438-
ts: Trace.Types.Timing.Micro(start),
439-
ph: Trace.Types.Events.Phase.INSTANT,
440-
};
441-
}
442-
443-
function sortAllConsoleTimestamps(events: Trace.Types.Events.ConsoleTimeStamp[]) {
444-
events.sort((a, b) => Trace.Handlers.ModelHandlers.UserTimings.consoleTimestampComparator(a, b, [...events]));
445-
}
446-
447-
it('consoleTimestampComparator sorts by start time in ASC order', () => {
443+
it('sorts console timestamps by start time in ASC order', () => {
448444
const event1 = makeFakeConsoleTimestampEvent(1, 1, 'E1', 'Track A');
449445
const event2 = makeFakeConsoleTimestampEvent(2, 1, 'E2', 'Track A');
450446
const event3 = makeFakeConsoleTimestampEvent(3, 1, 'E3', 'Track A');
451447
const events = [event3, event1, event2];
452-
sortAllConsoleTimestamps(events);
448+
449+
sortAll(events);
453450
assert.deepEqual(events, [event1, event2, event3]);
454451
});
455452

456-
it('consoleTimestampComparator sorts by longest duration if start is the same for all', () => {
453+
it('sorts console timestamps by longest duration if start is the same for all', () => {
457454
const event1 = makeFakeConsoleTimestampEvent(1, 1, 'E1', 'Track A');
458455
const event2 = makeFakeConsoleTimestampEvent(1, 2, 'E2', 'Track A');
459456
const event3 = makeFakeConsoleTimestampEvent(1, 3, 'E3', 'Track A');
460457
const events = [event1, event2, event3];
461-
sortAllConsoleTimestamps(events);
458+
459+
sortAll(events);
462460
assert.deepEqual(events, [event3, event2, event1]);
463461
});
464462

465-
it('consoleTimestampComparator flips if the timestamps are the same', () => {
463+
it('flips console timestamps if the timestamps are the same', () => {
466464
const event1 = makeFakeConsoleTimestampEvent(1, 3, 'E1', 'Track A');
467465
const event2 = makeFakeConsoleTimestampEvent(1, 3, 'E2', 'Track A');
468466
const event3 = makeFakeConsoleTimestampEvent(2, 6, 'E3', 'Track B');
469467
const event4 = makeFakeConsoleTimestampEvent(2, 6, 'E4', 'Track B');
470468
const events = [event1, event2, event3, event4];
471-
sortAllConsoleTimestamps(events);
469+
470+
sortAll(events);
472471
assert.deepEqual(events, [event2, event1, event4, event3]);
473472
});
474473

475-
it('consoleTimestampComparator wont flip across tracks', () => {
474+
it('wont flip console timestamps across tracks', () => {
476475
const event1 = makeFakeConsoleTimestampEvent(1, 2, 'E1', 'Track A');
477476
const event2 = makeFakeConsoleTimestampEvent(1, 2, 'E2', 'Track B');
478477
const event3 = makeFakeConsoleTimestampEvent(1, 2, 'E3', 'Track C');
479478
const event4 = makeFakeConsoleTimestampEvent(1, 2, 'E4', 'Track D');
480479
const events = [event1, event2, event3, event4];
481480

482-
sortAllConsoleTimestamps(events);
481+
sortAll(events);
483482
assert.deepEqual(events, [event1, event2, event3, event4]);
484483
});
485484

486-
it('consoleTimestampComparator three identical measure events', () => {
485+
it('sorts three identical console timestamp events', () => {
487486
const event1 = makeFakeConsoleTimestampEvent(1, 2, 'E1', 'Track A');
488487
const event2 = makeFakeConsoleTimestampEvent(1, 2, 'E2', 'Track A');
489488
const event3 = makeFakeConsoleTimestampEvent(1, 2, 'E3', 'Track A');
490489
const events = [event1, event2, event3];
491490

492-
sortAllConsoleTimestamps(events);
491+
sortAll(events);
493492
assert.deepEqual(events, [event3, event2, event1]);
494493
});
494+
495+
// Mixed synthetic events and console timestamps.
496+
497+
it('sorts mixed events by start time in ASC order', () => {
498+
const event1a = makeFakeSyntheticEvent(1, 1, 'E1a', 'Track A');
499+
const event1b = makeFakeConsoleTimestampEvent(1, 1, 'E1b', 'Track A');
500+
const event2a = makeFakeSyntheticEvent(2, 1, 'E2a', 'Track A');
501+
const event2b = makeFakeConsoleTimestampEvent(2, 1, 'E2b', 'Track A');
502+
const event3a = makeFakeSyntheticEvent(3, 1, 'E3a', 'Track A');
503+
const event3b = makeFakeConsoleTimestampEvent(3, 1, 'E3b', 'Track A');
504+
const events = [event3b, event3a, event1b, event1a, event2b, event2a];
505+
506+
sortAll(events);
507+
assert.deepEqual(events, [event1a, event1b, event2a, event2b, event3a, event3b]);
508+
});
509+
510+
it('wont flip mixed events across tracks', () => {
511+
const event1a = makeFakeSyntheticEvent(1, 2, 'E1a', 'Track A');
512+
const event2a = makeFakeSyntheticEvent(1, 2, 'E2a', 'Track B');
513+
const event3a = makeFakeSyntheticEvent(1, 2, 'E3a', 'Track C');
514+
const event4a = makeFakeSyntheticEvent(1, 2, 'E4a', 'Track D');
515+
const event1b = makeFakeConsoleTimestampEvent(1, 2, 'E1b', 'Track E');
516+
const event2b = makeFakeConsoleTimestampEvent(1, 2, 'E2b', 'Track F');
517+
const event3b = makeFakeConsoleTimestampEvent(1, 2, 'E3b', 'Track G');
518+
const event4b = makeFakeConsoleTimestampEvent(1, 2, 'E4b', 'Track H');
519+
const events = [event1a, event2a, event3a, event4a, event1b, event2b, event3b, event4b];
520+
521+
sortAll(events);
522+
assert.deepEqual(events, [event1a, event2a, event3a, event4a, event1b, event2b, event3b, event4b]);
523+
});
495524
});
496525
});

front_end/models/trace/handlers/UserTimingsHandler.ts

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,44 @@ const navTimingNames = [
112112
// flame chart).
113113
const ignoredNames = [...resourceTimingNames, ...navTimingNames];
114114

115+
function getEventTimings(event: Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp):
116+
{start: Types.Timing.Micro, end: Types.Timing.Micro} {
117+
if ('dur' in event) {
118+
// It's a SyntheticEventPair.
119+
return {start: event.ts, end: Types.Timing.Micro(event.ts + (event.dur ?? 0))};
120+
}
121+
122+
if (Types.Events.isConsoleTimeStamp(event)) {
123+
const {start, end} = event.args.data || {};
124+
if (typeof start === 'number' && typeof end === 'number') {
125+
return {start: Types.Timing.Micro(start), end: Types.Timing.Micro(end)};
126+
}
127+
}
128+
129+
// A ConsoleTimeStamp without start/end is just a point in time, so dur is 0.
130+
return {start: event.ts, end: event.ts};
131+
}
132+
133+
function getEventTrack(event: Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp): string|undefined {
134+
if (event.cat === 'blink.user_timing') {
135+
// This is a SyntheticUserTimingPair
136+
const detailString =
137+
((event as Types.Events.SyntheticUserTimingPair).args.data.beginEvent.args as {detail?: string})?.detail;
138+
if (detailString) {
139+
const details = Helpers.Trace.parseDevtoolsDetails(detailString, 'devtools');
140+
if (details && 'track' in details) {
141+
return details.track;
142+
}
143+
}
144+
} else if (Types.Events.isConsoleTimeStamp(event)) {
145+
const track = event.args.data?.track;
146+
return typeof track === 'string' ? track : undefined;
147+
}
148+
149+
// SyntheticConsoleTimingPair does not have track info.
150+
return undefined;
151+
}
152+
115153
/**
116154
* Similar to the default {@see Helpers.Trace.eventTimeComparator}
117155
* but with a twist:
@@ -132,55 +170,18 @@ const ignoredNames = [...resourceTimingNames, ...navTimingNames];
132170
* the second event is the parent of the first. Hence the switch.
133171
*
134172
*/
135-
export function userTimingComparator(
136-
a: Types.Events.SyntheticEventPair, b: Types.Events.SyntheticEventPair,
137-
originalArray: readonly Types.Events.SyntheticEventPair[]): number {
138-
const aStart = a.ts;
139-
const bStart = b.ts;
140-
const aEnd = aStart + (a.dur ?? 0);
141-
const bEnd = bStart + (b.dur ?? 0);
142-
const timeDifference = Helpers.Trace.compareBeginAndEnd(aStart, bStart, aEnd, bEnd);
143-
if (timeDifference) {
144-
return timeDifference;
145-
}
146-
147-
// Never re-order entries across different tracks.
148-
const aDetailString = (a.args.data.beginEvent.args as {detail?: string})?.detail;
149-
const bDetailString = (b.args.data.beginEvent.args as {detail?: string})?.detail;
150-
const aDetails = aDetailString ? Helpers.Trace.parseDevtoolsDetails(aDetailString, 'devtools') : null;
151-
const bDetails = bDetailString ? Helpers.Trace.parseDevtoolsDetails(bDetailString, 'devtools') : null;
152-
const aTrack = aDetails && 'track' in aDetails ? aDetails.track : undefined;
153-
const bTrack = bDetails && 'track' in bDetails ? bDetails.track : undefined;
154-
if (aTrack !== bTrack) {
155-
return 0; // Preserve current positions.
156-
}
157-
158-
// Prefer the event located in a further position in the original array.
159-
const aIndex = originalArray.indexOf(a);
160-
const bIndex = originalArray.indexOf(b);
161-
return bIndex - aIndex;
162-
}
163-
164-
export function consoleTimestampComparator(
165-
a: Types.Events.ConsoleTimeStamp, b: Types.Events.ConsoleTimeStamp,
166-
originalArray: readonly Types.Events.ConsoleTimeStamp[]): number {
167-
const aStart = a.args.data?.start;
168-
const aEnd = a.args.data?.end;
169-
const bStart = b.args.data?.start;
170-
const bEnd = b.args.data?.end;
171-
if (typeof aStart !== 'number' || typeof aEnd !== 'number' || typeof bStart !== 'number' ||
172-
typeof bEnd !== 'number') {
173-
return 0;
174-
}
175-
173+
export function userTimingComparator<T extends Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp>(
174+
a: T, b: T, originalArray: readonly T[]): number {
175+
const {start: aStart, end: aEnd} = getEventTimings(a);
176+
const {start: bStart, end: bEnd} = getEventTimings(b);
176177
const timeDifference = Helpers.Trace.compareBeginAndEnd(aStart, bStart, aEnd, bEnd);
177178
if (timeDifference) {
178179
return timeDifference;
179180
}
180181

181182
// Never re-order entries across different tracks.
182-
const aTrack = a.args.data?.track;
183-
const bTrack = b.args.data?.track;
183+
const aTrack = getEventTrack(a);
184+
const bTrack = getEventTrack(b);
184185
if (aTrack !== bTrack) {
185186
return 0; // Preserve current positions.
186187
}
@@ -217,7 +218,7 @@ export async function finalize(): Promise<void> {
217218
const asyncEvents = [...performanceMeasureEvents, ...consoleTimings];
218219
syntheticEvents = Helpers.Trace.createMatchedSortedSyntheticEvents(asyncEvents);
219220
syntheticEvents = syntheticEvents.sort((a, b) => userTimingComparator(a, b, [...syntheticEvents]));
220-
timestampEvents = timestampEvents.sort((a, b) => consoleTimestampComparator(a, b, [...timestampEvents]));
221+
timestampEvents = timestampEvents.sort((a, b) => userTimingComparator(a, b, [...timestampEvents]));
221222
}
222223

223224
export function data(): UserTimingsData {

0 commit comments

Comments
 (0)