diff --git a/packages/@lwc/perf-benchmarks/README.md b/packages/@lwc/perf-benchmarks/README.md index 9381e107f6..9e19674a5f 100644 --- a/packages/@lwc/perf-benchmarks/README.md +++ b/packages/@lwc/perf-benchmarks/README.md @@ -56,10 +56,13 @@ You can also use these environment variables to adjust the default benchmark set BENCHMARK_SAMPLE_SIZE=50 BENCHMARK_AUTO_SAMPLE_CONDITIONS=25% BENCHMARK_TIMEOUT=5 +BENCHMARK_CPU_THROTTLING_RATE=4 ``` See the [Tachometer documentation](https://github.com/Polymer/tachometer) for details on what these mean. +For `BENCHMARK_CPU_THROTTLING_RATE`, some tests have a built-in `cpuThrottlingRate` which is exported as a `const`. The environment variable will override this. + You can run a smoke test (to confirm the benchmark tests are working) using: ```shell diff --git a/packages/@lwc/perf-benchmarks/package.json b/packages/@lwc/perf-benchmarks/package.json index 23777dd897..90c143cdab 100644 --- a/packages/@lwc/perf-benchmarks/package.json +++ b/packages/@lwc/perf-benchmarks/package.json @@ -55,6 +55,9 @@ }, { "env": "BENCHMARK_SMOKE_TEST" + }, + { + "env": "BENCHMARK_CPU_THROTTLING_RATE" } ] }, diff --git a/packages/@lwc/perf-benchmarks/scripts/build.js b/packages/@lwc/perf-benchmarks/scripts/build.js index 78d5305f38..63beeaa7fc 100644 --- a/packages/@lwc/perf-benchmarks/scripts/build.js +++ b/packages/@lwc/perf-benchmarks/scripts/build.js @@ -9,14 +9,11 @@ * Builds the HTML and tachometer.json files necessary to run the benchmarks. */ -const path = require('path'); -const fs = require('fs'); -const { promisify } = require('util'); +const path = require('node:path'); +const { readFile, writeFile } = require('node:fs/promises'); const { glob } = require('glob'); const { hashElement } = require('folder-hash'); -const writeFile = promisify(fs.writeFile); - const { BENCHMARK_SMOKE_TEST, BENCHMARK_REPO = 'https://github.com/salesforce/lwc.git', @@ -27,6 +24,7 @@ const { let { BENCHMARK_SAMPLE_SIZE = 100, // minimum number of samples to run BENCHMARK_TIMEOUT = 15, // timeout in minutes during auto-sampling (after the minimum samples). If 0, no auto-sampling + BENCHMARK_CPU_THROTTLING_RATE, // CPU throttling factor, typically 2 or 4 } = process.env; const toInt = (num) => (typeof num === 'number' ? num : parseInt(num, 10)); @@ -35,6 +33,8 @@ const toInt = (num) => (typeof num === 'number' ? num : parseInt(num, 10)); BENCHMARK_SAMPLE_SIZE = BENCHMARK_SMOKE_TEST ? 2 : toInt(BENCHMARK_SAMPLE_SIZE); // Timeout of 0 means don't auto-sample at all BENCHMARK_TIMEOUT = BENCHMARK_SMOKE_TEST ? 0 : toInt(BENCHMARK_TIMEOUT); +BENCHMARK_CPU_THROTTLING_RATE = + BENCHMARK_CPU_THROTTLING_RATE && toInt(BENCHMARK_CPU_THROTTLING_RATE); const benchmarkComponentsDir = path.join(__dirname, '../../../@lwc/perf-benchmarks-components'); @@ -66,7 +66,7 @@ function createHtml(benchmarkFile) { `.trim(); } -function createTachometerJson(htmlFilename, benchmarkName, directoryHash) { +function createTachometerJson(htmlFilename, benchmarkName, directoryHash, cpuThrottlingRate) { return { $schema: 'https://raw.githubusercontent.com/Polymer/tachometer/master/config.schema.json', sampleSize: BENCHMARK_SAMPLE_SIZE, @@ -80,6 +80,7 @@ function createTachometerJson(htmlFilename, benchmarkName, directoryHash) { name: 'chrome', headless: true, ...(CHROME_BINARY && { binary: CHROME_BINARY }), + ...(typeof cpuThrottlingRate === 'number' && { cpuThrottlingRate }), }, measurement: { mode: 'performance', @@ -126,6 +127,16 @@ function createTachometerJson(htmlFilename, benchmarkName, directoryHash) { }; } +// Given a *.benchmark.js file, extract the exported `cpuThrottlingRate`. +async function extractCpuThrottlingRate(benchmarkFile) { + const contents = await readFile(benchmarkFile, 'utf-8'); + // Rollup transforms this into `const cpuThrottlingRate = 2; [...] export { cpuThrottlingRate };`, + // so we just look for the const, not the export. + // We could do a more sophisticated thing than a regex, but the regex works fine. + const match = contents.match(/const cpuThrottlingRate\s*=\s*(\d+)/); + return match && parseInt(match[1], 10); +} + // Given a benchmark source file, create the necessary HTML file and Tachometer JSON // file for running it. async function processBenchmarkFile(benchmarkFile, directoryHash) { @@ -141,7 +152,16 @@ async function processBenchmarkFile(benchmarkFile, directoryHash) { async function writeTachometerJsonFile() { const engineType = benchmarkFile.includes('/engine-server/') ? 'server' : 'dom'; const benchmarkName = `${engineType}-${benchmarkFileBasename.split('.')[0]}`; - const tachometerJson = createTachometerJson(htmlFilename, benchmarkName, directoryHash); + const cpuThrottlingRate = + typeof BENCHMARK_CPU_THROTTLING_RATE === 'number' + ? BENCHMARK_CPU_THROTTLING_RATE + : await extractCpuThrottlingRate(benchmarkFile); + const tachometerJson = createTachometerJson( + htmlFilename, + benchmarkName, + directoryHash, + cpuThrottlingRate + ); const jsonFilename = path.join( targetDir, `${benchmarkFileBasename.split('.')[0]}.tachometer.json` diff --git a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/benchmark-expression/expression.benchmark.js b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/benchmark-expression/expression.benchmark.js index aecdcb2ec7..c58ad75db5 100644 --- a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/benchmark-expression/expression.benchmark.js +++ b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/benchmark-expression/expression.benchmark.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, salesforce.com, inc. + * Copyright (c) 2024, Salesforce, Inc. * All rights reserved. * SPDX-License-Identifier: MIT * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT @@ -11,6 +11,9 @@ import Expression from '@lwc/perf-benchmarks-components/dist/dom/benchmark/expre import Store from '@lwc/perf-benchmarks-components/dist/dom/benchmark/store/store.js'; import { insertComponent, destroyComponent } from '../../../utils/utils.js'; +// Throttling because otherwise this benchmark completes in <~5ms on a MacBook Pro +export const cpuThrottlingRate = 4; + benchmark(`dom/expressions`, () => { let expressionElement; diff --git a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/clear-rows-1k.benchmark.js b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/clear-rows-1k.benchmark.js index 4218214c31..d53596660a 100644 --- a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/clear-rows-1k.benchmark.js +++ b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/clear-rows-1k.benchmark.js @@ -6,6 +6,9 @@ */ import { runJsFrameworkBenchmark, WARMUP_COUNT } from '../../../utils/runJsFrameworkBenchmark.js'; +// Throttling per https://krausest.github.io/js-framework-benchmark/2024/table_chrome_122.0.6261.69.html +export const cpuThrottlingRate = 4; + // Based on https://github.com/krausest/js-framework-benchmark/blob/6c9f43f/webdriver-ts/src/benchmarksPuppeteer.ts // See `benchClear()` runJsFrameworkBenchmark( diff --git a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/partial-update-1k.benchmark.js b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/partial-update-1k.benchmark.js index 8dc8e42b86..ec846f36a1 100644 --- a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/partial-update-1k.benchmark.js +++ b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/partial-update-1k.benchmark.js @@ -6,6 +6,9 @@ */ import { runJsFrameworkBenchmark, WARMUP_COUNT } from '../../../utils/runJsFrameworkBenchmark.js'; +// Throttling per https://krausest.github.io/js-framework-benchmark/2024/table_chrome_122.0.6261.69.html +export const cpuThrottlingRate = 4; + // Based on https://github.com/krausest/js-framework-benchmark/blob/6c9f43f/webdriver-ts/src/benchmarksPuppeteer.ts // See `benchUpdate()` runJsFrameworkBenchmark( diff --git a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/remove-row-1k.benchmark.js b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/remove-row-1k.benchmark.js index 17ded3df44..bfd71ead42 100644 --- a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/remove-row-1k.benchmark.js +++ b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/remove-row-1k.benchmark.js @@ -6,6 +6,9 @@ */ import { runJsFrameworkBenchmark, WARMUP_COUNT } from '../../../utils/runJsFrameworkBenchmark.js'; +// Throttling per https://krausest.github.io/js-framework-benchmark/2024/table_chrome_122.0.6261.69.html +export const cpuThrottlingRate = 2; + const rowsToSkip = 4; // Based on https://github.com/krausest/js-framework-benchmark/blob/6c9f43f/webdriver-ts/src/benchmarksPuppeteer.ts diff --git a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/select-row-1k.benchmark.js b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/select-row-1k.benchmark.js index d502293763..ce3a548c61 100644 --- a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/select-row-1k.benchmark.js +++ b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/select-row-1k.benchmark.js @@ -6,6 +6,9 @@ */ import { runJsFrameworkBenchmark, WARMUP_COUNT } from '../../../utils/runJsFrameworkBenchmark.js'; +// Throttling per https://krausest.github.io/js-framework-benchmark/2024/table_chrome_122.0.6261.69.html +export const cpuThrottlingRate = 4; + // Based on https://github.com/krausest/js-framework-benchmark/blob/6c9f43f/webdriver-ts/src/benchmarksPuppeteer.ts // See `benchSelect()` runJsFrameworkBenchmark( diff --git a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/swap-rows-1k.benchmark.js b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/swap-rows-1k.benchmark.js index 05397b07dd..0b05af2cf8 100644 --- a/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/swap-rows-1k.benchmark.js +++ b/packages/@lwc/perf-benchmarks/src/__benchmarks__/engine-dom/js-framework-benchmark/swap-rows-1k.benchmark.js @@ -6,6 +6,9 @@ */ import { runJsFrameworkBenchmark, WARMUP_COUNT } from '../../../utils/runJsFrameworkBenchmark.js'; +// Throttling per https://krausest.github.io/js-framework-benchmark/2024/table_chrome_122.0.6261.69.html +export const cpuThrottlingRate = 4; + // Based on https://github.com/krausest/js-framework-benchmark/blob/6c9f43f/webdriver-ts/src/benchmarksPuppeteer.ts // See `benchSwapRows()` runJsFrameworkBenchmark(