@paulirish/trace_engine 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/analyze-trace.mjs +24 -16
- package/generated/protocol.d.ts +39 -5
- package/models/cpu_profile/CPUProfileDataModel.d.ts +1 -1
- package/models/cpu_profile/CPUProfileDataModel.js +6 -6
- package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
- package/models/trace/ModelImpl.d.ts +0 -6
- package/models/trace/ModelImpl.js +1 -10
- package/models/trace/ModelImpl.js.map +1 -1
- package/models/trace/Processor.d.ts +0 -1
- package/models/trace/Processor.js +13 -14
- package/models/trace/Processor.js.map +1 -1
- package/models/trace/TracingManager.js.map +1 -1
- package/models/trace/handlers/InvalidationsHandler.js +0 -9
- package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
- package/models/trace/handlers/MetaHandler.js +25 -6
- package/models/trace/handlers/MetaHandler.js.map +1 -1
- package/models/trace/handlers/ModelHandlers.d.ts +1 -0
- package/models/trace/handlers/ModelHandlers.js +1 -0
- package/models/trace/handlers/ModelHandlers.js.map +1 -1
- package/models/trace/handlers/NetworkRequestsHandler.js +8 -7
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
- package/models/trace/handlers/RendererHandler.js +17 -7
- package/models/trace/handlers/RendererHandler.js.map +1 -1
- package/models/trace/handlers/SamplesHandler.d.ts +1 -0
- package/models/trace/handlers/SamplesHandler.js +11 -5
- package/models/trace/handlers/SamplesHandler.js.map +1 -1
- package/models/trace/handlers/SelectorStatsHandler.d.ts +9 -0
- package/models/trace/handlers/SelectorStatsHandler.js +28 -0
- package/models/trace/handlers/SelectorStatsHandler.js.map +1 -0
- package/models/trace/handlers/Threads.js +2 -2
- package/models/trace/handlers/Threads.js.map +1 -1
- package/models/trace/handlers/UserInteractionsHandler.d.ts +2 -0
- package/models/trace/handlers/UserInteractionsHandler.js +7 -0
- package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
- package/models/trace/handlers/WarningsHandler.js +0 -1
- package/models/trace/handlers/WarningsHandler.js.map +1 -1
- package/models/trace/handlers/handlers-tsconfig.json +1 -0
- package/models/trace/helpers/SamplesIntegrator.d.ts +6 -1
- package/models/trace/helpers/SamplesIntegrator.js +36 -8
- package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
- package/models/trace/helpers/Trace.d.ts +88 -6
- package/models/trace/helpers/Trace.js +270 -21
- package/models/trace/helpers/Trace.js.map +1 -1
- package/models/trace/insights/CumulativeLayoutShift.d.ts +29 -0
- package/models/trace/insights/CumulativeLayoutShift.js +81 -0
- package/models/trace/insights/CumulativeLayoutShift.js.map +1 -0
- package/models/trace/insights/InsightRunners.d.ts +2 -0
- package/models/trace/insights/InsightRunners.js +2 -0
- package/models/trace/insights/InsightRunners.js.map +1 -1
- package/models/trace/insights/Viewport.d.ts +5 -0
- package/models/trace/insights/Viewport.js +39 -0
- package/models/trace/insights/Viewport.js.map +1 -0
- package/models/trace/insights/insights-tsconfig.json +2 -0
- package/models/trace/insights/types.d.ts +2 -1
- package/models/trace/insights/types.js +1 -0
- package/models/trace/insights/types.js.map +1 -1
- package/models/trace/types/Configuration.d.ts +16 -28
- package/models/trace/types/Configuration.js +7 -27
- package/models/trace/types/Configuration.js.map +1 -1
- package/models/trace/types/TraceEvents.d.ts +101 -26
- package/models/trace/types/TraceEvents.js +10 -3
- package/models/trace/types/TraceEvents.js.map +1 -1
- package/package.json +1 -1
- package/PAUL.readme.md +0 -5
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
import * as Platform from '../../../core/platform/platform.js';
|
|
5
5
|
import * as Types from '../types/types.js';
|
|
6
|
-
|
|
6
|
+
import { eventTimingsMicroSeconds } from './Timing.js';
|
|
7
|
+
/**
|
|
8
|
+
* Extracts the raw stack trace of known trace events. Most likely than
|
|
9
|
+
* not you want to use `getZeroIndexedStackTraceForEvent`, which returns
|
|
10
|
+
* the stack with zero based numbering. Since some trace events are
|
|
11
|
+
* one based this function can yield unexpected results when used
|
|
12
|
+
* indiscriminately.
|
|
13
|
+
*/
|
|
14
|
+
function stackTraceForEvent(event) {
|
|
7
15
|
if (Types.TraceEvents.isSyntheticInvalidation(event)) {
|
|
8
16
|
return event.stackTrace || null;
|
|
9
17
|
}
|
|
@@ -43,7 +51,7 @@ export function addEventToProcessThread(event, eventsInProcessThread) {
|
|
|
43
51
|
eventsInThread.set(event.tid, events);
|
|
44
52
|
eventsInProcessThread.set(event.pid, eventsInThread);
|
|
45
53
|
}
|
|
46
|
-
function eventTimeComparator(a, b) {
|
|
54
|
+
export function eventTimeComparator(a, b) {
|
|
47
55
|
const aBeginTime = a.ts;
|
|
48
56
|
const bBeginTime = b.ts;
|
|
49
57
|
if (aBeginTime < bBeginTime) {
|
|
@@ -132,7 +140,17 @@ export function activeURLForFrameAtTime(frameId, time, rendererProcessesByFrame)
|
|
|
132
140
|
}
|
|
133
141
|
return null;
|
|
134
142
|
}
|
|
135
|
-
|
|
143
|
+
/**
|
|
144
|
+
* @param node the node attached to the profile call. Here a node represents a function in the call tree.
|
|
145
|
+
* @param profileId the profile ID that the sample came from that backs this call.
|
|
146
|
+
* @param sampleIndex the index of the sample in the given profile that this call was created from
|
|
147
|
+
* @param ts the timestamp of the profile call
|
|
148
|
+
* @param pid the process ID of the profile call
|
|
149
|
+
* @param tid the thread ID of the profile call
|
|
150
|
+
*
|
|
151
|
+
* See `panels/timeline/docs/profile_calls.md` for more context on how these events are created.
|
|
152
|
+
*/
|
|
153
|
+
export function makeProfileCall(node, profileId, sampleIndex, ts, pid, tid) {
|
|
136
154
|
return {
|
|
137
155
|
cat: '',
|
|
138
156
|
name: 'ProfileCall',
|
|
@@ -145,6 +163,8 @@ export function makeProfileCall(node, ts, pid, tid) {
|
|
|
145
163
|
dur: Types.Timing.MicroSeconds(0),
|
|
146
164
|
selfTime: Types.Timing.MicroSeconds(0),
|
|
147
165
|
callFrame: node.callFrame,
|
|
166
|
+
sampleIndex,
|
|
167
|
+
profileId,
|
|
148
168
|
};
|
|
149
169
|
}
|
|
150
170
|
export function makeSyntheticTraceEntry(name, ts, pid, tid) {
|
|
@@ -160,7 +180,14 @@ export function makeSyntheticTraceEntry(name, ts, pid, tid) {
|
|
|
160
180
|
selfTime: Types.Timing.MicroSeconds(0),
|
|
161
181
|
};
|
|
162
182
|
}
|
|
163
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Matches beginning events with TraceEventPairableAsyncEnd and TraceEventPairableAsyncInstant (ASYNC_NESTABLE_INSTANT)
|
|
185
|
+
* if provided, though currently only coming from Animations. Traces may contain multiple instant events so we need to
|
|
186
|
+
* account for that.
|
|
187
|
+
*
|
|
188
|
+
* @returns {Map<string, MatchingPairableAsyncEvents>} Map of the animation's ID to it's matching events.
|
|
189
|
+
*/
|
|
190
|
+
export function matchEvents(unpairedEvents) {
|
|
164
191
|
// map to store begin and end of the event
|
|
165
192
|
const matchedPairs = new Map();
|
|
166
193
|
// looking for start and end
|
|
@@ -173,16 +200,23 @@ export function matchBeginningAndEndEvents(unpairedEvents) {
|
|
|
173
200
|
// Console timings can be dispatched with the same id, so use the
|
|
174
201
|
// event name as well to generate unique ids.
|
|
175
202
|
const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedPairs, syntheticId, () => {
|
|
176
|
-
return { begin: null, end: null };
|
|
203
|
+
return { begin: null, end: null, instant: [] };
|
|
177
204
|
});
|
|
178
205
|
const isStartEvent = event.ph === "b" /* Types.TraceEvents.Phase.ASYNC_NESTABLE_START */;
|
|
179
206
|
const isEndEvent = event.ph === "e" /* Types.TraceEvents.Phase.ASYNC_NESTABLE_END */;
|
|
207
|
+
const isInstantEvent = event.ph === "n" /* Types.TraceEvents.Phase.ASYNC_NESTABLE_INSTANT */;
|
|
180
208
|
if (isStartEvent) {
|
|
181
209
|
otherEventsWithID.begin = event;
|
|
182
210
|
}
|
|
183
211
|
else if (isEndEvent) {
|
|
184
212
|
otherEventsWithID.end = event;
|
|
185
213
|
}
|
|
214
|
+
else if (isInstantEvent) {
|
|
215
|
+
if (!otherEventsWithID.instant) {
|
|
216
|
+
otherEventsWithID.instant = [];
|
|
217
|
+
}
|
|
218
|
+
otherEventsWithID.instant.push(event);
|
|
219
|
+
}
|
|
186
220
|
}
|
|
187
221
|
return matchedPairs;
|
|
188
222
|
}
|
|
@@ -192,36 +226,44 @@ function getSyntheticId(event) {
|
|
|
192
226
|
}
|
|
193
227
|
export function createSortedSyntheticEvents(matchedPairs, syntheticEventCallback) {
|
|
194
228
|
const syntheticEvents = [];
|
|
195
|
-
for (const [id,
|
|
196
|
-
const beginEvent =
|
|
197
|
-
const endEvent =
|
|
198
|
-
|
|
229
|
+
for (const [id, eventsTriplet] of matchedPairs.entries()) {
|
|
230
|
+
const beginEvent = eventsTriplet.begin;
|
|
231
|
+
const endEvent = eventsTriplet.end;
|
|
232
|
+
const instantEvents = eventsTriplet.instant;
|
|
233
|
+
if (!beginEvent || !(endEvent || instantEvents)) {
|
|
199
234
|
// This should never happen, the backend only creates the events once it
|
|
200
|
-
// has them both, so we should never get into this state.
|
|
235
|
+
// has them both (beginEvent & endEvent/instantEvents), so we should never get into this state.
|
|
201
236
|
// If we do, something is very wrong, so let's just drop that problematic event.
|
|
202
237
|
continue;
|
|
203
238
|
}
|
|
204
|
-
const
|
|
239
|
+
const triplet = { beginEvent, endEvent, instantEvents };
|
|
240
|
+
/**
|
|
241
|
+
* When trying to pair events with instant events present, there are times when these
|
|
242
|
+
* ASYNC_NESTABLE_INSTANT ('n') don't have a corresponding ASYNC_NESTABLE_END ('e') event.
|
|
243
|
+
* In these cases, pair without needing the endEvent.
|
|
244
|
+
*/
|
|
205
245
|
function eventsArePairable(data) {
|
|
206
|
-
|
|
207
|
-
|
|
246
|
+
const instantEventsMatch = data.instantEvents ? data.instantEvents.some(e => id === getSyntheticId(e)) : false;
|
|
247
|
+
const endEventMatch = data.endEvent ? id === getSyntheticId(data.endEvent) : false;
|
|
248
|
+
return Boolean(id) && (instantEventsMatch || endEventMatch);
|
|
208
249
|
}
|
|
209
|
-
if (!eventsArePairable(
|
|
250
|
+
if (!eventsArePairable(triplet)) {
|
|
210
251
|
continue;
|
|
211
252
|
}
|
|
253
|
+
const targetEvent = endEvent || beginEvent;
|
|
212
254
|
const event = {
|
|
213
|
-
cat:
|
|
214
|
-
ph:
|
|
215
|
-
pid:
|
|
216
|
-
tid:
|
|
255
|
+
cat: targetEvent.cat,
|
|
256
|
+
ph: targetEvent.ph,
|
|
257
|
+
pid: targetEvent.pid,
|
|
258
|
+
tid: targetEvent.tid,
|
|
217
259
|
id,
|
|
218
260
|
// Both events have the same name, so it doesn't matter which we pick to
|
|
219
261
|
// use as the description
|
|
220
262
|
name: beginEvent.name,
|
|
221
|
-
dur: Types.Timing.MicroSeconds(
|
|
263
|
+
dur: Types.Timing.MicroSeconds(targetEvent.ts - beginEvent.ts),
|
|
222
264
|
ts: beginEvent.ts,
|
|
223
265
|
args: {
|
|
224
|
-
data:
|
|
266
|
+
data: triplet,
|
|
225
267
|
},
|
|
226
268
|
};
|
|
227
269
|
if (event.dur < 0) {
|
|
@@ -237,8 +279,215 @@ export function createSortedSyntheticEvents(matchedPairs, syntheticEventCallback
|
|
|
237
279
|
return syntheticEvents.sort((a, b) => a.ts - b.ts);
|
|
238
280
|
}
|
|
239
281
|
export function createMatchedSortedSyntheticEvents(unpairedAsyncEvents, syntheticEventCallback) {
|
|
240
|
-
const matchedPairs =
|
|
282
|
+
const matchedPairs = matchEvents(unpairedAsyncEvents);
|
|
241
283
|
const syntheticEvents = createSortedSyntheticEvents(matchedPairs, syntheticEventCallback);
|
|
242
284
|
return syntheticEvents;
|
|
243
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Different trace events return line/column numbers that are 1 or 0 indexed.
|
|
288
|
+
* This function knows which events return 1 indexed numbers and normalizes
|
|
289
|
+
* them. The UI expects 0 indexed line numbers, so that is what we return.
|
|
290
|
+
*/
|
|
291
|
+
export function getZeroIndexedLineAndColumnForEvent(event) {
|
|
292
|
+
// Some events emit line numbers that are 1 indexed, but the UI layer expects
|
|
293
|
+
// numbers to be 0 indexed. So here, if the event matches a known 1-indexed
|
|
294
|
+
// number event, we subtract one from the line and column numbers.
|
|
295
|
+
// Otherwise, if the event has args.data.lineNumber/colNumber, we return it
|
|
296
|
+
// as is.
|
|
297
|
+
const numbers = getRawLineAndColumnNumbersForEvent(event);
|
|
298
|
+
const { lineNumber, columnNumber } = numbers;
|
|
299
|
+
switch (event.name) {
|
|
300
|
+
// All these events have line/column numbers which are 1 indexed; so we
|
|
301
|
+
// subtract to make them 0 indexed.
|
|
302
|
+
case "FunctionCall" /* Types.TraceEvents.KnownEventName.FunctionCall */:
|
|
303
|
+
case "EvaluateScript" /* Types.TraceEvents.KnownEventName.EvaluateScript */:
|
|
304
|
+
case "v8.compile" /* Types.TraceEvents.KnownEventName.Compile */:
|
|
305
|
+
case "v8.produceCache" /* Types.TraceEvents.KnownEventName.CacheScript */: {
|
|
306
|
+
return {
|
|
307
|
+
lineNumber: typeof lineNumber === 'number' ? lineNumber - 1 : undefined,
|
|
308
|
+
columnNumber: typeof columnNumber === 'number' ? columnNumber - 1 : undefined,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
default: {
|
|
312
|
+
return numbers;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Different trace events contain stack traces with line/column numbers
|
|
318
|
+
* that are 1 or 0 indexed.
|
|
319
|
+
* This function knows which events return 1 indexed numbers and normalizes
|
|
320
|
+
* them. The UI expects 0 indexed line numbers, so that is what we return.
|
|
321
|
+
*/
|
|
322
|
+
export function getZeroIndexedStackTraceForEvent(event) {
|
|
323
|
+
const stack = stackTraceForEvent(event);
|
|
324
|
+
if (!stack) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
return stack.map(callFrame => {
|
|
328
|
+
const normalizedCallFrame = { ...callFrame };
|
|
329
|
+
switch (event.name) {
|
|
330
|
+
case "ScheduleStyleRecalculation" /* Types.TraceEvents.KnownEventName.ScheduleStyleRecalculation */:
|
|
331
|
+
case "InvalidateLayout" /* Types.TraceEvents.KnownEventName.InvalidateLayout */:
|
|
332
|
+
case "UpdateLayoutTree" /* Types.TraceEvents.KnownEventName.UpdateLayoutTree */: {
|
|
333
|
+
normalizedCallFrame.lineNumber = callFrame.lineNumber && callFrame.lineNumber - 1;
|
|
334
|
+
normalizedCallFrame.columnNumber = callFrame.columnNumber && callFrame.columnNumber - 1;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return normalizedCallFrame;
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* NOTE: you probably do not want this function! (Which is why it is not exported).
|
|
342
|
+
*
|
|
343
|
+
* Some trace events have 0 indexed line/column numbers, and others have 1
|
|
344
|
+
* indexed. This function does NOT normalize them, but
|
|
345
|
+
* `getZeroIndexedLineAndColumnNumbersForEvent` does. It is best to use that!
|
|
346
|
+
*
|
|
347
|
+
* @see {@link getZeroIndexedLineAndColumnForEvent}
|
|
348
|
+
**/
|
|
349
|
+
function getRawLineAndColumnNumbersForEvent(event) {
|
|
350
|
+
if (!event.args?.data) {
|
|
351
|
+
return {
|
|
352
|
+
lineNumber: undefined,
|
|
353
|
+
columnNumber: undefined,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
let lineNumber = undefined;
|
|
357
|
+
let columnNumber = undefined;
|
|
358
|
+
if ('lineNumber' in event.args.data && typeof event.args.data.lineNumber === 'number') {
|
|
359
|
+
lineNumber = event.args.data.lineNumber;
|
|
360
|
+
}
|
|
361
|
+
if ('columnNumber' in event.args.data && typeof event.args.data.columnNumber === 'number') {
|
|
362
|
+
columnNumber = event.args.data.columnNumber;
|
|
363
|
+
}
|
|
364
|
+
return { lineNumber, columnNumber };
|
|
365
|
+
}
|
|
366
|
+
export function frameIDForEvent(event) {
|
|
367
|
+
// There are a few events (for example UpdateLayoutTree, ParseHTML) that have
|
|
368
|
+
// the frame stored in args.beginData
|
|
369
|
+
// Rather than list them all we just check for the presence of the field, so
|
|
370
|
+
// we are robust against future trace events also doing this.
|
|
371
|
+
// This check seems very robust, but it also helps satisfy TypeScript and
|
|
372
|
+
// prevents us against unexpected data.
|
|
373
|
+
if (event.args && 'beginData' in event.args && typeof event.args.beginData === 'object' &&
|
|
374
|
+
event.args.beginData !== null && 'frame' in event.args.beginData &&
|
|
375
|
+
typeof event.args.beginData.frame === 'string') {
|
|
376
|
+
return event.args.beginData.frame;
|
|
377
|
+
}
|
|
378
|
+
// Otherwise, we expect frame to be in args.data
|
|
379
|
+
if (event.args?.data?.frame) {
|
|
380
|
+
return event.args.data.frame;
|
|
381
|
+
}
|
|
382
|
+
// No known frame for this event.
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
const DevToolsTimelineEventCategory = 'disabled-by-default-devtools.timeline';
|
|
386
|
+
function isTopLevelEvent(event) {
|
|
387
|
+
return event.cat.includes(DevToolsTimelineEventCategory) && event.name === "RunTask" /* Types.TraceEvents.KnownEventName.RunTask */;
|
|
388
|
+
}
|
|
389
|
+
function topLevelEventIndexEndingAfter(events, time) {
|
|
390
|
+
let index = Platform.ArrayUtilities.upperBound(events, time, (time, event) => time - event.ts) - 1;
|
|
391
|
+
while (index > 0 && !isTopLevelEvent(events[index])) {
|
|
392
|
+
index--;
|
|
393
|
+
}
|
|
394
|
+
return Math.max(index, 0);
|
|
395
|
+
}
|
|
396
|
+
export function findUpdateLayoutTreeEvents(events, startTime, endTime) {
|
|
397
|
+
const foundEvents = [];
|
|
398
|
+
const startEventIndex = topLevelEventIndexEndingAfter(events, startTime);
|
|
399
|
+
for (let i = startEventIndex; i < events.length; i++) {
|
|
400
|
+
const event = events[i];
|
|
401
|
+
if (!Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (event.ts >= (endTime || Infinity)) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
foundEvents.push(event);
|
|
408
|
+
}
|
|
409
|
+
return foundEvents;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Iterates events in a tree hierarchically, from top to bottom,
|
|
413
|
+
* calling back on every event's start and end in the order
|
|
414
|
+
* dictated by the corresponding timestamp.
|
|
415
|
+
*
|
|
416
|
+
* Events are assumed to be in ascendent order by timestamp.
|
|
417
|
+
*
|
|
418
|
+
* Events with 0 duration are treated as instant events. These do not have a
|
|
419
|
+
* begin and end, but will be passed to the config.onInstantEvent callback as
|
|
420
|
+
* they are discovered. Do not provide this callback if you are not interested
|
|
421
|
+
* in them.
|
|
422
|
+
*
|
|
423
|
+
* For example, given this tree, the following callbacks
|
|
424
|
+
* are expected to be made in the following order
|
|
425
|
+
* |---------------A---------------|
|
|
426
|
+
* |------B------||-------D------|
|
|
427
|
+
* |---C---|
|
|
428
|
+
*
|
|
429
|
+
* 1. Start A
|
|
430
|
+
* 3. Start B
|
|
431
|
+
* 4. Start C
|
|
432
|
+
* 5. End C
|
|
433
|
+
* 6. End B
|
|
434
|
+
* 7. Start D
|
|
435
|
+
* 8. End D
|
|
436
|
+
* 9. End A
|
|
437
|
+
*
|
|
438
|
+
* By default, async events are skipped. This behaviour can be
|
|
439
|
+
* overriden making use of the config.ignoreAsyncEvents parameter.
|
|
440
|
+
*/
|
|
441
|
+
export function forEachEvent(events, config) {
|
|
442
|
+
const globalStartTime = config.startTime || Types.Timing.MicroSeconds(0);
|
|
443
|
+
const globalEndTime = config.endTime || Types.Timing.MicroSeconds(Infinity);
|
|
444
|
+
const ignoreAsyncEvents = config.ignoreAsyncEvents === false ? false : true;
|
|
445
|
+
const stack = [];
|
|
446
|
+
const startEventIndex = topLevelEventIndexEndingAfter(events, globalStartTime);
|
|
447
|
+
for (let i = startEventIndex; i < events.length; i++) {
|
|
448
|
+
const currentEvent = events[i];
|
|
449
|
+
const currentEventTimings = eventTimingsMicroSeconds(currentEvent);
|
|
450
|
+
if (currentEventTimings.endTime < globalStartTime) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
if (currentEventTimings.startTime > globalEndTime) {
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
const isIgnoredAsyncEvent = ignoreAsyncEvents && Types.TraceEvents.isAsyncPhase(currentEvent.ph);
|
|
457
|
+
if (isIgnoredAsyncEvent || Types.TraceEvents.isFlowPhase(currentEvent.ph)) {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
// If we have now reached an event that is after a bunch of events, we need
|
|
461
|
+
// to call the onEndEvent callback for those events before moving on.
|
|
462
|
+
let lastEventOnStack = stack.at(-1);
|
|
463
|
+
let lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;
|
|
464
|
+
while (lastEventOnStack && lastEventEndTime && lastEventEndTime <= currentEventTimings.startTime) {
|
|
465
|
+
stack.pop();
|
|
466
|
+
config.onEndEvent(lastEventOnStack);
|
|
467
|
+
lastEventOnStack = stack.at(-1);
|
|
468
|
+
lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;
|
|
469
|
+
}
|
|
470
|
+
// Now we have dealt with all events prior to this one, see if we need to care about this one.
|
|
471
|
+
if (config.eventFilter && !config.eventFilter(currentEvent)) {
|
|
472
|
+
// The user has chosen to filter this event out, so continue on and do nothing
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if (currentEventTimings.duration) {
|
|
476
|
+
config.onStartEvent(currentEvent);
|
|
477
|
+
stack.push(currentEvent);
|
|
478
|
+
}
|
|
479
|
+
else if (config.onInstantEvent) {
|
|
480
|
+
// An event with 0 duration is an instant event.
|
|
481
|
+
config.onInstantEvent(currentEvent);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
// Now we have finished looping over all events; any events remaining on the
|
|
485
|
+
// stack need to have their onEndEvent called.
|
|
486
|
+
while (stack.length) {
|
|
487
|
+
const last = stack.pop();
|
|
488
|
+
if (last) {
|
|
489
|
+
config.onEndEvent(last);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
244
493
|
//# sourceMappingURL=Trace.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Trace.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/Trace.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Types from '../types/types.js';\n\ntype MatchedPairType<T extends Types.TraceEvents.TraceEventPairableAsync> = Types.TraceEvents.SyntheticEventPair<T>;\n\nexport function stackTraceForEvent(event: Types.TraceEvents.TraceEventData): Types.TraceEvents.TraceEventCallFrame[]|\n null {\n if (Types.TraceEvents.isSyntheticInvalidation(event)) {\n return event.stackTrace || null;\n }\n if (event.args?.data?.stackTrace) {\n return event.args.data.stackTrace;\n }\n if (Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {\n return event.args.beginData?.stackTrace || null;\n }\n return null;\n}\n\nexport function extractOriginFromTrace(firstNavigationURL: string): string|null {\n const url = new URL(firstNavigationURL);\n if (url) {\n // We do this to save some space in the toolbar - seeing the `www` is less\n // useful than seeing `foo.com` if it's truncated at narrow widths\n if (url.host.startsWith('www.')) {\n return url.host.slice(4);\n }\n return url.host;\n }\n return null;\n}\n\nexport type EventsInThread<T extends Types.TraceEvents.TraceEventData> = Map<Types.TraceEvents.ThreadID, T[]>;\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nexport function addEventToProcessThread<T extends Types.TraceEvents.TraceEventData>(\n event: T,\n eventsInProcessThread: Map<Types.TraceEvents.ProcessID, EventsInThread<T>>,\n ): void {\n const {tid, pid} = event;\n let eventsInThread = eventsInProcessThread.get(pid);\n if (!eventsInThread) {\n eventsInThread = new Map<Types.TraceEvents.ThreadID, T[]>();\n }\n\n let events = eventsInThread.get(tid);\n if (!events) {\n events = [];\n }\n\n events.push(event);\n eventsInThread.set(event.tid, events);\n eventsInProcessThread.set(event.pid, eventsInThread);\n}\n\ntype TimeSpan = {\n ts: Types.Timing.MicroSeconds,\n dur?: Types.Timing.MicroSeconds,\n};\nfunction eventTimeComparator(a: TimeSpan, b: TimeSpan): -1|0|1 {\n const aBeginTime = a.ts;\n const bBeginTime = b.ts;\n if (aBeginTime < bBeginTime) {\n return -1;\n }\n if (aBeginTime > bBeginTime) {\n return 1;\n }\n const aDuration = a.dur ?? 0;\n const bDuration = b.dur ?? 0;\n const aEndTime = aBeginTime + aDuration;\n const bEndTime = bBeginTime + bDuration;\n if (aEndTime > bEndTime) {\n return -1;\n }\n if (aEndTime < bEndTime) {\n return 1;\n }\n return 0;\n}\n/**\n * Sorts all the events in place, in order, by their start time. If they have\n * the same start time, orders them by longest first.\n */\nexport function sortTraceEventsInPlace(events: {ts: Types.Timing.MicroSeconds, dur?: Types.Timing.MicroSeconds}[]):\n void {\n events.sort(eventTimeComparator);\n}\n\n/**\n * Returns an array of ordered events that results after merging the two\n * ordered input arrays.\n */\nexport function\nmergeEventsInOrder<T1 extends Types.TraceEvents.TraceEventData, T2 extends Types.TraceEvents.TraceEventData>(\n eventsArray1: readonly T1[], eventsArray2: readonly T2[]): (T1|T2)[] {\n const result = [];\n let i = 0;\n let j = 0;\n while (i < eventsArray1.length && j < eventsArray2.length) {\n const event1 = eventsArray1[i];\n const event2 = eventsArray2[j];\n const compareValue = eventTimeComparator(event1, event2);\n if (compareValue <= 0) {\n result.push(event1);\n i++;\n }\n if (compareValue === 1) {\n result.push(event2);\n j++;\n }\n }\n while (i < eventsArray1.length) {\n result.push(eventsArray1[i++]);\n }\n while (j < eventsArray2.length) {\n result.push(eventsArray2[j++]);\n }\n return result;\n}\n\nexport function getNavigationForTraceEvent(\n event: Types.TraceEvents.TraceEventData,\n eventFrameId: string,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n ): Types.TraceEvents.TraceEventNavigationStart|null {\n const navigations = navigationsByFrameId.get(eventFrameId);\n if (!navigations || eventFrameId === '') {\n // This event's navigation has been filtered out by the meta handler as a noise event\n // or contains an empty frameId.\n return null;\n }\n\n const eventNavigationIndex =\n Platform.ArrayUtilities.nearestIndexFromEnd(navigations, navigation => navigation.ts <= event.ts);\n\n if (eventNavigationIndex === null) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigations[eventNavigationIndex];\n}\n\nexport function extractId(event: Types.TraceEvents.TraceEventPairableAsync|\n MatchedPairType<Types.TraceEvents.TraceEventPairableAsync>): string|undefined {\n return event.id ?? event.id2?.global ?? event.id2?.local;\n}\n\nexport function activeURLForFrameAtTime(\n frameId: string, time: Types.Timing.MicroSeconds,\n rendererProcessesByFrame:\n Map<string,\n Map<Types.TraceEvents.ProcessID,\n {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindowMicroSeconds}[]>>): string|null {\n const processData = rendererProcessesByFrame.get(frameId);\n if (!processData) {\n return null;\n }\n for (const processes of processData.values()) {\n for (const processInfo of processes) {\n if (processInfo.window.min > time || processInfo.window.max < time) {\n continue;\n }\n return processInfo.frame.url;\n }\n }\n return null;\n}\n\nexport function makeProfileCall(\n node: CPUProfile.ProfileTreeModel.ProfileNode, ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.SyntheticProfileCall {\n return {\n cat: '',\n name: 'ProfileCall',\n nodeId: node.id,\n args: {},\n ph: Types.TraceEvents.Phase.COMPLETE,\n pid,\n tid,\n ts,\n dur: Types.Timing.MicroSeconds(0),\n selfTime: Types.Timing.MicroSeconds(0),\n callFrame: node.callFrame,\n };\n}\n\nexport function makeSyntheticTraceEntry(\n name: string, ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.SyntheticTraceEntry {\n return {\n cat: '',\n name,\n args: {},\n ph: Types.TraceEvents.Phase.COMPLETE,\n pid,\n tid,\n ts,\n dur: Types.Timing.MicroSeconds(0),\n selfTime: Types.Timing.MicroSeconds(0),\n };\n}\n\nexport function matchBeginningAndEndEvents(unpairedEvents: Types.TraceEvents.TraceEventPairableAsync[]): Map<string, {\n begin: Types.TraceEvents.TraceEventPairableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventPairableAsyncEnd | null,\n}> {\n // map to store begin and end of the event\n const matchedPairs: Map<string, {\n begin: Types.TraceEvents.TraceEventPairableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventPairableAsyncEnd | null,\n }> = new Map();\n\n // looking for start and end\n for (const event of unpairedEvents) {\n const syntheticId = getSyntheticId(event);\n if (syntheticId === undefined) {\n continue;\n }\n // Create a synthetic id to prevent collisions across categories.\n // Console timings can be dispatched with the same id, so use the\n // event name as well to generate unique ids.\n const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedPairs, syntheticId, () => {\n return {begin: null, end: null};\n });\n\n const isStartEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_START;\n const isEndEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_END;\n\n if (isStartEvent) {\n otherEventsWithID.begin = event as Types.TraceEvents.TraceEventPairableAsyncBegin;\n } else if (isEndEvent) {\n otherEventsWithID.end = event as Types.TraceEvents.TraceEventPairableAsyncEnd;\n }\n }\n\n return matchedPairs;\n}\n\nfunction getSyntheticId(event: Types.TraceEvents.TraceEventPairableAsync): string|undefined {\n const id = extractId(event);\n return id && `${event.cat}:${id}:${event.name}`;\n}\n\nexport function createSortedSyntheticEvents<T extends Types.TraceEvents.TraceEventPairableAsync>(\n matchedPairs: Map<string, {\n begin: Types.TraceEvents.TraceEventPairableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventPairableAsyncEnd | null,\n }>,\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void,\n ): MatchedPairType<T>[] {\n const syntheticEvents: MatchedPairType<T>[] = [];\n for (const [id, eventsPair] of matchedPairs.entries()) {\n const beginEvent = eventsPair.begin;\n const endEvent = eventsPair.end;\n if (!beginEvent || !endEvent) {\n // This should never happen, the backend only creates the events once it\n // has them both, so we should never get into this state.\n // If we do, something is very wrong, so let's just drop that problematic event.\n continue;\n }\n const pair = {beginEvent, endEvent};\n function eventsArePairable(data: {\n beginEvent: Types.TraceEvents.TraceEventPairableAsyncBegin,\n endEvent: Types.TraceEvents.TraceEventPairableAsyncEnd,\n }): data is MatchedPairType<T>['args']['data'] {\n return Boolean(getSyntheticId(data.beginEvent)) &&\n getSyntheticId(data.beginEvent) === getSyntheticId(data.endEvent);\n }\n if (!eventsArePairable(pair)) {\n continue;\n }\n const event: MatchedPairType<T> = {\n cat: endEvent.cat,\n ph: endEvent.ph,\n pid: endEvent.pid,\n tid: endEvent.tid,\n id,\n // Both events have the same name, so it doesn't matter which we pick to\n // use as the description\n name: beginEvent.name,\n dur: Types.Timing.MicroSeconds(endEvent.ts - beginEvent.ts),\n ts: beginEvent.ts,\n args: {\n data: pair,\n },\n };\n\n if (event.dur < 0) {\n // We have seen in the backend that sometimes animation events get\n // generated with multiple begin entries, or multiple end entries, and this\n // can cause invalid data on the performance panel, so we drop them.\n // crbug.com/1472375\n continue;\n }\n syntheticEventCallback?.(event);\n syntheticEvents.push(event);\n }\n return syntheticEvents.sort((a, b) => a.ts - b.ts);\n}\n\nexport function createMatchedSortedSyntheticEvents<T extends Types.TraceEvents.TraceEventPairableAsync>(\n unpairedAsyncEvents: T[],\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void): MatchedPairType<T>[] {\n const matchedPairs = matchBeginningAndEndEvents(unpairedAsyncEvents);\n const syntheticEvents = createSortedSyntheticEvents<T>(matchedPairs, syntheticEventCallback);\n return syntheticEvents;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Trace.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/Trace.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Types from '../types/types.js';\n\nimport {eventTimingsMicroSeconds} from './Timing.js';\n\ntype MatchedPairType<T extends Types.TraceEvents.TraceEventPairableAsync> = Types.TraceEvents.SyntheticEventPair<T>;\ntype MatchingPairableAsyncEvents = {\n begin: Types.TraceEvents.TraceEventPairableAsyncBegin|null,\n end: Types.TraceEvents.TraceEventPairableAsyncEnd|null,\n instant?: Types.TraceEvents.TraceEventPairableAsyncInstant[],\n};\n\n/**\n * Extracts the raw stack trace of known trace events. Most likely than\n * not you want to use `getZeroIndexedStackTraceForEvent`, which returns\n * the stack with zero based numbering. Since some trace events are\n * one based this function can yield unexpected results when used\n * indiscriminately.\n */\nfunction stackTraceForEvent(event: Types.TraceEvents.TraceEventData): Types.TraceEvents.TraceEventCallFrame[]|null {\n if (Types.TraceEvents.isSyntheticInvalidation(event)) {\n return event.stackTrace || null;\n }\n if (event.args?.data?.stackTrace) {\n return event.args.data.stackTrace;\n }\n if (Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {\n return event.args.beginData?.stackTrace || null;\n }\n return null;\n}\n\nexport function extractOriginFromTrace(firstNavigationURL: string): string|null {\n const url = new URL(firstNavigationURL);\n if (url) {\n // We do this to save some space in the toolbar - seeing the `www` is less\n // useful than seeing `foo.com` if it's truncated at narrow widths\n if (url.host.startsWith('www.')) {\n return url.host.slice(4);\n }\n return url.host;\n }\n return null;\n}\n\nexport type EventsInThread<T extends Types.TraceEvents.TraceEventData> = Map<Types.TraceEvents.ThreadID, T[]>;\n// Each thread contains events. Events indicate the thread and process IDs, which are\n// used to store the event in the correct process thread entry below.\nexport function addEventToProcessThread<T extends Types.TraceEvents.TraceEventData>(\n event: T,\n eventsInProcessThread: Map<Types.TraceEvents.ProcessID, EventsInThread<T>>,\n ): void {\n const {tid, pid} = event;\n let eventsInThread = eventsInProcessThread.get(pid);\n if (!eventsInThread) {\n eventsInThread = new Map<Types.TraceEvents.ThreadID, T[]>();\n }\n\n let events = eventsInThread.get(tid);\n if (!events) {\n events = [];\n }\n\n events.push(event);\n eventsInThread.set(event.tid, events);\n eventsInProcessThread.set(event.pid, eventsInThread);\n}\n\ntype TimeSpan = {\n ts: Types.Timing.MicroSeconds,\n dur?: Types.Timing.MicroSeconds,\n};\nexport function eventTimeComparator(a: TimeSpan, b: TimeSpan): -1|0|1 {\n const aBeginTime = a.ts;\n const bBeginTime = b.ts;\n if (aBeginTime < bBeginTime) {\n return -1;\n }\n if (aBeginTime > bBeginTime) {\n return 1;\n }\n const aDuration = a.dur ?? 0;\n const bDuration = b.dur ?? 0;\n const aEndTime = aBeginTime + aDuration;\n const bEndTime = bBeginTime + bDuration;\n if (aEndTime > bEndTime) {\n return -1;\n }\n if (aEndTime < bEndTime) {\n return 1;\n }\n return 0;\n}\n/**\n * Sorts all the events in place, in order, by their start time. If they have\n * the same start time, orders them by longest first.\n */\nexport function sortTraceEventsInPlace(events: {ts: Types.Timing.MicroSeconds, dur?: Types.Timing.MicroSeconds}[]):\n void {\n events.sort(eventTimeComparator);\n}\n\n/**\n * Returns an array of ordered events that results after merging the two\n * ordered input arrays.\n */\nexport function\nmergeEventsInOrder<T1 extends Types.TraceEvents.TraceEventData, T2 extends Types.TraceEvents.TraceEventData>(\n eventsArray1: readonly T1[], eventsArray2: readonly T2[]): (T1|T2)[] {\n const result = [];\n let i = 0;\n let j = 0;\n while (i < eventsArray1.length && j < eventsArray2.length) {\n const event1 = eventsArray1[i];\n const event2 = eventsArray2[j];\n const compareValue = eventTimeComparator(event1, event2);\n if (compareValue <= 0) {\n result.push(event1);\n i++;\n }\n if (compareValue === 1) {\n result.push(event2);\n j++;\n }\n }\n while (i < eventsArray1.length) {\n result.push(eventsArray1[i++]);\n }\n while (j < eventsArray2.length) {\n result.push(eventsArray2[j++]);\n }\n return result;\n}\n\nexport function getNavigationForTraceEvent(\n event: Types.TraceEvents.TraceEventData,\n eventFrameId: string,\n navigationsByFrameId: Map<string, Types.TraceEvents.TraceEventNavigationStart[]>,\n ): Types.TraceEvents.TraceEventNavigationStart|null {\n const navigations = navigationsByFrameId.get(eventFrameId);\n if (!navigations || eventFrameId === '') {\n // This event's navigation has been filtered out by the meta handler as a noise event\n // or contains an empty frameId.\n return null;\n }\n\n const eventNavigationIndex =\n Platform.ArrayUtilities.nearestIndexFromEnd(navigations, navigation => navigation.ts <= event.ts);\n\n if (eventNavigationIndex === null) {\n // This event's navigation has been filtered out by the meta handler as a noise event.\n return null;\n }\n return navigations[eventNavigationIndex];\n}\n\nexport function extractId(event: Types.TraceEvents.TraceEventPairableAsync|\n MatchedPairType<Types.TraceEvents.TraceEventPairableAsync>): string|undefined {\n return event.id ?? event.id2?.global ?? event.id2?.local;\n}\n\nexport function activeURLForFrameAtTime(\n frameId: string, time: Types.Timing.MicroSeconds,\n rendererProcessesByFrame:\n Map<string,\n Map<Types.TraceEvents.ProcessID,\n {frame: Types.TraceEvents.TraceFrame, window: Types.Timing.TraceWindowMicroSeconds}[]>>): string|null {\n const processData = rendererProcessesByFrame.get(frameId);\n if (!processData) {\n return null;\n }\n for (const processes of processData.values()) {\n for (const processInfo of processes) {\n if (processInfo.window.min > time || processInfo.window.max < time) {\n continue;\n }\n return processInfo.frame.url;\n }\n }\n return null;\n}\n\n/**\n * @param node the node attached to the profile call. Here a node represents a function in the call tree.\n * @param profileId the profile ID that the sample came from that backs this call.\n * @param sampleIndex the index of the sample in the given profile that this call was created from\n * @param ts the timestamp of the profile call\n * @param pid the process ID of the profile call\n * @param tid the thread ID of the profile call\n *\n * See `panels/timeline/docs/profile_calls.md` for more context on how these events are created.\n */\nexport function makeProfileCall(\n node: CPUProfile.ProfileTreeModel.ProfileNode, profileId: Types.TraceEvents.ProfileID, sampleIndex: number,\n ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.SyntheticProfileCall {\n return {\n cat: '',\n name: 'ProfileCall',\n nodeId: node.id,\n args: {},\n ph: Types.TraceEvents.Phase.COMPLETE,\n pid,\n tid,\n ts,\n dur: Types.Timing.MicroSeconds(0),\n selfTime: Types.Timing.MicroSeconds(0),\n callFrame: node.callFrame,\n sampleIndex,\n profileId,\n };\n}\n\nexport function makeSyntheticTraceEntry(\n name: string, ts: Types.Timing.MicroSeconds, pid: Types.TraceEvents.ProcessID,\n tid: Types.TraceEvents.ThreadID): Types.TraceEvents.SyntheticTraceEntry {\n return {\n cat: '',\n name,\n args: {},\n ph: Types.TraceEvents.Phase.COMPLETE,\n pid,\n tid,\n ts,\n dur: Types.Timing.MicroSeconds(0),\n selfTime: Types.Timing.MicroSeconds(0),\n };\n}\n\n/**\n * Matches beginning events with TraceEventPairableAsyncEnd and TraceEventPairableAsyncInstant (ASYNC_NESTABLE_INSTANT)\n * if provided, though currently only coming from Animations. Traces may contain multiple instant events so we need to\n * account for that.\n *\n * @returns {Map<string, MatchingPairableAsyncEvents>} Map of the animation's ID to it's matching events.\n */\nexport function matchEvents(unpairedEvents: Types.TraceEvents.TraceEventPairableAsync[]):\n Map<string, MatchingPairableAsyncEvents> {\n // map to store begin and end of the event\n const matchedPairs: Map<string, MatchingPairableAsyncEvents> = new Map();\n\n // looking for start and end\n for (const event of unpairedEvents) {\n const syntheticId = getSyntheticId(event);\n if (syntheticId === undefined) {\n continue;\n }\n // Create a synthetic id to prevent collisions across categories.\n // Console timings can be dispatched with the same id, so use the\n // event name as well to generate unique ids.\n const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedPairs, syntheticId, () => {\n return {begin: null, end: null, instant: []};\n });\n\n const isStartEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_START;\n const isEndEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_END;\n const isInstantEvent = event.ph === Types.TraceEvents.Phase.ASYNC_NESTABLE_INSTANT;\n\n if (isStartEvent) {\n otherEventsWithID.begin = event as Types.TraceEvents.TraceEventPairableAsyncBegin;\n } else if (isEndEvent) {\n otherEventsWithID.end = event as Types.TraceEvents.TraceEventPairableAsyncEnd;\n } else if (isInstantEvent) {\n if (!otherEventsWithID.instant) {\n otherEventsWithID.instant = [];\n }\n otherEventsWithID.instant.push(event as Types.TraceEvents.TraceEventPairableAsyncInstant);\n }\n }\n return matchedPairs;\n}\n\nfunction getSyntheticId(event: Types.TraceEvents.TraceEventPairableAsync): string|undefined {\n const id = extractId(event);\n return id && `${event.cat}:${id}:${event.name}`;\n}\n\nexport function createSortedSyntheticEvents<T extends Types.TraceEvents.TraceEventPairableAsync>(\n matchedPairs: Map<string, {\n begin: Types.TraceEvents.TraceEventPairableAsyncBegin | null,\n end: Types.TraceEvents.TraceEventPairableAsyncEnd | null,\n instant?: Types.TraceEvents.TraceEventPairableAsyncInstant[],\n }>,\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void,\n ): MatchedPairType<T>[] {\n const syntheticEvents: MatchedPairType<T>[] = [];\n for (const [id, eventsTriplet] of matchedPairs.entries()) {\n const beginEvent = eventsTriplet.begin;\n const endEvent = eventsTriplet.end;\n const instantEvents = eventsTriplet.instant;\n if (!beginEvent || !(endEvent || instantEvents)) {\n // This should never happen, the backend only creates the events once it\n // has them both (beginEvent & endEvent/instantEvents), so we should never get into this state.\n // If we do, something is very wrong, so let's just drop that problematic event.\n continue;\n }\n const triplet = {beginEvent, endEvent, instantEvents};\n /**\n * When trying to pair events with instant events present, there are times when these\n * ASYNC_NESTABLE_INSTANT ('n') don't have a corresponding ASYNC_NESTABLE_END ('e') event.\n * In these cases, pair without needing the endEvent.\n */\n function eventsArePairable(data: {\n beginEvent: Types.TraceEvents.TraceEventPairableAsyncBegin,\n endEvent: Types.TraceEvents.TraceEventPairableAsyncEnd|null,\n instantEvents?: Types.TraceEvents.TraceEventPairableAsyncInstant[],\n }): data is MatchedPairType<T>['args']['data'] {\n const instantEventsMatch = data.instantEvents ? data.instantEvents.some(e => id === getSyntheticId(e)) : false;\n const endEventMatch = data.endEvent ? id === getSyntheticId(data.endEvent) : false;\n return Boolean(id) && (instantEventsMatch || endEventMatch);\n }\n if (!eventsArePairable(triplet)) {\n continue;\n }\n const targetEvent = endEvent || beginEvent;\n const event: MatchedPairType<T> = {\n cat: targetEvent.cat,\n ph: targetEvent.ph,\n pid: targetEvent.pid,\n tid: targetEvent.tid,\n id,\n // Both events have the same name, so it doesn't matter which we pick to\n // use as the description\n name: beginEvent.name,\n dur: Types.Timing.MicroSeconds(targetEvent.ts - beginEvent.ts),\n ts: beginEvent.ts,\n args: {\n data: triplet,\n },\n };\n\n if (event.dur < 0) {\n // We have seen in the backend that sometimes animation events get\n // generated with multiple begin entries, or multiple end entries, and this\n // can cause invalid data on the performance panel, so we drop them.\n // crbug.com/1472375\n continue;\n }\n syntheticEventCallback?.(event);\n syntheticEvents.push(event);\n }\n return syntheticEvents.sort((a, b) => a.ts - b.ts);\n}\n\nexport function createMatchedSortedSyntheticEvents<T extends Types.TraceEvents.TraceEventPairableAsync>(\n unpairedAsyncEvents: T[],\n syntheticEventCallback?: (syntheticEvent: MatchedPairType<T>) => void): MatchedPairType<T>[] {\n const matchedPairs = matchEvents(unpairedAsyncEvents);\n const syntheticEvents = createSortedSyntheticEvents<T>(matchedPairs, syntheticEventCallback);\n return syntheticEvents;\n}\n\n/**\n * Different trace events return line/column numbers that are 1 or 0 indexed.\n * This function knows which events return 1 indexed numbers and normalizes\n * them. The UI expects 0 indexed line numbers, so that is what we return.\n */\nexport function getZeroIndexedLineAndColumnForEvent(event: Types.TraceEvents.TraceEventData): {\n lineNumber?: number,\n columnNumber?: number,\n} {\n // Some events emit line numbers that are 1 indexed, but the UI layer expects\n // numbers to be 0 indexed. So here, if the event matches a known 1-indexed\n // number event, we subtract one from the line and column numbers.\n // Otherwise, if the event has args.data.lineNumber/colNumber, we return it\n // as is.\n const numbers = getRawLineAndColumnNumbersForEvent(event);\n const {lineNumber, columnNumber} = numbers;\n\n switch (event.name) {\n // All these events have line/column numbers which are 1 indexed; so we\n // subtract to make them 0 indexed.\n case Types.TraceEvents.KnownEventName.FunctionCall:\n case Types.TraceEvents.KnownEventName.EvaluateScript:\n case Types.TraceEvents.KnownEventName.Compile:\n case Types.TraceEvents.KnownEventName.CacheScript: {\n return {\n lineNumber: typeof lineNumber === 'number' ? lineNumber - 1 : undefined,\n columnNumber: typeof columnNumber === 'number' ? columnNumber - 1 : undefined,\n };\n }\n default: {\n return numbers;\n }\n }\n}\n\n/**\n * Different trace events contain stack traces with line/column numbers\n * that are 1 or 0 indexed.\n * This function knows which events return 1 indexed numbers and normalizes\n * them. The UI expects 0 indexed line numbers, so that is what we return.\n */\nexport function getZeroIndexedStackTraceForEvent(event: Types.TraceEvents.TraceEventData):\n Types.TraceEvents.TraceEventCallFrame[]|null {\n const stack = stackTraceForEvent(event);\n if (!stack) {\n return null;\n }\n return stack.map(callFrame => {\n const normalizedCallFrame = {...callFrame};\n switch (event.name) {\n case Types.TraceEvents.KnownEventName.ScheduleStyleRecalculation:\n case Types.TraceEvents.KnownEventName.InvalidateLayout:\n case Types.TraceEvents.KnownEventName.UpdateLayoutTree: {\n normalizedCallFrame.lineNumber = callFrame.lineNumber && callFrame.lineNumber - 1;\n normalizedCallFrame.columnNumber = callFrame.columnNumber && callFrame.columnNumber - 1;\n }\n }\n return normalizedCallFrame;\n });\n}\n\n/**\n * NOTE: you probably do not want this function! (Which is why it is not exported).\n *\n * Some trace events have 0 indexed line/column numbers, and others have 1\n * indexed. This function does NOT normalize them, but\n * `getZeroIndexedLineAndColumnNumbersForEvent` does. It is best to use that!\n *\n * @see {@link getZeroIndexedLineAndColumnForEvent}\n **/\nfunction getRawLineAndColumnNumbersForEvent(event: Types.TraceEvents.TraceEventData): {\n lineNumber?: number,\n columnNumber?: number,\n} {\n if (!event.args?.data) {\n return {\n lineNumber: undefined,\n columnNumber: undefined,\n };\n }\n let lineNumber: number|undefined = undefined;\n let columnNumber: number|undefined = undefined;\n if ('lineNumber' in event.args.data && typeof event.args.data.lineNumber === 'number') {\n lineNumber = event.args.data.lineNumber;\n }\n if ('columnNumber' in event.args.data && typeof event.args.data.columnNumber === 'number') {\n columnNumber = event.args.data.columnNumber;\n }\n\n return {lineNumber, columnNumber};\n}\n\nexport function frameIDForEvent(event: Types.TraceEvents.TraceEventData): string|null {\n // There are a few events (for example UpdateLayoutTree, ParseHTML) that have\n // the frame stored in args.beginData\n // Rather than list them all we just check for the presence of the field, so\n // we are robust against future trace events also doing this.\n // This check seems very robust, but it also helps satisfy TypeScript and\n // prevents us against unexpected data.\n if (event.args && 'beginData' in event.args && typeof event.args.beginData === 'object' &&\n event.args.beginData !== null && 'frame' in event.args.beginData &&\n typeof event.args.beginData.frame === 'string') {\n return event.args.beginData.frame;\n }\n // Otherwise, we expect frame to be in args.data\n if (event.args?.data?.frame) {\n return event.args.data.frame;\n }\n\n // No known frame for this event.\n return null;\n}\n\nconst DevToolsTimelineEventCategory = 'disabled-by-default-devtools.timeline';\nfunction isTopLevelEvent(event: Types.TraceEvents.TraceEventData): boolean {\n return event.cat.includes(DevToolsTimelineEventCategory) && event.name === Types.TraceEvents.KnownEventName.RunTask;\n}\n\nfunction topLevelEventIndexEndingAfter(\n events: Types.TraceEvents.TraceEventData[], time: Types.Timing.MicroSeconds): number {\n let index = Platform.ArrayUtilities.upperBound(events, time, (time, event) => time - event.ts) - 1;\n while (index > 0 && !isTopLevelEvent(events[index])) {\n index--;\n }\n return Math.max(index, 0);\n}\nexport function findUpdateLayoutTreeEvents(\n events: Types.TraceEvents.TraceEventData[], startTime: Types.Timing.MicroSeconds,\n endTime?: Types.Timing.MicroSeconds): Types.TraceEvents.TraceEventUpdateLayoutTree[] {\n const foundEvents: Types.TraceEvents.TraceEventUpdateLayoutTree[] = [];\n const startEventIndex = topLevelEventIndexEndingAfter(events, startTime);\n for (let i = startEventIndex; i < events.length; i++) {\n const event = events[i];\n if (!Types.TraceEvents.isTraceEventUpdateLayoutTree(event)) {\n continue;\n }\n if (event.ts >= (endTime || Infinity)) {\n continue;\n }\n foundEvents.push(event);\n }\n return foundEvents;\n}\n\nexport interface ForEachEventConfig {\n onStartEvent: (event: Types.TraceEvents.TraceEventData) => void;\n onEndEvent: (event: Types.TraceEvents.TraceEventData) => void;\n onInstantEvent?: (event: Types.TraceEvents.TraceEventData) => void;\n eventFilter?: (event: Types.TraceEvents.TraceEventData) => boolean;\n startTime?: Types.Timing.MicroSeconds;\n endTime?: Types.Timing.MicroSeconds;\n /* If async events should be skipped. Defaults to true */\n ignoreAsyncEvents?: boolean;\n}\n\n/**\n * Iterates events in a tree hierarchically, from top to bottom,\n * calling back on every event's start and end in the order\n * dictated by the corresponding timestamp.\n *\n * Events are assumed to be in ascendent order by timestamp.\n *\n * Events with 0 duration are treated as instant events. These do not have a\n * begin and end, but will be passed to the config.onInstantEvent callback as\n * they are discovered. Do not provide this callback if you are not interested\n * in them.\n *\n * For example, given this tree, the following callbacks\n * are expected to be made in the following order\n * |---------------A---------------|\n * |------B------||-------D------|\n * |---C---|\n *\n * 1. Start A\n * 3. Start B\n * 4. Start C\n * 5. End C\n * 6. End B\n * 7. Start D\n * 8. End D\n * 9. End A\n *\n * By default, async events are skipped. This behaviour can be\n * overriden making use of the config.ignoreAsyncEvents parameter.\n */\nexport function forEachEvent(\n events: Types.TraceEvents.TraceEventData[],\n config: ForEachEventConfig,\n ): void {\n const globalStartTime = config.startTime || Types.Timing.MicroSeconds(0);\n const globalEndTime = config.endTime || Types.Timing.MicroSeconds(Infinity);\n const ignoreAsyncEvents = config.ignoreAsyncEvents === false ? false : true;\n\n const stack: Types.TraceEvents.TraceEventData[] = [];\n const startEventIndex = topLevelEventIndexEndingAfter(events, globalStartTime);\n for (let i = startEventIndex; i < events.length; i++) {\n const currentEvent = events[i];\n const currentEventTimings = eventTimingsMicroSeconds(currentEvent);\n if (currentEventTimings.endTime < globalStartTime) {\n continue;\n }\n if (currentEventTimings.startTime > globalEndTime) {\n break;\n }\n\n const isIgnoredAsyncEvent = ignoreAsyncEvents && Types.TraceEvents.isAsyncPhase(currentEvent.ph);\n if (isIgnoredAsyncEvent || Types.TraceEvents.isFlowPhase(currentEvent.ph)) {\n continue;\n }\n\n // If we have now reached an event that is after a bunch of events, we need\n // to call the onEndEvent callback for those events before moving on.\n let lastEventOnStack = stack.at(-1);\n let lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n while (lastEventOnStack && lastEventEndTime && lastEventEndTime <= currentEventTimings.startTime) {\n stack.pop();\n config.onEndEvent(lastEventOnStack);\n lastEventOnStack = stack.at(-1);\n lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n }\n\n // Now we have dealt with all events prior to this one, see if we need to care about this one.\n if (config.eventFilter && !config.eventFilter(currentEvent)) {\n // The user has chosen to filter this event out, so continue on and do nothing\n continue;\n }\n\n if (currentEventTimings.duration) {\n config.onStartEvent(currentEvent);\n stack.push(currentEvent);\n } else if (config.onInstantEvent) {\n // An event with 0 duration is an instant event.\n config.onInstantEvent(currentEvent);\n }\n }\n\n // Now we have finished looping over all events; any events remaining on the\n // stack need to have their onEndEvent called.\n while (stack.length) {\n const last = stack.pop();\n if (last) {\n config.onEndEvent(last);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type * as Types from '../types/types.js';
|
|
2
|
+
import { type InsightResult, type NavigationInsightContext, type RequiredData } from './types.js';
|
|
3
|
+
export declare function deps(): ['Meta', 'Animations'];
|
|
4
|
+
export declare const enum AnimationFailureReasons {
|
|
5
|
+
UNSUPPORTED_CSS_PROPERTY = "UNSUPPORTED_CSS_PROPERTY",
|
|
6
|
+
TRANSFROM_BOX_SIZE_DEPENDENT = "TRANSFROM_BOX_SIZE_DEPENDENT",
|
|
7
|
+
FILTER_MAY_MOVE_PIXELS = "FILTER_MAY_MOVE_PIXELS",
|
|
8
|
+
NON_REPLACE_COMPOSITE_MODE = "NON_REPLACE_COMPOSITE_MODE",
|
|
9
|
+
INCOMPATIBLE_ANIMATIONS = "INCOMPATIBLE_ANIMATIONS",
|
|
10
|
+
UNSUPPORTED_TIMING_PARAMS = "UNSUPPORTED_TIMING_PARAMS"
|
|
11
|
+
}
|
|
12
|
+
export interface NoncompositedAnimationFailure {
|
|
13
|
+
/**
|
|
14
|
+
* Animation name.
|
|
15
|
+
*/
|
|
16
|
+
name?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Failure reason based on mask number defined in
|
|
19
|
+
* https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22.
|
|
20
|
+
*/
|
|
21
|
+
failureReasons: AnimationFailureReasons[];
|
|
22
|
+
/**
|
|
23
|
+
* Unsupported properties.
|
|
24
|
+
*/
|
|
25
|
+
unsupportedProperties?: Types.TraceEvents.TraceEventAnimation['args']['data']['unsupportedProperties'];
|
|
26
|
+
}
|
|
27
|
+
export declare function generateInsight(traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext): InsightResult<{
|
|
28
|
+
animationFailures?: readonly NoncompositedAnimationFailure[];
|
|
29
|
+
}>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Copyright 2024 The Chromium Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
import * as Helpers from '../helpers/helpers.js';
|
|
5
|
+
export function deps() {
|
|
6
|
+
return ['Meta', 'Animations'];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Each failure reason is represented by a bit flag. The bit shift operator '<<' is used to define
|
|
10
|
+
* which bit corresponds to each failure reason.
|
|
11
|
+
* https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22
|
|
12
|
+
* @type {{flag: number, failure: AnimationFailureReasons}[]}
|
|
13
|
+
*/
|
|
14
|
+
const ACTIONABLE_FAILURE_REASONS = [
|
|
15
|
+
{
|
|
16
|
+
flag: 1 << 13,
|
|
17
|
+
failure: "UNSUPPORTED_CSS_PROPERTY" /* AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY */,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
flag: 1 << 11,
|
|
21
|
+
failure: "TRANSFROM_BOX_SIZE_DEPENDENT" /* AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT */,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
flag: 1 << 12,
|
|
25
|
+
failure: "FILTER_MAY_MOVE_PIXELS" /* AnimationFailureReasons.FILTER_MAY_MOVE_PIXELS */,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
flag: 1 << 4,
|
|
29
|
+
failure: "NON_REPLACE_COMPOSITE_MODE" /* AnimationFailureReasons.NON_REPLACE_COMPOSITE_MODE */,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
flag: 1 << 6,
|
|
33
|
+
failure: "INCOMPATIBLE_ANIMATIONS" /* AnimationFailureReasons.INCOMPATIBLE_ANIMATIONS */,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
flag: 1 << 3,
|
|
37
|
+
failure: "UNSUPPORTED_TIMING_PARAMS" /* AnimationFailureReasons.UNSUPPORTED_TIMING_PARAMS */,
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Returns a list of NoncompositedAnimationFailures.
|
|
42
|
+
*/
|
|
43
|
+
function getNonCompositedAnimations(animations) {
|
|
44
|
+
const failures = [];
|
|
45
|
+
for (const event of animations) {
|
|
46
|
+
const beginEvent = event.args.data.beginEvent;
|
|
47
|
+
const instantEvents = event.args.data.instantEvents || [];
|
|
48
|
+
/**
|
|
49
|
+
* Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').
|
|
50
|
+
* An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.
|
|
51
|
+
*/
|
|
52
|
+
for (const event of instantEvents) {
|
|
53
|
+
const failureMask = event.args.data.compositeFailed;
|
|
54
|
+
const unsupportedProperties = event.args.data.unsupportedProperties;
|
|
55
|
+
if (!failureMask || !unsupportedProperties) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const failureReasons = ACTIONABLE_FAILURE_REASONS.filter(reason => failureMask & reason.flag).map(reason => {
|
|
59
|
+
return reason.failure;
|
|
60
|
+
});
|
|
61
|
+
const failure = {
|
|
62
|
+
name: beginEvent.args.data.displayName,
|
|
63
|
+
failureReasons,
|
|
64
|
+
unsupportedProperties,
|
|
65
|
+
};
|
|
66
|
+
failures.push(failure);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return failures;
|
|
70
|
+
}
|
|
71
|
+
export function generateInsight(traceParsedData, context) {
|
|
72
|
+
const compositeAnimationEvents = traceParsedData.Animations.animations.filter(event => {
|
|
73
|
+
const nav = Helpers.Trace.getNavigationForTraceEvent(event, context.frameId, traceParsedData.Meta.navigationsByFrameId);
|
|
74
|
+
return nav?.args.data?.navigationId === context.navigationId;
|
|
75
|
+
});
|
|
76
|
+
const animationFailures = getNonCompositedAnimations(compositeAnimationEvents);
|
|
77
|
+
return {
|
|
78
|
+
animationFailures,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=CumulativeLayoutShift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CumulativeLayoutShift.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/CumulativeLayoutShift.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AASjD,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAChC,CAAC;AA2BD;;;;;GAKG;AACH,MAAM,0BAA0B,GAAG;IACjC;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,mFAAkD;KAC1D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,2FAAsD;KAC9D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,+EAAgD;KACxD;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,uFAAoD;KAC5D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,iFAAiD;KACzD;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,qFAAmD;KAC3D;CACF,CAAC;AAEF;;GAEG;AACH,SAAS,0BAA0B,CAAC,UAA+D;IAEjG,MAAM,QAAQ,GAAoC,EAAE,CAAC;IACrD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;QAC9C,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC;QAC1D;;;WAGG;QACH,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAClC,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;YACpD,MAAM,qBAAqB,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC;YACpE,IAAI,CAAC,WAAW,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC3C,SAAS;YACX,CAAC;YACD,MAAM,cAAc,GAAG,0BAA0B,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;gBACzG,OAAO,MAAM,CAAC,OAAO,CAAC;YACxB,CAAC,CAAC,CAAC;YACH,MAAM,OAAO,GAAkC;gBAC7C,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW;gBACtC,cAAc;gBACd,qBAAqB;aACtB,CAAC;YACF,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,eAA0C,EAAE,OAAiC;IAE3G,MAAM,wBAAwB,GAAG,eAAe,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACpF,MAAM,GAAG,GACL,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAChH,OAAO,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,YAAY,CAAC;IAC/D,CAAC,CAAC,CAAC;IACH,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,wBAAwB,CAAC,CAAC;IAC/E,OAAO;QACL,iBAAiB;KAClB,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n type InsightResult,\n type NavigationInsightContext,\n type RequiredData,\n} from './types.js';\n\nexport function deps(): ['Meta', 'Animations'] {\n return ['Meta', 'Animations'];\n}\n\nexport const enum AnimationFailureReasons {\n UNSUPPORTED_CSS_PROPERTY = 'UNSUPPORTED_CSS_PROPERTY',\n TRANSFROM_BOX_SIZE_DEPENDENT = 'TRANSFROM_BOX_SIZE_DEPENDENT',\n FILTER_MAY_MOVE_PIXELS = 'FILTER_MAY_MOVE_PIXELS',\n NON_REPLACE_COMPOSITE_MODE = 'NON_REPLACE_COMPOSITE_MODE',\n INCOMPATIBLE_ANIMATIONS = 'INCOMPATIBLE_ANIMATIONS',\n UNSUPPORTED_TIMING_PARAMS = 'UNSUPPORTED_TIMING_PARAMS',\n}\n\nexport interface NoncompositedAnimationFailure {\n /**\n * Animation name.\n */\n name?: string;\n /**\n * Failure reason based on mask number defined in\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22.\n */\n failureReasons: AnimationFailureReasons[];\n /**\n * Unsupported properties.\n */\n unsupportedProperties?: Types.TraceEvents.TraceEventAnimation['args']['data']['unsupportedProperties'];\n}\n\n/**\n * Each failure reason is represented by a bit flag. The bit shift operator '<<' is used to define\n * which bit corresponds to each failure reason.\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22\n * @type {{flag: number, failure: AnimationFailureReasons}[]}\n */\nconst ACTIONABLE_FAILURE_REASONS = [\n {\n flag: 1 << 13,\n failure: AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY,\n },\n {\n flag: 1 << 11,\n failure: AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT,\n },\n {\n flag: 1 << 12,\n failure: AnimationFailureReasons.FILTER_MAY_MOVE_PIXELS,\n },\n {\n flag: 1 << 4,\n failure: AnimationFailureReasons.NON_REPLACE_COMPOSITE_MODE,\n },\n {\n flag: 1 << 6,\n failure: AnimationFailureReasons.INCOMPATIBLE_ANIMATIONS,\n },\n {\n flag: 1 << 3,\n failure: AnimationFailureReasons.UNSUPPORTED_TIMING_PARAMS,\n },\n];\n\n/**\n * Returns a list of NoncompositedAnimationFailures.\n */\nfunction getNonCompositedAnimations(animations: readonly Types.TraceEvents.SyntheticAnimationPair[]):\n NoncompositedAnimationFailure[] {\n const failures: NoncompositedAnimationFailure[] = [];\n for (const event of animations) {\n const beginEvent = event.args.data.beginEvent;\n const instantEvents = event.args.data.instantEvents || [];\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n for (const event of instantEvents) {\n const failureMask = event.args.data.compositeFailed;\n const unsupportedProperties = event.args.data.unsupportedProperties;\n if (!failureMask || !unsupportedProperties) {\n continue;\n }\n const failureReasons = ACTIONABLE_FAILURE_REASONS.filter(reason => failureMask & reason.flag).map(reason => {\n return reason.failure;\n });\n const failure: NoncompositedAnimationFailure = {\n name: beginEvent.args.data.displayName,\n failureReasons,\n unsupportedProperties,\n };\n failures.push(failure);\n }\n }\n return failures;\n}\n\nexport function generateInsight(traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext):\n InsightResult<{animationFailures?: readonly NoncompositedAnimationFailure[]}> {\n const compositeAnimationEvents = traceParsedData.Animations.animations.filter(event => {\n const nav =\n Helpers.Trace.getNavigationForTraceEvent(event, context.frameId, traceParsedData.Meta.navigationsByFrameId);\n return nav?.args.data?.navigationId === context.navigationId;\n });\n const animationFailures = getNonCompositedAnimations(compositeAnimationEvents);\n return {\n animationFailures,\n };\n}\n"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * as CumulativeLayoutShift from './CumulativeLayoutShift.js';
|
|
1
2
|
export * as InteractionToNextPaint from './InteractionToNextPaint.js';
|
|
2
3
|
export * as LargestContentfulPaint from './LargestContentfulPaint.js';
|
|
3
4
|
export * as RenderBlocking from './RenderBlocking.js';
|
|
5
|
+
export * as Viewport from './Viewport.js';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// Copyright 2024 The Chromium Authors. All rights reserved.
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
+
export * as CumulativeLayoutShift from './CumulativeLayoutShift.js';
|
|
4
5
|
export * as InteractionToNextPaint from './InteractionToNextPaint.js';
|
|
5
6
|
export * as LargestContentfulPaint from './LargestContentfulPaint.js';
|
|
6
7
|
export * as RenderBlocking from './RenderBlocking.js';
|
|
8
|
+
export * as Viewport from './Viewport.js';
|
|
7
9
|
//# sourceMappingURL=InsightRunners.js.map
|