@electron-stagewright/plugin-budget 0.0.0-stage → 0.2.0

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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +214 -2
  3. package/dist/budget.d.ts +143 -0
  4. package/dist/budget.d.ts.map +1 -0
  5. package/dist/budget.js +134 -0
  6. package/dist/budget.js.map +1 -0
  7. package/dist/bundle.d.ts +15 -0
  8. package/dist/bundle.d.ts.map +1 -0
  9. package/dist/bundle.js +64 -0
  10. package/dist/bundle.js.map +1 -0
  11. package/dist/check-api.d.ts +15 -0
  12. package/dist/check-api.d.ts.map +1 -0
  13. package/dist/check-api.js +11 -0
  14. package/dist/check-api.js.map +1 -0
  15. package/dist/check.d.ts +50 -0
  16. package/dist/check.d.ts.map +1 -0
  17. package/dist/check.js +198 -0
  18. package/dist/check.js.map +1 -0
  19. package/dist/cli.d.ts +85 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +464 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/index.d.ts +24 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +17 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/measure.d.ts +81 -0
  28. package/dist/measure.d.ts.map +1 -0
  29. package/dist/measure.js +269 -0
  30. package/dist/measure.js.map +1 -0
  31. package/dist/memory.d.ts +43 -0
  32. package/dist/memory.d.ts.map +1 -0
  33. package/dist/memory.js +159 -0
  34. package/dist/memory.js.map +1 -0
  35. package/dist/plugin.d.ts +13 -0
  36. package/dist/plugin.d.ts.map +1 -0
  37. package/dist/plugin.js +456 -0
  38. package/dist/plugin.js.map +1 -0
  39. package/dist/probe.d.ts +74 -0
  40. package/dist/probe.d.ts.map +1 -0
  41. package/dist/probe.js +181 -0
  42. package/dist/probe.js.map +1 -0
  43. package/dist/render.d.ts +21 -0
  44. package/dist/render.d.ts.map +1 -0
  45. package/dist/render.js +63 -0
  46. package/dist/render.js.map +1 -0
  47. package/dist/run.d.ts +267 -0
  48. package/dist/run.d.ts.map +1 -0
  49. package/dist/run.js +257 -0
  50. package/dist/run.js.map +1 -0
  51. package/dist/session.d.ts +79 -0
  52. package/dist/session.d.ts.map +1 -0
  53. package/dist/session.js +263 -0
  54. package/dist/session.js.map +1 -0
  55. package/package.json +67 -3
package/dist/run.js ADDED
@@ -0,0 +1,257 @@
1
+ /**
2
+ * The run document: raw measurements of one build, and the flat summary `check` and `compare` read.
3
+ *
4
+ * @module
5
+ */
6
+ import { readFile } from 'node:fs/promises';
7
+ import { z } from 'zod';
8
+ import { MEMORY_METRICS, PHASES, PROCESS_TYPES } from './budget.js';
9
+ export const RUN_FORMAT = 'electron-stagewright-budget-run';
10
+ export const RUN_SCHEMA_VERSION = 1;
11
+ const stallSchema = z.object({
12
+ windowMs: z.number(),
13
+ blockedMs: z.number(),
14
+ blockedPercent: z.number(),
15
+ maxStallMs: z.number(),
16
+ stallsOver50Ms: z.number(),
17
+ stallsOver100Ms: z.number(),
18
+ });
19
+ const latencySchema = z.object({
20
+ count: z.number(),
21
+ p50: z.number(),
22
+ p95: z.number(),
23
+ p99: z.number(),
24
+ max: z.number(),
25
+ });
26
+ const processSchema = z.object({
27
+ pid: z.number(),
28
+ type: z.enum(PROCESS_TYPES),
29
+ name: z.string().optional(),
30
+ // In the run's `metric`; absent when the OS reader could not see this pid.
31
+ mb: z.number().optional(),
32
+ workingSetMb: z.number(),
33
+ });
34
+ const memorySchema = z.object({
35
+ metric: z.enum(MEMORY_METRICS),
36
+ processes: z.array(processSchema),
37
+ });
38
+ const measurementSchema = z.object({
39
+ startup: z.object({ firstWindowMs: z.number() }).optional(),
40
+ memory: memorySchema.optional(),
41
+ // The sample with the most memory outside the GPU during the window, when it was sampled.
42
+ memoryPeak: memorySchema.optional(),
43
+ mainThread: stallSchema.optional(),
44
+ ipc: latencySchema.optional(),
45
+ // Why a requested metric is missing, keyed by `startup` / `memory` / `mainThread` / `ipc`.
46
+ unavailable: z.record(z.string(), z.string()).optional(),
47
+ });
48
+ const bundleEntrySchema = z.object({
49
+ id: z.string(),
50
+ path: z.string(),
51
+ gzip: z.boolean(),
52
+ files: z.number(),
53
+ bytes: z.number(),
54
+ unavailable: z.string().optional(),
55
+ });
56
+ export const runSchema = z.object({
57
+ format: z.literal(RUN_FORMAT),
58
+ schema_version: z.literal(RUN_SCHEMA_VERSION),
59
+ created_at: z.string(),
60
+ platform: z.string(),
61
+ arch: z.string(),
62
+ electron_version: z.string().optional(),
63
+ label: z.string().optional(),
64
+ rounds: z.array(z.object({ round: z.number(), phase: z.enum(PHASES), measurement: measurementSchema })),
65
+ bundle: z.object({ entries: z.array(bundleEntrySchema) }).optional(),
66
+ });
67
+ /** A run file that is missing or is not a run document. */
68
+ export class RunFileError extends Error {
69
+ runPath;
70
+ constructor(message, runPath) {
71
+ super(message);
72
+ this.runPath = runPath;
73
+ this.name = 'RunFileError';
74
+ }
75
+ }
76
+ export async function loadRun(runPath) {
77
+ let raw;
78
+ try {
79
+ raw = JSON.parse(await readFile(runPath, 'utf8'));
80
+ }
81
+ catch (error) {
82
+ throw new RunFileError(`Cannot read run file ${runPath}: ${error instanceof Error ? error.message : String(error)}`, runPath);
83
+ }
84
+ const parsed = runSchema.safeParse(raw);
85
+ if (!parsed.success) {
86
+ const issues = parsed.error.issues
87
+ .map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`)
88
+ .join('; ');
89
+ throw new RunFileError(`${runPath} is not a ${RUN_FORMAT} document: ${issues}`, runPath);
90
+ }
91
+ return parsed.data;
92
+ }
93
+ export function createRun(fields) {
94
+ return {
95
+ format: RUN_FORMAT,
96
+ schema_version: RUN_SCHEMA_VERSION,
97
+ created_at: (fields.now ?? new Date()).toISOString(),
98
+ platform: process.platform,
99
+ arch: process.arch,
100
+ ...(fields.electronVersion === undefined ? {} : { electron_version: fields.electronVersion }),
101
+ ...(fields.label === undefined ? {} : { label: fields.label }),
102
+ rounds: fields.rounds,
103
+ ...(fields.bundle === undefined ? {} : { bundle: fields.bundle }),
104
+ };
105
+ }
106
+ /**
107
+ * One run from several, rounds numbered in order, so a check takes the median across all of them.
108
+ * Every run must come from the same platform; the first Electron version, label and bundle win.
109
+ */
110
+ export function mergeRuns(runs) {
111
+ const [first] = runs;
112
+ if (first === undefined)
113
+ throw new Error('mergeRuns needs at least one run');
114
+ const other = runs.find((run) => run.platform !== first.platform || run.arch !== first.arch);
115
+ if (other !== undefined) {
116
+ throw new Error(`cannot merge runs from ${first.platform}-${first.arch} and ${other.platform}-${other.arch}`);
117
+ }
118
+ let round = 0;
119
+ const electronVersion = runs.find((run) => run.electron_version !== undefined)?.electron_version;
120
+ const label = runs.find((run) => run.label !== undefined)?.label;
121
+ const bundle = runs.find((run) => run.bundle !== undefined)?.bundle;
122
+ return {
123
+ format: RUN_FORMAT,
124
+ schema_version: RUN_SCHEMA_VERSION,
125
+ created_at: first.created_at,
126
+ platform: first.platform,
127
+ arch: first.arch,
128
+ ...(electronVersion === undefined ? {} : { electron_version: electronVersion }),
129
+ ...(label === undefined ? {} : { label }),
130
+ // Each run numbers its rounds from 1; a run's cold and warm launch share a round.
131
+ rounds: runs.flatMap((run) => {
132
+ const offset = round;
133
+ const numbers = run.rounds.map((entry) => entry.round);
134
+ round += numbers.length === 0 ? 0 : Math.max(...numbers);
135
+ return run.rounds.map((entry) => ({ ...entry, round: entry.round + offset }));
136
+ }),
137
+ ...(bundle === undefined ? {} : { bundle }),
138
+ };
139
+ }
140
+ const round1 = (value) => Math.round(value * 10) / 10;
141
+ export function median(values) {
142
+ const sorted = [...values].sort((a, b) => a - b);
143
+ const middle = Math.floor(sorted.length / 2);
144
+ const upper = sorted[middle] ?? 0;
145
+ return sorted.length % 2 === 1 ? upper : ((sorted[middle - 1] ?? upper) + upper) / 2;
146
+ }
147
+ /** Nearest-rank percentiles; an empty set reports zeros with `count: 0`. */
148
+ export function summarizeLatencies(samples) {
149
+ const sorted = samples.filter(Number.isFinite).sort((a, b) => a - b);
150
+ const at = (percentile) => round1(sorted[Math.min(sorted.length - 1, Math.ceil((percentile / 100) * sorted.length) - 1)] ?? 0);
151
+ return { count: sorted.length, p50: at(50), p95: at(95), p99: at(99), max: at(100) };
152
+ }
153
+ /**
154
+ * Megabytes per process type for one memory sample, in the sample's metric. A type with a pid the
155
+ * OS reader could not see is left out rather than undercounted.
156
+ */
157
+ export function memoryByType(memory) {
158
+ const totals = {};
159
+ const partial = new Set();
160
+ for (const entry of memory.processes) {
161
+ const mb = memory.metric === 'workingSet' ? entry.workingSetMb : entry.mb;
162
+ if (mb === undefined)
163
+ partial.add(entry.type);
164
+ else
165
+ totals[entry.type] = (totals[entry.type] ?? 0) + mb;
166
+ }
167
+ for (const type of partial)
168
+ delete totals[type];
169
+ return totals;
170
+ }
171
+ /** Sum of every type the sample holds, or undefined when one of them is unmeasured or none exist. */
172
+ export function memoryTotal(memory, skipGpu) {
173
+ const types = new Set(memory.processes.map((entry) => entry.type));
174
+ if (skipGpu)
175
+ types.delete('gpu');
176
+ if (types.size === 0)
177
+ return undefined;
178
+ const totals = memoryByType(memory);
179
+ let sum = 0;
180
+ for (const type of types) {
181
+ const mb = totals[type];
182
+ if (mb === undefined)
183
+ return undefined;
184
+ sum += mb;
185
+ }
186
+ return sum;
187
+ }
188
+ function pushMemory(prefix, memories, push) {
189
+ // Rounds whose OS reader failed fall back to another metric; the majority one is summarised.
190
+ const counts = new Map();
191
+ for (const memory of memories)
192
+ counts.set(memory.metric, (counts.get(memory.metric) ?? 0) + 1);
193
+ let primary;
194
+ for (const { metric } of memories) {
195
+ if (primary === undefined || (counts.get(metric) ?? 0) > (counts.get(primary) ?? 0)) {
196
+ primary = metric;
197
+ }
198
+ }
199
+ // Working set is always recorded, so a budget may name it on any platform.
200
+ for (const metric of new Set([primary, 'workingSet'])) {
201
+ if (metric === undefined)
202
+ continue;
203
+ const sameMetric = memories
204
+ .filter((memory) => memory.metric === primary)
205
+ .map((memory) => ({ ...memory, metric }));
206
+ const byType = sameMetric.map(memoryByType);
207
+ for (const type of PROCESS_TYPES) {
208
+ push(`${prefix}.${type}`, 'MB', byType.map((totals) => totals[type]), metric);
209
+ }
210
+ push(`${prefix}.totalWithoutGpu`, 'MB', sameMetric.map((memory) => memoryTotal(memory, true)), metric);
211
+ push(`${prefix}.total`, 'MB', sameMetric.map((memory) => memoryTotal(memory, false)), metric);
212
+ }
213
+ }
214
+ /** Flatten a run into comparable rows (`memory.main`, `ipc.p99Ms`, `bundle.<id>`, ...). */
215
+ export function summarizeRun(run) {
216
+ const rows = [];
217
+ for (const phase of PHASES) {
218
+ const measurements = run.rounds.filter((r) => r.phase === phase).map((r) => r.measurement);
219
+ const push = (id, unit, values, metric) => {
220
+ const present = values.filter((value) => value !== undefined);
221
+ if (present.length === 0)
222
+ return;
223
+ const exact = median(present);
224
+ rows.push({
225
+ id,
226
+ phase,
227
+ value: round1(exact),
228
+ exact,
229
+ unit,
230
+ ...(metric === undefined ? {} : { metric }),
231
+ samples: present.length,
232
+ });
233
+ };
234
+ push('startup.firstWindowMs', 'ms', measurements.map((m) => m.startup?.firstWindowMs));
235
+ pushMemory('memory', measurements.flatMap((m) => (m.memory === undefined ? [] : [m.memory])), push);
236
+ pushMemory('memoryPeak', measurements.flatMap((m) => (m.memoryPeak === undefined ? [] : [m.memoryPeak])), push);
237
+ push('mainThread.blockedPercent', '%', measurements.map((m) => m.mainThread?.blockedPercent));
238
+ push('mainThread.maxStallMs', 'ms', measurements.map((m) => m.mainThread?.maxStallMs));
239
+ const ipc = measurements.flatMap((m) => (m.ipc !== undefined && m.ipc.count > 0 ? [m.ipc] : []));
240
+ push('ipc.p95Ms', 'ms', ipc.map((latency) => latency.p95));
241
+ push('ipc.p99Ms', 'ms', ipc.map((latency) => latency.p99));
242
+ }
243
+ for (const entry of run.bundle?.entries ?? []) {
244
+ if (entry.unavailable !== undefined)
245
+ continue;
246
+ rows.push({
247
+ id: `bundle.${entry.id}`,
248
+ value: round1(entry.bytes / 1024),
249
+ exact: entry.bytes / 1024,
250
+ unit: 'KB',
251
+ ...(entry.gzip ? { metric: 'gzip' } : {}),
252
+ samples: 1,
253
+ });
254
+ }
255
+ return rows;
256
+ }
257
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Measure one live app session through the transport's `evaluate` seam.
3
+ *
4
+ * @module
5
+ */
6
+ import { type HostStartTimeReader, type OsMemoryReader } from './memory.js';
7
+ import { type Measurement, type MemoryMeasurement } from './run.js';
8
+ /** The slice of a transport session the budget needs. */
9
+ export interface EvaluatingSession {
10
+ evaluate<T = unknown>(target: 'main' | 'renderer', body: string, arg?: unknown): Promise<T>;
11
+ }
12
+ export interface IpcProbe {
13
+ readonly probe: string;
14
+ readonly intervalMs?: number;
15
+ }
16
+ export declare const MAIN_EVAL_OFF = "main eval is off; start the server with --allow-eval=main (or bare --allow-eval)";
17
+ export declare const RENDERER_EVAL_OFF = "renderer eval is off; start the server with bare --allow-eval to measure it";
18
+ /**
19
+ * Open a measurement window: arm the main-thread sampler and, when a probe is given and renderer
20
+ * eval is allowed, the IPC probe loop. Returns why the IPC probe did not start, if it did not.
21
+ */
22
+ export declare function startWindow(session: EvaluatingSession, options: {
23
+ readonly ipc?: IpcProbe;
24
+ readonly allowRenderer: boolean;
25
+ /** Why the renderer is off, when it is not the eval grant. */
26
+ readonly rendererOff?: string;
27
+ /** Set when main eval is unavailable: only the IPC probe starts. */
28
+ readonly mainUnavailable?: string;
29
+ }): Promise<{
30
+ ipc: boolean;
31
+ ipcUnavailable?: string;
32
+ }>;
33
+ export interface MeasureOptions {
34
+ readonly allowRenderer: boolean;
35
+ readonly rendererOff?: string;
36
+ /** Set when {@link startWindow} already opened a window; otherwise one is run for `windowMs`. */
37
+ readonly open?: {
38
+ readonly ipc: boolean;
39
+ readonly ipcUnavailable?: string;
40
+ };
41
+ readonly windowMs: number;
42
+ readonly ipc?: IpcProbe;
43
+ readonly sleep?: (ms: number) => Promise<void>;
44
+ readonly memoryReader?: OsMemoryReader;
45
+ readonly hostStartTime?: HostStartTimeReader;
46
+ /** The renderer grant alone; defaults to `allowRenderer`. */
47
+ readonly allowStartup?: boolean;
48
+ /**
49
+ * Why main eval is unavailable (a build with the EnableNodeCliInspectArguments fuse off). Memory
50
+ * then comes from `memoryProbe` through the renderer; blocking and startup are unmeasured.
51
+ */
52
+ readonly mainUnavailable?: string;
53
+ readonly memoryProbe?: string;
54
+ }
55
+ /** How a sampler reads memory: from main, or through the app's renderer memory probe. */
56
+ export interface MemorySource {
57
+ readonly mainUnavailable?: string;
58
+ readonly memoryProbe?: string;
59
+ readonly allowRenderer: boolean;
60
+ readonly memoryReader?: OsMemoryReader;
61
+ }
62
+ /**
63
+ * One memory sample of the app, for a sampler that runs during the window. Only used on an app
64
+ * this host launched, so the pid-namespace check of {@link measureSession} is skipped.
65
+ */
66
+ export declare function sampleMemory(session: EvaluatingSession, source: MemorySource): Promise<MemoryMeasurement | undefined>;
67
+ /**
68
+ * Whether `a` is a heavier sample than `b`. A sample with every process in its own metric beats
69
+ * one that fell back to working set, which counts in a different unit.
70
+ */
71
+ export declare function heavierMemory(a: MemoryMeasurement, b: MemoryMeasurement): boolean;
72
+ export interface SessionMeasurement {
73
+ readonly measurement: Measurement;
74
+ readonly electronVersion?: string;
75
+ readonly platform: string;
76
+ }
77
+ /** Close the window (running one first when none is open) and sample memory and startup. */
78
+ export declare function measureSession(session: EvaluatingSession, options: MeasureOptions): Promise<SessionMeasurement>;
79
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Measure one live app session through the transport's `evaluate` seam.
3
+ *
4
+ * @module
5
+ */
6
+ import { validateEvalContent } from '@electron-stagewright/core';
7
+ import { measureMemory, osMemoryReader, hostStartTimeReader, } from './memory.js';
8
+ import { DEFAULT_IPC_INTERVAL_MS, IPC_READ_BODY, MAIN_BODY, buildIpcStartBody, buildMemoryProbeBody, } from './probe.js';
9
+ import { memoryByType, memoryTotal, summarizeLatencies, } from './run.js';
10
+ export const MAIN_EVAL_OFF = 'main eval is off; start the server with --allow-eval=main (or bare --allow-eval)';
11
+ export const RENDERER_EVAL_OFF = 'renderer eval is off; start the server with bare --allow-eval to measure it';
12
+ const message = (error) => (error instanceof Error ? error.message : String(error));
13
+ /**
14
+ * Open a measurement window: arm the main-thread sampler and, when a probe is given and renderer
15
+ * eval is allowed, the IPC probe loop. Returns why the IPC probe did not start, if it did not.
16
+ */
17
+ export async function startWindow(session, options) {
18
+ if (options.mainUnavailable === undefined) {
19
+ await session.evaluate('main', MAIN_BODY, { op: 'start' });
20
+ }
21
+ if (options.ipc === undefined)
22
+ return { ipc: false };
23
+ if (!options.allowRenderer) {
24
+ return { ipc: false, ipcUnavailable: options.rendererOff ?? RENDERER_EVAL_OFF };
25
+ }
26
+ try {
27
+ // The probe is caller-supplied JavaScript: hold it to the same blocklist as the eval tools.
28
+ validateEvalContent(options.ipc.probe, { target: 'renderer' });
29
+ }
30
+ catch (error) {
31
+ return { ipc: false, ipcUnavailable: `the IPC probe was refused: ${message(error)}` };
32
+ }
33
+ try {
34
+ await session.evaluate('renderer', buildIpcStartBody(options.ipc.probe), {
35
+ intervalMs: options.ipc.intervalMs ?? DEFAULT_IPC_INTERVAL_MS,
36
+ });
37
+ return { ipc: true };
38
+ }
39
+ catch (error) {
40
+ return { ipc: false, ipcUnavailable: `the IPC probe did not start: ${message(error)}` };
41
+ }
42
+ }
43
+ /** Read the renderer memory probe; throws with the reason it cannot. */
44
+ async function probeMetrics(session, source) {
45
+ const reason = source.mainUnavailable ?? 'main eval is unavailable';
46
+ if (source.memoryProbe === undefined) {
47
+ throw new Error(`${reason}; name a memoryProbe in the budget to measure memory`);
48
+ }
49
+ if (!source.allowRenderer)
50
+ throw new Error(`${reason}, and ${RENDERER_EVAL_OFF}`);
51
+ try {
52
+ validateEvalContent(source.memoryProbe, { target: 'renderer' });
53
+ }
54
+ catch (error) {
55
+ throw new Error(`the memory probe was refused: ${message(error)}`);
56
+ }
57
+ try {
58
+ return await session.evaluate('renderer', buildMemoryProbeBody(source.memoryProbe));
59
+ }
60
+ catch (error) {
61
+ throw new Error(`the memory probe failed: ${message(error)}`);
62
+ }
63
+ }
64
+ /**
65
+ * One memory sample of the app, for a sampler that runs during the window. Only used on an app
66
+ * this host launched, so the pid-namespace check of {@link measureSession} is skipped.
67
+ */
68
+ export async function sampleMemory(session, source) {
69
+ try {
70
+ const processes = source.mainUnavailable === undefined
71
+ ? (await session.evaluate('main', MAIN_BODY, { op: 'facts' })).processes
72
+ : (await probeMetrics(session, source)).processes;
73
+ const { memory } = await measureMemory(processes.filter((entry) => isPid(entry.pid)), process.platform, source.memoryReader ?? osMemoryReader(process.platform));
74
+ return memory;
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
80
+ /** Memory outside the GPU in the sample's metric, else in working set. */
81
+ function memoryWeight(memory) {
82
+ const total = memoryTotal(memory, true);
83
+ if (total !== undefined)
84
+ return total;
85
+ const byType = memoryByType({ ...memory, metric: 'workingSet' });
86
+ return Object.entries(byType).reduce((sum, [type, mb]) => (type === 'gpu' ? sum : sum + mb), 0);
87
+ }
88
+ /**
89
+ * Whether `a` is a heavier sample than `b`. A sample with every process in its own metric beats
90
+ * one that fell back to working set, which counts in a different unit.
91
+ */
92
+ export function heavierMemory(a, b) {
93
+ const aComplete = memoryTotal(a, true) !== undefined;
94
+ const bComplete = memoryTotal(b, true) !== undefined;
95
+ if (aComplete !== bComplete)
96
+ return aComplete;
97
+ return memoryWeight(a) > memoryWeight(b);
98
+ }
99
+ async function measureWithoutMain(session, options, open) {
100
+ const unavailable = {
101
+ mainThread: options.mainUnavailable,
102
+ startup: options.mainUnavailable,
103
+ };
104
+ const ipc = await readIpc(session, open, unavailable);
105
+ let memory;
106
+ let electronVersion;
107
+ try {
108
+ const metrics = await probeMetrics(session, options);
109
+ electronVersion = /Electron\/(\S+)/.exec(metrics.userAgent)?.[1];
110
+ const measured = await measureMemory(metrics.processes.filter((entry) => isPid(entry.pid)), process.platform, options.memoryReader ?? osMemoryReader(process.platform));
111
+ memory = measured.memory;
112
+ if (measured.error !== undefined)
113
+ unavailable['memory'] = measured.error;
114
+ }
115
+ catch (error) {
116
+ unavailable['memory'] = message(error);
117
+ }
118
+ return {
119
+ measurement: {
120
+ ...(memory === undefined ? {} : { memory }),
121
+ ...(ipc === undefined ? {} : { ipc }),
122
+ unavailable,
123
+ },
124
+ ...(electronVersion === undefined ? {} : { electronVersion }),
125
+ platform: process.platform,
126
+ };
127
+ }
128
+ async function readIpc(session, open, unavailable) {
129
+ if (open.ipcUnavailable !== undefined)
130
+ unavailable['ipc'] = open.ipcUnavailable;
131
+ if (!open.ipc)
132
+ return undefined;
133
+ try {
134
+ const read = await session.evaluate('renderer', IPC_READ_BODY, {
135
+ stop: true,
136
+ });
137
+ if (read === null) {
138
+ unavailable['ipc'] = 'the IPC probe was lost; the window navigated during the measurement';
139
+ }
140
+ else if (read.samples.length === 0) {
141
+ unavailable['ipc'] =
142
+ read.lastError === null
143
+ ? 'the IPC probe completed no round trip'
144
+ : `the IPC probe failed: ${read.lastError}`;
145
+ }
146
+ else {
147
+ return summarizeLatencies(read.samples);
148
+ }
149
+ }
150
+ catch (error) {
151
+ unavailable['ipc'] = `could not read the IPC probe: ${message(error)}`;
152
+ }
153
+ return undefined;
154
+ }
155
+ /** `ps` start times have whole-second resolution. */
156
+ const START_TIME_TOLERANCE_MS = 2_000;
157
+ /**
158
+ * Pids come from the app, but the OS reader runs on this host. Refuse to read them when the
159
+ * host's process with the main pid did not start when the app's main process did.
160
+ */
161
+ async function hostMismatch(facts, reader) {
162
+ if (!isPid(facts.pid))
163
+ return 'the app reported an invalid main pid';
164
+ if (facts.creationTime === null || reader === undefined)
165
+ return undefined;
166
+ const started = await reader(facts.pid);
167
+ if (started === undefined)
168
+ return undefined;
169
+ if (started !== 'missing' && Math.abs(started - facts.creationTime) <= START_TIME_TOLERANCE_MS) {
170
+ return undefined;
171
+ }
172
+ return `pid ${facts.pid} on this host is not the app's main process (another pid namespace?)`;
173
+ }
174
+ /** App-reported pids reach host commands and /proc paths, so only plain pids pass. */
175
+ const isPid = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
176
+ /** Close the window (running one first when none is open) and sample memory and startup. */
177
+ export async function measureSession(session, options) {
178
+ const unavailable = {};
179
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
180
+ let open = options.open;
181
+ if (open === undefined) {
182
+ open = await startWindow(session, {
183
+ allowRenderer: options.allowRenderer,
184
+ ...(options.rendererOff === undefined ? {} : { rendererOff: options.rendererOff }),
185
+ ...(options.ipc === undefined ? {} : { ipc: options.ipc }),
186
+ ...(options.mainUnavailable === undefined
187
+ ? {}
188
+ : { mainUnavailable: options.mainUnavailable }),
189
+ });
190
+ await sleep(options.windowMs);
191
+ }
192
+ if (options.mainUnavailable !== undefined) {
193
+ return measureWithoutMain(session, { ...options, mainUnavailable: options.mainUnavailable }, open);
194
+ }
195
+ const stall = await session.evaluate('main', MAIN_BODY, {
196
+ op: 'read',
197
+ stop: true,
198
+ });
199
+ // The app restarted its main process mid-window, or the window outlived MAX_WINDOW_MS.
200
+ if (stall === null)
201
+ unavailable['mainThread'] = 'the measurement window was lost or expired';
202
+ const ipc = await readIpc(session, open, unavailable);
203
+ const facts = await session.evaluate('main', MAIN_BODY, { op: 'facts' });
204
+ let reader = options.memoryReader ?? osMemoryReader(facts.platform);
205
+ const mismatch = reader === undefined
206
+ ? undefined
207
+ : await hostMismatch(facts, options.hostStartTime ?? hostStartTimeReader(facts.platform));
208
+ if (mismatch !== undefined) {
209
+ reader = () => Promise.reject(new Error(mismatch));
210
+ }
211
+ const { memory, error: memoryError } = await measureMemory(facts.processes.filter((entry) => isPid(entry.pid)), facts.platform, reader);
212
+ if (memoryError !== undefined)
213
+ unavailable['memory'] = memoryError;
214
+ let startup;
215
+ if (options.allowStartup === false) {
216
+ unavailable['startup'] = RENDERER_EVAL_OFF;
217
+ }
218
+ else if (options.allowStartup === undefined && !options.allowRenderer) {
219
+ unavailable['startup'] = options.rendererOff ?? RENDERER_EVAL_OFF;
220
+ }
221
+ else if (facts.creationTime === null) {
222
+ unavailable['startup'] = 'this Electron does not report the process creation time';
223
+ }
224
+ else {
225
+ try {
226
+ // Read from main so the first window counts, not whichever renderer is selected.
227
+ const timing = await session.evaluate('main', MAIN_BODY, {
228
+ op: 'startup',
229
+ });
230
+ if ('error' in timing)
231
+ throw new Error(timing.error);
232
+ const firstWindowMs = timing.timeOrigin + timing.loadEventEnd - facts.creationTime;
233
+ // A later document means the first one was left; pushState keeps the document.
234
+ const navigated = timing.firstUrl !== null ? timing.url !== timing.firstUrl : (timing.historyLength ?? 1) > 1;
235
+ if (timing.type !== 'navigate' || navigated) {
236
+ unavailable['startup'] = 'the first window was reloaded or navigated since launch';
237
+ }
238
+ else if (!(timing.loadEventEnd > 0) ||
239
+ !(firstWindowMs > 0) ||
240
+ !Number.isFinite(firstWindowMs)) {
241
+ unavailable['startup'] = 'the window has not finished loading';
242
+ }
243
+ else {
244
+ startup = { firstWindowMs: Math.round(firstWindowMs) };
245
+ }
246
+ }
247
+ catch (error) {
248
+ unavailable['startup'] = `could not read navigation timing: ${message(error)}`;
249
+ }
250
+ }
251
+ return {
252
+ measurement: {
253
+ ...(startup === undefined ? {} : { startup }),
254
+ memory,
255
+ ...(stall === null ? {} : { mainThread: stall }),
256
+ ...(ipc === undefined ? {} : { ipc }),
257
+ ...(Object.keys(unavailable).length === 0 ? {} : { unavailable }),
258
+ },
259
+ ...(facts.electron === null ? {} : { electronVersion: facts.electron }),
260
+ platform: facts.platform,
261
+ };
262
+ }
263
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}