Perf/cmin parallel processing#434
Open
0xalpharush wants to merge 2 commits into
Open
Conversation
Implements parallel corpus minimization for `cargo fuzz cmin` with intelligent control file reuse to minimize redundant test executions. Key features: - Parallel batch minimization: Splits corpus into batches processed concurrently - Tournament-style merging: Pairwise merge of batches in log₂(N) rounds - Control file optimization: Appends new file lists to existing control files, allowing libFuzzer to skip re-executing already-processed inputs - Automatic temp directory cleanup: All temp files created under single root - CPU detection: Defaults to number of available CPUs with --jobs flag - Handles odd batch counts gracefully Implementation details: - Added `jobs` parameter to Cmin struct with CPU auto-detection - Created helper functions: calculate_effective_workers, link_or_copy_files - Minimum batch size of 100 files to avoid excessive parallelization overhead - Uses hard links with fallback to copy for cross-filesystem compatibility - Filters batch directories precisely (batch-N only, not batch-N-input/output) - Merges control file entries to track processed files across tournament rounds - Reuses batch directories to maintain control file path validity Performance characteristics: - Execution overhead: ~(1 + log₂(W)) × N executions for W workers - Wall-clock speedup: W / (1 + log₂(W)) without redundancy - Control file optimization provides 2x speedup per merge when files are redundant - Scales better with more workers and larger corpora 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Switch cmin to a coordinator/worker merge queue backed by crossbeam channels so merging can begin as soon as batches finish rather than waiting for the whole Rayon phase. This keeps CPU busy by overlapping minimization and tournament merging, reduces lock contention, and avoids head-of-line blocking for large corpora. Also adds a size strategy to force a globally optimal single-worker minset.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add a cmin strategy
speedwhich batches corpora into N workers and merges workers in pairs until single, minimized corpora is produced. In my experiment, this is about 10x faster and results in about 35% more files. The minset is still correct, but we are not adding thesizeconstraint that libfuzzer has (it will replace 2 files with 1 if it covers the same edges but is smaller).Initially, I tried implementing this like
coveragewhich can be run in parallel batches and aggregated at the very end. It offered some performance benefits but still had to execute about half the initial corpus serially. In order to benefit from more rounds of parallel batches and not incur too much re-execution overhead, I exploited the interrupt-recovery mechanism in libfuzzer's control file to merge batches pairwise. For example, if we merge batch A and batch B, we effectively cache the features and coverage info of A, requiring libfuzzer to only re-run B to minimize A and B. While this is only approximating the global optima wrt to size, sometimes the speed is worth it.Because each round experiences reduction and we can cache half the inputs each round, we re-execute inputs far less than if we were not to use the caching and perform pairwise merging.
sizestrategyspeedstrategy