From a7493fcef519bc6bc113a6b2a63c5aa1939d7c7f Mon Sep 17 00:00:00 2001 From: Runloop Agent Date: Tue, 17 Mar 2026 09:21:17 +0000 Subject: [PATCH] perf(bmj): parallelize scenario log downloads with max concurrency of 50 Replace the serial download loop in `bmj logs` with a concurrent executor capped at 50 simultaneous downloads. This significantly reduces wall-clock time when a job has many scenarios. Output lines are printed atomically as each download completes. Co-Authored-By: Claude Sonnet 4.6 --- src/commands/benchmark-job/logs.ts | 44 ++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/commands/benchmark-job/logs.ts b/src/commands/benchmark-job/logs.ts index d434210..4be923d 100644 --- a/src/commands/benchmark-job/logs.ts +++ b/src/commands/benchmark-job/logs.ts @@ -253,6 +253,29 @@ async function downloadScenarioLogs( } } +/** Run tasks in parallel with a maximum concurrency limit */ +async function runWithConcurrency( + tasks: (() => Promise)[], + maxConcurrency: number, +): Promise { + const results: T[] = new Array(tasks.length); + let nextIndex = 0; + + async function worker() { + while (nextIndex < tasks.length) { + const i = nextIndex++; + results[i] = await tasks[i](); + } + } + + const workers = Array.from( + { length: Math.min(maxConcurrency, tasks.length) }, + () => worker(), + ); + await Promise.all(workers); + return results; +} + export async function downloadBenchmarkJobLogs( jobId: string, options: LogsOptions = {}, @@ -326,18 +349,23 @@ export async function downloadBenchmarkJobLogs( `\nDownloading logs for ${targets.length} scenario run(s) to ${chalk.bold(outputDir)}\n`, ); - // Download logs one at a time to avoid overwhelming the API + // Download logs in parallel with a max concurrency of 50 + const MAX_CONCURRENCY = 50; let succeeded = 0; - for (const target of targets) { - process.stdout.write( - ` ${target.agentName} / ${target.scenarioName}... `, - ); + + const tasks = targets.map((target) => async () => { const ok = await downloadScenarioLogs(target); if (ok) { - console.log(chalk.green("done")); - succeeded++; + console.log( + chalk.green(` ✓ ${target.agentName} / ${target.scenarioName}`), + ); + return true; } - } + return false; + }); + + const results = await runWithConcurrency(tasks, MAX_CONCURRENCY); + succeeded = results.filter(Boolean).length; console.log( `\n${chalk.green(`Downloaded logs for ${succeeded}/${targets.length} scenario run(s)`)} to ${chalk.bold(outputDir)}`,