From 7af4121f3c50d9e5c5d748dec86a5b35434fc5c1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 16 May 2026 12:20:30 -0400 Subject: [PATCH 1/3] solutions-engineering: make CPU benchmark fixed-work Change the fraud benchmark from a fixed-duration CPU burn to fixed parallel work so larger runners can improve wall-clock duration while smaller runners saturate CPU. Co-authored-by: Cursor --- .github/workflows/acme-ci.yml | 5 +- .../app/scripts/resource-profile.js | 56 +++++++++++++------ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/.github/workflows/acme-ci.yml b/.github/workflows/acme-ci.yml index 70dc378..d8b5c22 100644 --- a/.github/workflows/acme-ci.yml +++ b/.github/workflows/acme-ci.yml @@ -48,8 +48,9 @@ jobs: - run: npm ci - run: npm run profile:cpu env: - PROFILE_DURATION_MS: 45000 - PROFILE_CPU_WORKERS: 8 + PROFILE_CPU_TASKS: 32 + PROFILE_CPU_ITERATIONS: 300000000 + PROFILE_CPU_WORKERS: 16 unit-tests: name: Unit tests shard ${{ matrix.shard }}/8 diff --git a/solutions-engineering/migration-lab/app/scripts/resource-profile.js b/solutions-engineering/migration-lab/app/scripts/resource-profile.js index d66a5f1..318fed5 100644 --- a/solutions-engineering/migration-lab/app/scripts/resource-profile.js +++ b/solutions-engineering/migration-lab/app/scripts/resource-profile.js @@ -9,19 +9,26 @@ function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } -function burnCpu(ms) { - const end = Date.now() + ms; +function iterationCount() { + return Number(process.env.PROFILE_CPU_ITERATIONS || 45000000); +} + +function taskCount() { + return Number(process.env.PROFILE_CPU_TASKS || 32); +} + +function burnIterations(iterations) { let value = 0; - while (Date.now() < end) { - value += Math.sqrt((value % 1000) + Math.random()); + for (let i = 0; i < iterations; i += 1) { + value += Math.sqrt((value + i) % 1000); } return value; } if (!isMainThread) { - const value = burnCpu(workerData.durationMs); + const value = burnIterations(workerData.iterations); parentPort.postMessage(value); return; } @@ -34,24 +41,37 @@ async function runIdleProfile() { console.log('background report profile completed'); } +function runCpuTask(iterations) { + return new Promise((resolve, reject) => { + const worker = new Worker(__filename, { workerData: { iterations } }); + worker.once('message', resolve); + worker.once('error', reject); + worker.once('exit', (code) => { + if (code !== 0) { + reject(new Error(`worker exited with code ${code}`)); + } + }); + }); +} + async function runCpuProfile() { - const duration = durationMs(); - const workers = Number(process.env.PROFILE_CPU_WORKERS || Math.max(4, os.cpus().length * 2)); + const workers = Number(process.env.PROFILE_CPU_WORKERS || Math.max(2, os.cpus().length)); + const tasks = taskCount(); + const iterations = iterationCount(); + let nextTask = 0; - console.log(`starting fraud model profile with workers=${workers} duration_ms=${duration}`); + console.log(`starting fraud model profile with workers=${workers} tasks=${tasks} iterations_per_task=${iterations}`); console.log(`detected_cpu_count=${os.cpus().length}`); + async function runWorkerQueue() { + while (nextTask < tasks) { + nextTask += 1; + await runCpuTask(iterations); + } + } + await Promise.all( - Array.from({ length: workers }, () => new Promise((resolve, reject) => { - const worker = new Worker(__filename, { workerData: { durationMs: duration } }); - worker.once('message', resolve); - worker.once('error', reject); - worker.once('exit', (code) => { - if (code !== 0) { - reject(new Error(`worker exited with code ${code}`)); - } - }); - })), + Array.from({ length: Math.min(workers, tasks) }, () => runWorkerQueue()), ); console.log('fraud model profile completed'); From 82d6f7e192defa24c13d0d1142ed776aa64db1e5 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 16 May 2026 12:25:37 -0400 Subject: [PATCH 2/3] solutions-engineering: lengthen fixed-work CPU benchmark Increase the fraud benchmark work size so the initial 4-vCPU migration takes about a minute while larger runners can show meaningful speedup. Co-authored-by: Cursor --- .github/workflows/acme-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acme-ci.yml b/.github/workflows/acme-ci.yml index d8b5c22..2915705 100644 --- a/.github/workflows/acme-ci.yml +++ b/.github/workflows/acme-ci.yml @@ -49,7 +49,7 @@ jobs: - run: npm run profile:cpu env: PROFILE_CPU_TASKS: 32 - PROFILE_CPU_ITERATIONS: 300000000 + PROFILE_CPU_ITERATIONS: 750000000 PROFILE_CPU_WORKERS: 16 unit-tests: From 9f35b8cef8cf92e4088c998a01f8be7ca8183f1c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 16 May 2026 12:43:00 -0400 Subject: [PATCH 3/3] solutions-engineering: use crypto CPU benchmark Switch the fraud benchmark to a native crypto workload split into smaller tasks so runner CPU sizing produces a clearer performance delta. Co-authored-by: Cursor --- .github/workflows/acme-ci.yml | 6 +++--- .../app/scripts/resource-profile.js | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/acme-ci.yml b/.github/workflows/acme-ci.yml index 2915705..22ed623 100644 --- a/.github/workflows/acme-ci.yml +++ b/.github/workflows/acme-ci.yml @@ -48,9 +48,9 @@ jobs: - run: npm ci - run: npm run profile:cpu env: - PROFILE_CPU_TASKS: 32 - PROFILE_CPU_ITERATIONS: 750000000 - PROFILE_CPU_WORKERS: 16 + PROFILE_CPU_TASKS: 256 + PROFILE_CPU_ITERATIONS: 6250000 + PROFILE_CPU_WORKERS: 32 unit-tests: name: Unit tests shard ${{ matrix.shard }}/8 diff --git a/solutions-engineering/migration-lab/app/scripts/resource-profile.js b/solutions-engineering/migration-lab/app/scripts/resource-profile.js index 318fed5..587ad4b 100644 --- a/solutions-engineering/migration-lab/app/scripts/resource-profile.js +++ b/solutions-engineering/migration-lab/app/scripts/resource-profile.js @@ -1,4 +1,5 @@ const os = require('os'); +const crypto = require('crypto'); const { Worker, isMainThread, parentPort, workerData } = require('worker_threads'); function durationMs() { @@ -17,18 +18,20 @@ function taskCount() { return Number(process.env.PROFILE_CPU_TASKS || 32); } -function burnIterations(iterations) { - let value = 0; - - for (let i = 0; i < iterations; i += 1) { - value += Math.sqrt((value + i) % 1000); - } +function runFraudScoringBatch(iterations) { + const output = crypto.pbkdf2Sync( + 'acme-payments-risk-input', + 'merchant-risk-model-v3', + iterations, + 64, + 'sha512', + ); - return value; + return output.readUInt32BE(0); } if (!isMainThread) { - const value = burnIterations(workerData.iterations); + const value = runFraudScoringBatch(workerData.iterations); parentPort.postMessage(value); return; }