@paulirish/trace_engine 0.0.5 → 0.0.6
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/PAUL.readme.md +5 -0
- package/README.md +25 -5
- package/analyze-trace.mjs +16 -7
- package/package.json +3 -2
- package/test/test-trace-engine.mjs +52 -0
- package/trace.mjs +43 -16
- package/trace.mjs.map +2 -2
- package/09-06/meta.json +0 -989
- package/09-06/trace.mjs +0 -5681
- package/09-06/trace.mjs.map +0 -7
- package/CONTRIBUTING.md +0 -5
- package/meta.json +0 -996
package/PAUL.readme.md
ADDED
package/README.md
CHANGED
|
@@ -18,19 +18,39 @@ console.log(processor.data)
|
|
|
18
18
|
|
|
19
19
|
See the included `analyze-trace.mjs` a runnable invocation.
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Maintainer cheatsheet
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
# parent doc: go/btlax
|
|
23
|
+
See also http://go/btlax
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
#### Build, run, extract
|
|
27
26
|
|
|
27
|
+
```sh
|
|
28
|
+
# build bundle with esbuild
|
|
28
29
|
front_end/models/trace/build-trace-engine-lib.sh
|
|
29
30
|
|
|
31
|
+
# run
|
|
32
|
+
node scripts/analyze-trace.mjs test/unittests/fixtures/traces/web-dev.json.gz
|
|
33
|
+
|
|
34
|
+
# test
|
|
35
|
+
node scripts/test/test-trace-engine.mjs
|
|
36
|
+
|
|
37
|
+
# copy built files to $HOME/code/trace_engine
|
|
30
38
|
front_end/models/trace/copy-build-trace-engine-for-publish.sh
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### Test and publish
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
# switch to standalone
|
|
45
|
+
cd $HOME/code/trace_engine
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
# test
|
|
48
|
+
node test/test-trace-engine.mjs
|
|
33
49
|
|
|
50
|
+
# bump and publish
|
|
51
|
+
npm version v0.0.XXX # Manually determine next version
|
|
52
|
+
npm publish --access public --dry-run
|
|
53
|
+
npm publish --access public
|
|
34
54
|
```
|
|
35
55
|
|
|
36
56
|
## High level architecture
|
package/analyze-trace.mjs
CHANGED
|
@@ -5,26 +5,35 @@
|
|
|
5
5
|
// Run this first:
|
|
6
6
|
// front_end/models/trace/build-trace-engine-lib.sh
|
|
7
7
|
|
|
8
|
-
import fs from 'fs';
|
|
9
|
-
import zlib from 'zlib';
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import zlib from 'node:zlib';
|
|
10
10
|
// eslint-disable-next-line rulesdir/es_modules_import
|
|
11
11
|
import * as TraceModel from './trace.mjs';
|
|
12
12
|
|
|
13
13
|
polyfillDOMRect();
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const filename = process.argv.at(2) ?? './test/invalid-animation-events.json.gz';
|
|
15
|
+
|
|
16
|
+
export async function analyzeTrace(filename) {
|
|
18
17
|
const traceEvents = loadTraceEventsFromFile(filename);
|
|
19
18
|
|
|
20
19
|
// Primary usage:
|
|
21
20
|
const processor = TraceModel.Processor.TraceProcessor.createWithAllHandlers(); // aka `fullTraceEngine`
|
|
22
21
|
await processor.parse(traceEvents);
|
|
22
|
+
return processor.data;
|
|
23
|
+
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
// If run as CLI, parse the argv trace (or a fallback)
|
|
26
|
+
if (import.meta.url.endsWith(process?.argv[1])) {
|
|
27
|
+
cli();
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
async function cli() {
|
|
31
|
+
const filename = process.argv.at(2);
|
|
32
|
+
const traceModel = await analyzeTrace(filename);
|
|
33
|
+
console.log(traceModel);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
28
37
|
/**
|
|
29
38
|
* @param {string=} filename
|
|
30
39
|
* @returns TraceEvent[]
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paulirish/trace_engine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "trace.mjs",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node
|
|
7
|
+
"test": "node test/test-trace-engine.mjs",
|
|
8
|
+
"prepublishOnly": "npm test"
|
|
8
9
|
},
|
|
9
10
|
"type": "module",
|
|
10
11
|
"keywords": [],
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright 2023 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
|
+
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
import {strict as assert} from 'assert';
|
|
7
|
+
|
|
8
|
+
import {analyzeTrace} from '../analyze-trace.mjs';
|
|
9
|
+
|
|
10
|
+
const filename = './test/invalid-animation-events.json.gz';
|
|
11
|
+
const data = await analyzeTrace(filename);
|
|
12
|
+
|
|
13
|
+
test('key values are populated', t => {
|
|
14
|
+
assert.equal(data.Renderer.allRendererEvents.length > 90_000, true);
|
|
15
|
+
assert.equal(data.Screenshots.length > 2, true);
|
|
16
|
+
assert.equal(data.Meta.threadsInProcess.size > 2, true);
|
|
17
|
+
assert.equal(data.Meta.mainFrameNavigations.length > 0, true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('numeric values are set and look legit', t => {
|
|
21
|
+
const shouldBeNumbers = [
|
|
22
|
+
data.Meta.traceBounds.min,
|
|
23
|
+
data.Meta.traceBounds.max,
|
|
24
|
+
data.Meta.traceBounds.range,
|
|
25
|
+
data.Meta.browserProcessId,
|
|
26
|
+
data.Meta.browserThreadId,
|
|
27
|
+
data.Meta.gpuProcessId,
|
|
28
|
+
data.Meta.gpuThreadId,
|
|
29
|
+
Array.from(data.Meta.topLevelRendererIds.values()).at(0),
|
|
30
|
+
Array.from(data.Meta.frameByProcessId.keys()).at(0),
|
|
31
|
+
];
|
|
32
|
+
for (const datum of shouldBeNumbers) {
|
|
33
|
+
assert.equal(isNaN(datum), false);
|
|
34
|
+
assert.equal(typeof datum, 'number');
|
|
35
|
+
assert.equal(datum > 10, true);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('string values are set and look legit', t => {
|
|
40
|
+
const shouldBeStrings = [
|
|
41
|
+
data.Meta.mainFrameId,
|
|
42
|
+
data.Meta.mainFrameURL,
|
|
43
|
+
Array.from(data.Meta.navigationsByFrameId.keys()).at(0),
|
|
44
|
+
Array.from(data.Meta.navigationsByNavigationId.keys()).at(0),
|
|
45
|
+
data.Meta.mainFrameId,
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
for (const datum of shouldBeStrings) {
|
|
49
|
+
assert.equal(typeof datum, 'string');
|
|
50
|
+
assert.equal(datum.length > 10, true);
|
|
51
|
+
}
|
|
52
|
+
});
|
package/trace.mjs
CHANGED
|
@@ -2040,18 +2040,34 @@ function walkTreeFromEntry(entryToNode3, rootEntry, onEntryStart, onEntryEnd) {
|
|
|
2040
2040
|
}
|
|
2041
2041
|
walkTreeByNode(entryToNode3, startNode, onEntryStart, onEntryEnd);
|
|
2042
2042
|
}
|
|
2043
|
-
function walkEntireTree(entryToNode3, tree, onEntryStart, onEntryEnd) {
|
|
2043
|
+
function walkEntireTree(entryToNode3, tree, onEntryStart, onEntryEnd, traceWindowToInclude) {
|
|
2044
2044
|
for (const rootNode of tree.roots) {
|
|
2045
|
-
walkTreeByNode(entryToNode3, rootNode, onEntryStart, onEntryEnd);
|
|
2045
|
+
walkTreeByNode(entryToNode3, rootNode, onEntryStart, onEntryEnd, traceWindowToInclude);
|
|
2046
2046
|
}
|
|
2047
2047
|
}
|
|
2048
|
-
function walkTreeByNode(entryToNode3, rootNode, onEntryStart, onEntryEnd) {
|
|
2048
|
+
function walkTreeByNode(entryToNode3, rootNode, onEntryStart, onEntryEnd, traceWindowToInclude) {
|
|
2049
|
+
if (traceWindowToInclude && !treeNodeIsInWindow(rootNode, traceWindowToInclude)) {
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2049
2052
|
onEntryStart(rootNode.entry);
|
|
2050
2053
|
for (const child of rootNode.children) {
|
|
2051
|
-
walkTreeByNode(entryToNode3, child, onEntryStart, onEntryEnd);
|
|
2054
|
+
walkTreeByNode(entryToNode3, child, onEntryStart, onEntryEnd, traceWindowToInclude);
|
|
2052
2055
|
}
|
|
2053
2056
|
onEntryEnd(rootNode.entry);
|
|
2054
2057
|
}
|
|
2058
|
+
function treeNodeIsInWindow(node, traceWindow) {
|
|
2059
|
+
const { startTime, endTime } = eventTimingsMicroSeconds(node.entry);
|
|
2060
|
+
if (startTime >= traceWindow.min && startTime < traceWindow.max) {
|
|
2061
|
+
return true;
|
|
2062
|
+
}
|
|
2063
|
+
if (endTime > traceWindow.min && endTime <= traceWindow.max) {
|
|
2064
|
+
return true;
|
|
2065
|
+
}
|
|
2066
|
+
if (startTime <= traceWindow.min && endTime >= traceWindow.max) {
|
|
2067
|
+
return true;
|
|
2068
|
+
}
|
|
2069
|
+
return false;
|
|
2070
|
+
}
|
|
2055
2071
|
|
|
2056
2072
|
// front_end/models/trace/handlers/GPUHandler.ts
|
|
2057
2073
|
var handlerState3 = 1 /* UNINITIALIZED */;
|
|
@@ -3303,6 +3319,8 @@ __export(WarningsHandler_exports, {
|
|
|
3303
3319
|
FORCED_LAYOUT_AND_STYLES_THRESHOLD: () => FORCED_LAYOUT_AND_STYLES_THRESHOLD,
|
|
3304
3320
|
LONG_MAIN_THREAD_TASK_THRESHOLD: () => LONG_MAIN_THREAD_TASK_THRESHOLD,
|
|
3305
3321
|
data: () => data12,
|
|
3322
|
+
deps: () => deps6,
|
|
3323
|
+
finalize: () => finalize11,
|
|
3306
3324
|
handleEvent: () => handleEvent12,
|
|
3307
3325
|
reset: () => reset12
|
|
3308
3326
|
});
|
|
@@ -3350,6 +3368,15 @@ function handleEvent12(event) {
|
|
|
3350
3368
|
return;
|
|
3351
3369
|
}
|
|
3352
3370
|
}
|
|
3371
|
+
function deps6() {
|
|
3372
|
+
return ["UserInteractions"];
|
|
3373
|
+
}
|
|
3374
|
+
async function finalize11() {
|
|
3375
|
+
const longInteractions = data10().interactionsOverThreshold;
|
|
3376
|
+
for (const interaction of longInteractions) {
|
|
3377
|
+
storeWarning(interaction, "LONG_INTERACTION");
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3353
3380
|
function data12() {
|
|
3354
3381
|
return {
|
|
3355
3382
|
perEvent: new Map(warningsPerEvent),
|
|
@@ -3361,7 +3388,7 @@ function data12() {
|
|
|
3361
3388
|
var WorkersHandler_exports = {};
|
|
3362
3389
|
__export(WorkersHandler_exports, {
|
|
3363
3390
|
data: () => data13,
|
|
3364
|
-
finalize: () =>
|
|
3391
|
+
finalize: () => finalize12,
|
|
3365
3392
|
handleEvent: () => handleEvent13,
|
|
3366
3393
|
initialize: () => initialize5,
|
|
3367
3394
|
reset: () => reset13
|
|
@@ -3389,7 +3416,7 @@ function handleEvent13(event) {
|
|
|
3389
3416
|
sessionIdEvents.push(event);
|
|
3390
3417
|
}
|
|
3391
3418
|
}
|
|
3392
|
-
async function
|
|
3419
|
+
async function finalize12() {
|
|
3393
3420
|
if (handlerState8 !== 2 /* INITIALIZED */) {
|
|
3394
3421
|
throw new Error("Handler is not initialized");
|
|
3395
3422
|
}
|
|
@@ -3508,8 +3535,8 @@ __export(RendererHandler_exports, {
|
|
|
3508
3535
|
assignThreadName: () => assignThreadName,
|
|
3509
3536
|
buildHierarchy: () => buildHierarchy,
|
|
3510
3537
|
data: () => data17,
|
|
3511
|
-
deps: () =>
|
|
3512
|
-
finalize: () =>
|
|
3538
|
+
deps: () => deps7,
|
|
3539
|
+
finalize: () => finalize14,
|
|
3513
3540
|
handleEvent: () => handleEvent17,
|
|
3514
3541
|
handleUserConfig: () => handleUserConfig,
|
|
3515
3542
|
initialize: () => initialize7,
|
|
@@ -3523,7 +3550,7 @@ __export(RendererHandler_exports, {
|
|
|
3523
3550
|
var SamplesHandler_exports = {};
|
|
3524
3551
|
__export(SamplesHandler_exports, {
|
|
3525
3552
|
data: () => data16,
|
|
3526
|
-
finalize: () =>
|
|
3553
|
+
finalize: () => finalize13,
|
|
3527
3554
|
getProfileCallFunctionName: () => getProfileCallFunctionName,
|
|
3528
3555
|
handleEvent: () => handleEvent16,
|
|
3529
3556
|
initialize: () => initialize6,
|
|
@@ -3682,7 +3709,7 @@ var CPUProfileDataModel = class extends ProfileTreeModel {
|
|
|
3682
3709
|
this.profileHead = this.translateProfileTree(profile.nodes);
|
|
3683
3710
|
this.initialize(this.profileHead);
|
|
3684
3711
|
this.extractMetaNodes();
|
|
3685
|
-
if (this.samples) {
|
|
3712
|
+
if (this.samples?.length) {
|
|
3686
3713
|
this.sortSamples();
|
|
3687
3714
|
this.normalizeTimestamps();
|
|
3688
3715
|
this.fixMissingSamples();
|
|
@@ -4138,7 +4165,7 @@ function handleEvent16(event) {
|
|
|
4138
4165
|
return;
|
|
4139
4166
|
}
|
|
4140
4167
|
}
|
|
4141
|
-
async function
|
|
4168
|
+
async function finalize13() {
|
|
4142
4169
|
if (handlerState9 !== 2 /* INITIALIZED */) {
|
|
4143
4170
|
throw new Error("Samples Handler is not initialized");
|
|
4144
4171
|
}
|
|
@@ -4245,7 +4272,7 @@ function handleEvent17(event) {
|
|
|
4245
4272
|
allRendererEvents.push(event);
|
|
4246
4273
|
}
|
|
4247
4274
|
}
|
|
4248
|
-
async function
|
|
4275
|
+
async function finalize14() {
|
|
4249
4276
|
if (handlerState10 !== 2 /* INITIALIZED */) {
|
|
4250
4277
|
throw new Error("Renderer Handler is not initialized");
|
|
4251
4278
|
}
|
|
@@ -4389,7 +4416,7 @@ function makeCompleteEvent(event) {
|
|
|
4389
4416
|
completeEventStack.push(syntheticComplete);
|
|
4390
4417
|
return syntheticComplete;
|
|
4391
4418
|
}
|
|
4392
|
-
function
|
|
4419
|
+
function deps7() {
|
|
4393
4420
|
return ["Meta", "Samples", "AuctionWorklets"];
|
|
4394
4421
|
}
|
|
4395
4422
|
|
|
@@ -5281,9 +5308,9 @@ function sortHandlers(traceHandlers) {
|
|
|
5281
5308
|
if (!handler) {
|
|
5282
5309
|
return;
|
|
5283
5310
|
}
|
|
5284
|
-
const
|
|
5285
|
-
if (
|
|
5286
|
-
|
|
5311
|
+
const deps8 = handler.deps?.();
|
|
5312
|
+
if (deps8) {
|
|
5313
|
+
deps8.forEach(visitHandler);
|
|
5287
5314
|
}
|
|
5288
5315
|
sortedMap.set(handlerName, handler);
|
|
5289
5316
|
};
|