Skip to content

Fork alpharush invariant executor to use real multi-worker parallelism #9

@aviggiano

Description

@aviggiano

Problem

The Foundry baseline in scfuzzbench is not saturating CPU during invariant campaigns even when we pass --threads.

Concrete example:

PR #9 adds extra invariant_noop_* functions to the target to keep the machine busier, but that is only inflating invariant-check overhead. It is not the real fix.

Diagnosis

This is not a scfuzzbench runner misconfiguration.

scfuzzbench already passes --threads to Foundry in fuzzers/foundry/run.sh when FOUNDRY_THREADS is set.

The real bottleneck is in the invariant execution model inherited from alpharush:

  • suite-level parallelism is across contracts, but scfuzzbench runs forge test --mc CryticToFoundry, so there is only one suite to execute.
  • crates/forge/src/runner.rs keeps only the first invariant function as the top-level test entrypoint with the comment: Only keep the first invariant function — the campaign checks all invariant_fns.
  • crates/evm/evm/src/executors/invariant/mod.rs runs a single sequential while continue_campaign(runs) campaign.
  • the same invariant executor creates exactly one worker corpus with WorkerCorpus::new(0, ...).
  • by contrast, the ordinary fuzz executor in crates/evm/evm/src/executors/fuzz/mod.rs already has a real multi-worker model using rayon and num_workers.

So the current behavior is:

  • --threads helps when there are multiple contracts/suites.
  • for one large invariant suite, CPU utilization stays low because the invariant campaign itself is effectively single-worker.
  • adding noop invariants does not create principled parallelism; it just adds more checks inside the same campaign.

Desired fix

Fork alpharush into aviggiano/foundry and implement real multi-worker parallelism for invariant campaigns.

Concretely:

  1. Reuse the fuzz executor's worker model as the design reference.
  2. Allow a single invariant campaign to fan out across multiple workers when --threads > 1.
  3. Preserve existing failure persistence, shrinking, and replay semantics.
  4. Keep determinism expectations reasonable for seeded runs.
  5. Add a regression/benchmark test that shows one-contract invariant suites can scale with threads instead of requiring target-side noop padding.

Non-goals

  • Do not rely on target-side hacks like extra noop invariants.
  • Do not push this burden into scfuzzbench if the real limitation is inside Foundry's invariant executor.

Acceptance signal

On a single-contract benchmark like CryticToFoundry, increasing --threads should materially increase CPU utilization and throughput during invariant campaigns, without needing PR 9 style target inflation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions