Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tools/profiler/convert-to-perfetto.ts
6435 views
1
const filename = Deno.args[0];
2
const frameSkip = Deno.args[1] === undefined ? 3 : Number(Deno.args[1]);
3
const file = Deno.readTextFileSync(filename);
4
5
let longestCommonPrefix: string | undefined = undefined;
6
// find the longest common prefix for source to trim
7
for (const fileLine of file.split("\n")) {
8
if (fileLine === "")
9
continue;
10
const entries = fileLine.split(" ");
11
if (entries.length === 4) {
12
continue;
13
}
14
const [_name, source] = fileLine.split(" ");
15
if (source === "=[C]") continue;
16
17
if (longestCommonPrefix === undefined) {
18
longestCommonPrefix = source;
19
} else {
20
// find the longest common prefix
21
let i = 0;
22
while (i < longestCommonPrefix.length && longestCommonPrefix[i] === source[i]) {
23
i++;
24
}
25
longestCommonPrefix = longestCommonPrefix.slice(0, i);
26
}
27
}
28
29
if (longestCommonPrefix === undefined) {
30
throw new Error("Internal error: no common prefix found");
31
}
32
33
type LuaStack = {
34
frames: LuaStackFrame[];
35
time: number;
36
line: number;
37
category: string;
38
}
39
40
type LuaStackFrame = {
41
location: string;
42
// name: string;
43
// source: string;
44
// line: number;
45
}
46
47
const stacks: LuaStack[] = [];
48
let stackNum = "";
49
let time = 0;
50
let thisStack: LuaStackFrame[] = [];
51
let category = "";
52
53
for (const fileLine of file.split("\n")) {
54
if (fileLine === "") continue;
55
const entries = fileLine.split(" ");
56
if (entries.length === 4) {
57
category = entries[2];
58
if (stackNum !== entries[0]) {
59
if (thisStack.length) {
60
thisStack[0].location = `${thisStack[0].location}:${entries[3]}`;
61
}
62
stacks.push({
63
frames: thisStack,
64
time: Number(entries[1]),
65
line: Number(entries[3]),
66
category
67
});
68
thisStack = [];
69
stackNum = entries[0];
70
}
71
continue;
72
}
73
const [name, source, line] = fileLine.split(" ");
74
try {
75
const frame: LuaStackFrame = {
76
location: `${source.slice(longestCommonPrefix.length)}:${line}:${name}`,
77
};
78
thisStack.push(frame);
79
} catch (_e) {
80
throw new Error(`Error parsing line: ${fileLine}`);
81
}
82
}
83
84
// add a sentinel stack to make sure the last stack is also output
85
stacks.push({
86
frames: [],
87
time,
88
line: 0,
89
category: ""
90
});
91
92
// convert these to chrome://tracing format
93
type Frame = {
94
name: string;
95
parent?: string;
96
}
97
98
type TraceEvent = {
99
name: string;
100
sf: string;
101
ph: string;
102
ts: number;
103
cat?: string;
104
}
105
106
const stackFrames: Record<number, Frame> = {};
107
let stackNo = 0;
108
const traceEvents: TraceEvent[] = [];
109
let prevStack: LuaStackFrame[] = [];
110
let prevCat: string = "";
111
const perfettoStack: number[] = [];
112
113
let now = 0;
114
for (const stack of stacks) {
115
debugger;
116
const thisStackFrames = stack.frames.toReversed().slice(frameSkip);
117
118
let overlappingI = 0;
119
while (overlappingI < thisStackFrames.length && overlappingI < prevStack.length) {
120
if (thisStackFrames[overlappingI].location !== prevStack[overlappingI].location ||
121
stack.category !== prevCat) {
122
break;
123
}
124
overlappingI++;
125
}
126
// pop off the stack
127
for (let i = prevStack.length - 1; i >= overlappingI; --i) {
128
const prevFrame = prevStack[i];
129
let newNow = stack.time * 1000000;
130
if (newNow <= now) {
131
newNow = now + 1;
132
}
133
now = newNow;
134
135
traceEvents.push({
136
ph: "E",
137
name: prevFrame.location,
138
sf: String(perfettoStack.pop()),
139
ts: now,
140
cat: prevCat !== "" ? prevCat : undefined
141
});
142
}
143
144
// push on the stack
145
for (let i = overlappingI; i < thisStackFrames.length; ++i) {
146
const nextFrame = thisStackFrames[i];
147
let newNow = stack.time * 1000000;
148
if (newNow <= now) {
149
newNow = now + 1;
150
}
151
now = newNow;
152
stackFrames[stackNo] = {
153
name: nextFrame.location,
154
parent: perfettoStack.length ? String(perfettoStack[perfettoStack.length - 1]) : undefined
155
}
156
traceEvents.push({
157
ph: "B",
158
name: nextFrame.location,
159
sf: String(stackNo),
160
ts: newNow,
161
cat: stack.category !== "" ? stack.category : undefined
162
});
163
perfettoStack.push(stackNo++);
164
}
165
prevStack = thisStackFrames;
166
prevCat = stack.category;
167
}
168
169
console.log(JSON.stringify({ traceEvents, stackFrames }, null, 2));
170