Skip to content

Commit 5fc23d7

Browse files
rshestfacebook-github-bot
authored andcommitted
Add type-safe API for passing around benchmark results (#53143)
Summary: Pull Request resolved: #53143 # Changelog: [Internal] - This refactors the way Fantom benchmark test results are passed to the top level, making it type safe and more maintainable. Reviewed By: andrewdacenko Differential Revision: D79812707 fbshipit-source-id: d8bfef7e1b0c11b277a08f5e4c810f8c1efd7f89
1 parent e92da16 commit 5fc23d7

4 files changed

Lines changed: 63 additions & 53 deletions

File tree

private/react-native-fantom/runner/benchmarkUtils.js

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,52 +8,36 @@
88
* @format
99
*/
1010

11-
import {markdownTable} from './utils';
12-
13-
type TestTaskTiming = {
14-
name: string,
15-
latency: {
16-
mean: number,
17-
min: number,
18-
max: number,
19-
p50: number,
20-
p75: number,
21-
p99: number,
22-
},
23-
};
11+
import type {BenchmarkResult} from '../src/Benchmark';
2412

25-
export type BenchmarkTestArtifact = {
26-
type: string,
27-
timings: $ReadOnlyArray<TestTaskTiming>,
28-
};
13+
import {markdownTable} from './utils';
2914

3015
export const printBenchmarkResultsRanking = (
31-
testResults: Array<{
16+
benchmarkResults: Array<{
3217
title: string,
33-
testArtifact: mixed,
18+
result: BenchmarkResult,
3419
}>,
3520
) => {
3621
const testTaskTimings: {[string]: {[string]: number}} = {};
3722
let numTestVariants = 0;
3823

39-
for (const testResult of testResults) {
40-
// $FlowExpectedError[incompatible-cast]
41-
const testArtifact = testResult?.testArtifact as ?BenchmarkTestArtifact;
24+
for (const benchmarkResult of benchmarkResults) {
25+
const result = benchmarkResult.result;
4226
if (
43-
testArtifact == null ||
44-
testArtifact.timings == null ||
45-
testArtifact.type !== 'benchmark' ||
46-
testResult.title == null
27+
result == null ||
28+
result.timings == null ||
29+
benchmarkResult.title == null
4730
) {
4831
continue;
4932
}
5033
numTestVariants++;
51-
for (const taskTiming of testArtifact.timings) {
34+
for (const taskTiming of result.timings) {
5235
const taskName = taskTiming.name;
5336
if (testTaskTimings[taskName] === undefined) {
5437
testTaskTimings[taskName] = {};
5538
}
56-
testTaskTimings[taskName][testResult.title] = taskTiming.latency.p50;
39+
testTaskTimings[taskName][benchmarkResult.title] =
40+
taskTiming.latency?.p50 ?? taskTiming.latency.mean;
5741
}
5842
}
5943
if (numTestVariants <= 1 || Object.keys(testTaskTimings).length === 0) {

private/react-native-fantom/runner/runner.js

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type {
1414
TestSuiteResult,
1515
} from '../runtime/setup';
1616
import type {TestSnapshotResults} from '../runtime/snapshotContext';
17-
import type {BenchmarkTestArtifact} from './benchmarkUtils';
17+
import type {BenchmarkResult} from '../src/Benchmark';
1818
import type {
1919
AsyncCommandResult,
2020
ConsoleLogMessage,
@@ -80,7 +80,7 @@ function buildError(
8080

8181
async function processRNTesterCommandResult(
8282
result: AsyncCommandResult,
83-
): Promise<TestSuiteResult> {
83+
): Promise<[TestSuiteResult, ?BenchmarkResult]> {
8484
const stdoutChunks = [];
8585
const stderrChunks = [];
8686

@@ -92,7 +92,7 @@ async function processRNTesterCommandResult(
9292
stderrChunks.push(chunk);
9393
});
9494

95-
let testResult;
95+
let testResult, benchmarkResult;
9696

9797
const rl = readline.createInterface({input: result.childProcess.stdout});
9898
rl.on('line', (rawLine: string) => {
@@ -116,6 +116,9 @@ async function processRNTesterCommandResult(
116116
case 'test-result':
117117
testResult = parsed;
118118
break;
119+
case 'benchmark-result':
120+
benchmarkResult = parsed;
121+
break;
119122
case 'console-log':
120123
printConsoleLog(parsed);
121124
break;
@@ -152,7 +155,7 @@ async function processRNTesterCommandResult(
152155
);
153156
}
154157

155-
return testResult;
158+
return [testResult, benchmarkResult];
156159
}
157160

158161
function generateBytecodeBundle({
@@ -223,6 +226,7 @@ module.exports = async function runTest(
223226
);
224227

225228
const testResultsByConfig = [];
229+
const benchmarkResults = [];
226230

227231
const skippedTestResults = ({
228232
ancestorTitles,
@@ -241,7 +245,6 @@ module.exports = async function runTest(
241245
snapshotResults: {} as TestSnapshotResults,
242246
status: 'pending' as TestCaseResult['status'],
243247
testFilePath: testPath,
244-
testArtifact: {} as mixed,
245248
title,
246249
},
247250
];
@@ -371,9 +374,8 @@ module.exports = async function runTest(
371374
hermesVariant: testConfig.hermesVariant,
372375
});
373376

374-
const processedResult = await processRNTesterCommandResult(
375-
rnTesterCommandResult,
376-
);
377+
const [processedResult, benchmarkResult] =
378+
await processRNTesterCommandResult(rnTesterCommandResult);
377379

378380
if (containsError(processedResult) || EnvironmentOptions.profileJS) {
379381
await createSourceMap({
@@ -439,6 +441,13 @@ module.exports = async function runTest(
439441
});
440442
}
441443

444+
if (benchmarkResult != null) {
445+
benchmarkResults.push({
446+
title: testResults[0]?.ancestorTitles?.[0] ?? maybeCommonAncestor,
447+
result: benchmarkResult,
448+
});
449+
}
450+
442451
testResultsByConfig.push(testResults);
443452
}
444453

@@ -455,17 +464,7 @@ module.exports = async function runTest(
455464
snapshotResults,
456465
);
457466

458-
printBenchmarkResultsRanking(
459-
testResults.map(testResult => {
460-
// $FlowExpectedError[incompatible-cast]
461-
const testArtifact = testResult.testArtifact as ?BenchmarkTestArtifact;
462-
const title = testResult.ancestorTitles[0];
463-
return {
464-
title,
465-
testArtifact,
466-
};
467-
}),
468-
);
467+
printBenchmarkResultsRanking(benchmarkResults);
469468

470469
return {
471470
testFilePath: testPath,

private/react-native-fantom/runtime/setup.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* @format
99
*/
1010

11+
import type {BenchmarkResult} from '../src/Benchmark';
1112
import type {SnapshotConfig, TestSnapshotResults} from './snapshotContext';
1213

1314
import {getConstants} from '../src/Constants';
@@ -26,7 +27,6 @@ export type TestCaseResult = {
2627
failureDetails: Array<FailureDetail>,
2728
numPassingAsserts: number,
2829
snapshotResults: TestSnapshotResults,
29-
testArtifact?: mixed,
3030
// location: string,
3131
};
3232

@@ -315,7 +315,6 @@ function runSpec(spec: Spec): TestCaseResult {
315315
failureDetails: [],
316316
numPassingAsserts: 0,
317317
snapshotResults: {},
318-
testArtifact: null,
319318
};
320319

321320
if (!shouldRunSuite(spec)) {
@@ -330,7 +329,7 @@ function runSpec(spec: Spec): TestCaseResult {
330329

331330
try {
332331
invokeHooks(spec.parentContext, 'beforeEachHooks');
333-
result.testArtifact = spec.implementation();
332+
spec.implementation();
334333
invokeHooks(spec.parentContext, 'afterEachHooks');
335334

336335
status = 'passed';
@@ -402,6 +401,13 @@ function reportTestSuiteResult(testSuiteResult: TestSuiteResult): void {
402401
);
403402
}
404403

404+
export function reportBenchmarkResult(result: BenchmarkResult): void {
405+
// Force the import of the native module to be lazy
406+
const NativeFantom =
407+
require('react-native/src/private/testing/fantom/specs/NativeFantom').default;
408+
NativeFantom.reportTestSuiteResultsJSON(JSON.stringify(result));
409+
}
410+
405411
function validateEmptyMessageQueue(): void {
406412
// Force the import of the native module to be lazy
407413
const NativeFantom =

private/react-native-fantom/src/Benchmark.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* @format
99
*/
1010

11+
import {reportBenchmarkResult} from '../runtime/setup';
1112
import {getConstants} from './index';
1213
import nullthrows from 'nullthrows';
1314
import NativeCPUTime from 'react-native/src/private/testing/fantom/specs/NativeCPUTime';
@@ -30,6 +31,23 @@ export type SuiteOptions = $ReadOnly<{
3031

3132
export type TestOptions = FnOptions;
3233

34+
export type TestTaskTiming = {
35+
name: string,
36+
latency: {
37+
mean: number,
38+
min: number,
39+
max: number,
40+
p50?: number,
41+
p75?: number,
42+
p99?: number,
43+
},
44+
};
45+
46+
export type BenchmarkResult = {
47+
type: string,
48+
timings: $ReadOnlyArray<TestTaskTiming>,
49+
};
50+
3351
type InternalTestOptions = $ReadOnly<{
3452
...FnOptions,
3553
only?: boolean,
@@ -176,7 +194,7 @@ export function suite(
176194
'Failing focused test to prevent it from being committed',
177195
);
178196
}
179-
return createBenchmarkTestArtifact(bench, tasks);
197+
reportBenchmarkResult(createBenchmarkResultsObject(bench, tasks));
180198
});
181199

182200
const test = (
@@ -255,9 +273,12 @@ function printBenchmarkResults(bench: Bench) {
255273
console.log('');
256274
}
257275

258-
function createBenchmarkTestArtifact(bench: Bench, tasks: Array<TestTask>) {
276+
function createBenchmarkResultsObject(
277+
bench: Bench,
278+
tasks: Array<TestTask>,
279+
): BenchmarkResult {
259280
return {
260-
type: 'benchmark',
281+
type: 'benchmark-result',
261282
timings: tasks.map((task, i) => {
262283
const result = bench.results[i];
263284
const {min, max, mean, p50, p75, p99} = result.latency;

0 commit comments

Comments
 (0)