Skip to content

Commit 192339f

Browse files
committed
metrics: fix CPU usage collection
1 parent 9938203 commit 192339f

File tree

3 files changed

+39
-15
lines changed

3 files changed

+39
-15
lines changed

packages/replay/metrics/configs/ci/collect.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,22 @@ const result = await collector.execute({
2626
tries: 10,
2727
async shouldAccept(results: Metrics[]): Promise<boolean> {
2828
const stats = new MetricsStats(results);
29-
return true
30-
&& checkStdDev(stats, 'lcp', MetricsStats.lcp, 30)
31-
&& checkStdDev(stats, 'cls', MetricsStats.cls, 0.1)
32-
&& checkStdDev(stats, 'cpu', MetricsStats.cpu, 10)
33-
&& checkStdDev(stats, 'memory-mean', MetricsStats.memoryMean, 30 * 1024)
34-
&& checkStdDev(stats, 'memory-max', MetricsStats.memoryMax, 100 * 1024);
29+
if (!checkStdDev(stats, 'lcp', MetricsStats.lcp, 30)
30+
|| !checkStdDev(stats, 'cls', MetricsStats.cls, 0.1)
31+
|| !checkStdDev(stats, 'cpu', MetricsStats.cpu, 10)
32+
|| !checkStdDev(stats, 'memory-mean', MetricsStats.memoryMean, 30 * 1024)
33+
|| !checkStdDev(stats, 'memory-max', MetricsStats.memoryMax, 100 * 1024)) {
34+
return false;
35+
}
36+
37+
const cpuUsage = stats.mean(MetricsStats.cpu)!;
38+
if (cpuUsage > 0.9) {
39+
console.error(`CPU usage too high to be accurate: ${(cpuUsage * 100).toFixed(2)} %.`,
40+
'Consider simplifying the scenario or changing the CPU throttling factor.');
41+
return false;
42+
}
43+
44+
return true;
3545
},
3646
});
3747

packages/replay/metrics/configs/dev/collect.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Metrics, MetricsCollector } from '../../src/collector.js';
2+
import { MetricsStats } from '../../src/results/metrics-stats.js';
23
import { JankTestScenario } from '../../src/scenarios.js';
34
import { latestResultFile } from './env.js';
45

@@ -9,7 +10,14 @@ const result = await collector.execute({
910
b: new JankTestScenario(true),
1011
runs: 1,
1112
tries: 1,
12-
async shouldAccept(_results: Metrics[]): Promise<boolean> {
13+
async shouldAccept(results: Metrics[]): Promise<boolean> {
14+
const stats = new MetricsStats(results);
15+
const cpuUsage = stats.mean(MetricsStats.cpu)!;
16+
if (cpuUsage > 0.9) {
17+
console.error(`CPU usage too high to be accurate: ${(cpuUsage * 100).toFixed(2)} %.`,
18+
'Consider simplifying the scenario or changing the CPU throttling factor.');
19+
return false;
20+
}
1321
return true;
1422
},
1523
});

packages/replay/metrics/src/perf/sampler.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ export class PerfMetrics {
3333
}
3434

3535
public get Duration(): number {
36-
// TODO check if any of `Duration` fields is maybe a sum of the others. E.g. verify the measured CPU usage manually.
37-
return this._metrics.reduce((sum, metric) => metric.name.endsWith('Duration') ? sum + metric.value : sum, 0);
36+
return this._find('TaskDuration');
3837
}
3938

4039
public get JSHeapUsedSize(): number {
@@ -46,16 +45,17 @@ export class PerfMetricsSampler {
4645
private _consumers: PerfMetricsConsumer[] = [];
4746
private _timer!: NodeJS.Timer;
4847

48+
private constructor(private _cdp: playwright.CDPSession) { }
49+
4950
public static async create(cdp: playwright.CDPSession, interval: number): Promise<PerfMetricsSampler> {
50-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
51+
const self = new PerfMetricsSampler(cdp);
5152
await cdp.send('Performance.enable', { timeDomain: 'timeTicks' })
5253

53-
const self = new PerfMetricsSampler();
54+
// collect first sample immediately
55+
void self._collectSample();
5456

55-
self._timer = setInterval(async () => {
56-
const metrics = await cdp.send('Performance.getMetrics').then((v) => v.metrics);
57-
self._consumers.forEach((cb) => cb(new PerfMetrics(metrics)).catch(console.log));
58-
}, interval);
57+
// and set up automatic collection in the given interval
58+
self._timer = setInterval(self._collectSample.bind(self), interval);
5959

6060
return self;
6161
}
@@ -67,4 +67,10 @@ export class PerfMetricsSampler {
6767
public stop(): void {
6868
clearInterval(this._timer);
6969
}
70+
71+
private async _collectSample(): Promise<void> {
72+
const response = await this._cdp.send('Performance.getMetrics');
73+
const metrics = new PerfMetrics(response.metrics);
74+
this._consumers.forEach(cb => cb(metrics).catch(console.error));
75+
}
7076
}

0 commit comments

Comments
 (0)