Skip to content

FE-1314: Run experiment runs in parallel across workers - #9162

Draft
kube wants to merge 1 commit into
mainfrom
cf/fe-1314-run-experiment-runs-in-parallel-across-workers
Draft

FE-1314: Run experiment runs in parallel across workers#9162
kube wants to merge 1 commit into
mainfrom
cf/fe-1314-run-experiment-runs-in-parallel-across-workers

Conversation

@kube

@kube kube commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

An experiment ran every one of its runs in a single Web Worker, so a 1000-run experiment used one core however many the machine had.

Runs are independent — separate seed, separate RNG state, separate frame buffers, no shared mutable state — so they can be split across workers. This shards them, by default one worker per logical core minus one so the editor stays responsive.

Measured on the SIR example, 2000 runs, 10-core machine: ~4.1× at 8 shards, with byte-identical merged output at every shard count.

🔗 Related links

🔍 What does this change?

Sharding must not change what an experiment reports. Two things make that hold:

  • Seeds derive from the run's global index, not its position within a shard, so run i gets the same seed whichever worker owns it.
  • A frame is finalised only once every still-running shard has reported it, with finished shards dropped from the watermark rather than blocking it.

frameValue on a scalar metric frame is already reduced and cannot be merged — a mean of means is not a mean — so frames now carry their pre-reduction accumulator state, which the metric monoids (empty/merge) recombine.

No SharedArrayBuffer is needed: the app is not cross-origin isolated, and message-passing shards over independent runs need no shared memory.

// Hosts can cap or pin parallelism; omitted means one per core, minus one.
<ExperimentsProvider workerFactory={createWorker} experimentShardCount={4}>
flowchart LR
  E[Experiment: N runs] --> P{shard plan}
  P -->|runs 0..k| W1[Worker 1]
  P -->|runs k..2k| W2[Worker 2]
  P -->|runs 2k..N| W3[Worker 3]
  W1 & W2 & W3 -->|per-frame accumulator state| M[merge monoid]
  M --> R[frame finalised at the slowest shard]
Loading

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s)

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

Several experiments running at once each take the same number of workers, so they compete for cores and all slow down. Progress reports the slowest shard's position, so the bar never runs ahead of the results behind it.

🐾 Next steps

Stacked on top of this: place token capacity (FE-1237), a swappable backend interface (FE-1341), and the WebGPU backend (FE-1340).

🛡 What tests cover this?

shard-plan.test.ts covers the split; metrics/merge.test.ts covers monoid recombination; experiment.test.ts covers the shard watermark and that output is identical at every shard count. Benchmarks under benchmarks/sharded-experiment*.mjs.

❓ How to test this?

  1. Check out the branch and run an experiment with a few thousand runs.
  2. Confirm it finishes materially faster than on main, and that CPU use spans several cores.
  3. Re-run with the same seed and experimentShardCount set to 1, then unset — the reported distributions should be identical.

@kube kube self-assigned this Aug 4, 2026
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview Aug 8, 2026 1:13am
petrinaut Ready Ready Preview Aug 8, 2026 1:13am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Aug 8, 2026 1:13am

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team labels Aug 4, 2026
@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 4, 2026 23:02 Inactive
@github-actions github-actions Bot added the area/deps Relates to third-party dependencies (area) label Aug 5, 2026
Comment thread libs/@hashintel/petrinaut-core/src/webgpu/emit-wgsl.ts Fixed
@github-actions github-actions Bot added the area/apps > hash.design Affects the `hash.design` design site (app) label Aug 5, 2026
An experiment ran every run in a single worker, using one core however
many the machine had. Runs are independent, so they now split across
one worker per logical core minus one, capped at the run count —
measured at ~4x on 8 shards.

Sharding cannot change results: seeds derive from the run's global
index rather than its position in a shard, and per-frame statistics
recombine through the metric accumulator monoids, so output is
byte-identical at every shard count. Scalar frames carry their
pre-reduction accumulator state, since a mean of means is not a mean.
@kube
kube force-pushed the cf/fe-1314-run-experiment-runs-in-parallel-across-workers branch from 0b5348e to 986094b Compare August 8, 2026 01:02
@github-actions github-actions Bot removed area/deps Relates to third-party dependencies (area) area/apps > hash.design Affects the `hash.design` design site (app) labels Aug 8, 2026
@kube kube changed the title FE-1314, FE-1237: Run experiments in parallel across workers, add place token capacity FE-1314: Run experiment runs in parallel across workers Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

2 participants