|
1 | 1 | import { Metric } from "./metric.mjs"; |
2 | 2 | import { params } from "./params.mjs"; |
3 | | -import { TEST_INVOKER_LOOKUP } from "./test-invoker.mjs"; |
| 3 | +import { SUITE_RUNNER_LOOKUP } from "./suite-runner.mjs"; |
4 | 4 |
|
5 | 5 | const performance = globalThis.performance; |
6 | 6 |
|
@@ -223,7 +223,7 @@ function geomeanToScore(geomean) { |
223 | 223 | // The WarmupSuite is used to make sure all runner helper functions and |
224 | 224 | // classes are compiled, to avoid unnecessary pauses due to delayed |
225 | 225 | // compilation of runner methods in the middle of the measuring cycle. |
226 | | -const WarmupSuite = { |
| 226 | +export const WarmupSuite = { |
227 | 227 | name: "Warmup", |
228 | 228 | url: "warmup/index.html", |
229 | 229 | async prepare(page) { |
@@ -410,7 +410,7 @@ export class BenchmarkRunner { |
410 | 410 | // FIXME: Encapsulate more state in the SuiteRunner. |
411 | 411 | // FIXME: Return and use measured values from SuiteRunner. |
412 | 412 | const suiteRunnerClass = SUITE_RUNNER_LOOKUP[suite.type ?? "default"]; |
413 | | - const suiteRunner = new suiteRunnerClass(this._measuredValues, this._frame, this._page, this._client, suite); |
| 413 | + const suiteRunner = new suiteRunnerClass(this._frame, this._page, params, suite, this._client, this._measuredValues); |
414 | 414 | await suiteRunner.run(); |
415 | 415 | } |
416 | 416 |
|
@@ -484,151 +484,3 @@ export class BenchmarkRunner { |
484 | 484 | metric.computeAggregatedMetrics(); |
485 | 485 | } |
486 | 486 | } |
487 | | - |
488 | | -// FIXME: Create AsyncSuiteRunner subclass. |
489 | | -// FIXME: Create RemoteSuiteRunner subclass. |
490 | | -export class SuiteRunner { |
491 | | - constructor(measuredValues, frame, page, client, suite) { |
492 | | - // FIXME: Create SuiteRunner-local measuredValues. |
493 | | - this._suiteResults = measuredValues.tests[suite.name]; |
494 | | - if (!this._suiteResults) { |
495 | | - this._suiteResults = { tests: {}, total: 0 }; |
496 | | - measuredValues.tests[suite.name] = this._suiteResults; |
497 | | - } |
498 | | - this._measuredValues = measuredValues; |
499 | | - this._frame = frame; |
500 | | - this._page = page; |
501 | | - this._client = client; |
502 | | - this._suite = suite; |
503 | | - } |
504 | | - |
505 | | - async run() { |
506 | | - await this._prepareSuite(); |
507 | | - await this._runSuite(); |
508 | | - } |
509 | | - |
510 | | - async _prepareSuite() { |
511 | | - const suiteName = this._suite.name; |
512 | | - const suitePrepareStartLabel = `suite-${suiteName}-prepare-start`; |
513 | | - const suitePrepareEndLabel = `suite-${suiteName}-prepare-end`; |
514 | | - |
515 | | - performance.mark(suitePrepareStartLabel); |
516 | | - await this._loadFrame(); |
517 | | - await this._suite.prepare(this._page); |
518 | | - performance.mark(suitePrepareEndLabel); |
519 | | - |
520 | | - performance.measure(`suite-${suiteName}-prepare`, suitePrepareStartLabel, suitePrepareEndLabel); |
521 | | - } |
522 | | - |
523 | | - async _runSuite() { |
524 | | - const suiteName = this._suite.name; |
525 | | - const suiteStartLabel = `suite-${suiteName}-start`; |
526 | | - const suiteEndLabel = `suite-${suiteName}-end`; |
527 | | - |
528 | | - performance.mark(suiteStartLabel); |
529 | | - for (const test of this._suite.tests) |
530 | | - await this._runTestAndRecordResults(test); |
531 | | - performance.mark(suiteEndLabel); |
532 | | - |
533 | | - performance.measure(`suite-${suiteName}`, suiteStartLabel, suiteEndLabel); |
534 | | - this._validateSuiteTotal(); |
535 | | - } |
536 | | - |
537 | | - _validateSuiteTotal() { |
538 | | - // When the test is fast and the precision is low (for example with Firefox' |
539 | | - // privacy.resistFingerprinting preference), it's possible that the measured |
540 | | - // total duration for an entire is 0. |
541 | | - const suiteTotal = this._suiteResults.total; |
542 | | - if (suiteTotal === 0) |
543 | | - throw new Error(`Got invalid 0-time total for suite ${this._suite.name}: ${suiteTotal}`); |
544 | | - } |
545 | | - |
546 | | - async _loadFrame() { |
547 | | - return new Promise((resolve, reject) => { |
548 | | - const frame = this._page._frame; |
549 | | - frame.onload = () => resolve(); |
550 | | - frame.onerror = () => reject(); |
551 | | - frame.src = this._suite.url; |
552 | | - }); |
553 | | - } |
554 | | - |
555 | | - async _runTestAndRecordResults(test) { |
556 | | - if (this._client?.willRunTest) |
557 | | - await this._client.willRunTest(this._suite, test); |
558 | | - |
559 | | - // Prepare all mark labels outside the measuring loop. |
560 | | - const suiteName = this._suite.name; |
561 | | - const testName = test.name; |
562 | | - const startLabel = `${suiteName}.${testName}-start`; |
563 | | - const syncEndLabel = `${suiteName}.${testName}-sync-end`; |
564 | | - const asyncStartLabel = `${suiteName}.${testName}-async-start`; |
565 | | - const asyncEndLabel = `${suiteName}.${testName}-async-end`; |
566 | | - |
567 | | - let syncTime; |
568 | | - let asyncStartTime; |
569 | | - let asyncTime; |
570 | | - const runSync = () => { |
571 | | - if (params.warmupBeforeSync) { |
572 | | - performance.mark("warmup-start"); |
573 | | - const startTime = performance.now(); |
574 | | - // Infinite loop for the specified ms. |
575 | | - while (performance.now() - startTime < params.warmupBeforeSync) |
576 | | - continue; |
577 | | - performance.mark("warmup-end"); |
578 | | - } |
579 | | - performance.mark(startLabel); |
580 | | - const syncStartTime = performance.now(); |
581 | | - test.run(this._page); |
582 | | - const syncEndTime = performance.now(); |
583 | | - performance.mark(syncEndLabel); |
584 | | - |
585 | | - syncTime = syncEndTime - syncStartTime; |
586 | | - |
587 | | - performance.mark(asyncStartLabel); |
588 | | - asyncStartTime = performance.now(); |
589 | | - }; |
590 | | - const measureAsync = () => { |
591 | | - // Some browsers don't immediately update the layout for paint. |
592 | | - // Force the layout here to ensure we're measuring the layout time. |
593 | | - const height = this._frame.contentDocument.body.getBoundingClientRect().height; |
594 | | - const asyncEndTime = performance.now(); |
595 | | - asyncTime = asyncEndTime - asyncStartTime; |
596 | | - this._frame.contentWindow._unusedHeightValue = height; // Prevent dead code elimination. |
597 | | - performance.mark(asyncEndLabel); |
598 | | - if (params.warmupBeforeSync) |
599 | | - performance.measure("warmup", "warmup-start", "warmup-end"); |
600 | | - const suiteName = this._suite.name; |
601 | | - const testName = test.name; |
602 | | - performance.measure(`${suiteName}.${testName}-sync`, startLabel, syncEndLabel); |
603 | | - performance.measure(`${suiteName}.${testName}-async`, asyncStartLabel, asyncEndLabel); |
604 | | - }; |
605 | | - |
606 | | - const report = () => this._recordTestResults(test, syncTime, asyncTime); |
607 | | - const invokerClass = TEST_INVOKER_LOOKUP[params.measurementMethod]; |
608 | | - const invoker = new invokerClass(runSync, measureAsync, report, params); |
609 | | - |
610 | | - return invoker.start(); |
611 | | - } |
612 | | - |
613 | | - async _recordTestResults(test, syncTime, asyncTime) { |
614 | | - // Skip reporting updates for the warmup suite. |
615 | | - if (this._suite === WarmupSuite) |
616 | | - return; |
617 | | - |
618 | | - const total = syncTime + asyncTime; |
619 | | - this._suiteResults.tests[test.name] = { tests: { Sync: syncTime, Async: asyncTime }, total: total }; |
620 | | - this._suiteResults.total += total; |
621 | | - |
622 | | - if (this._client?.didRunTest) |
623 | | - await this._client.didRunTest(this._suite, test); |
624 | | - } |
625 | | -} |
626 | | - |
627 | | -// FIXME: implement remote steps |
628 | | -class RemoteSuiteRunner extends SuiteRunner {} |
629 | | - |
630 | | -const SUITE_RUNNER_LOOKUP = { |
631 | | - __proto__: null, |
632 | | - default: SuiteRunner, |
633 | | - remote: RemoteSuiteRunner, |
634 | | -}; |
0 commit comments