Parallelize log-archive parsing in unifiedlog_iterator (3-4x speedup)#124
Parallelize log-archive parsing in unifiedlog_iterator (3-4x speedup)#124cvandeplas wants to merge 3 commits into
Conversation
Add per-file parallelism to the log-archive mode using rayon and crossbeam-channel. Each tracev3 file is processed in parallel by a worker thread that reads, parses (build_log), and serializes results to JSONL bytes. A dedicated writer thread receives pre-serialized batches via a bounded channel and writes them out with BufWriter. Key changes: - Add rayon and crossbeam-channel dependencies - Wrap output in BufWriter to reduce write syscalls - New parallel parse_log_archive() using rayon par_iter over files - Workers serialize JSONL in-thread, send Vec<u8> batches to writer - Oversize string resolution deferred to a second pass on writer thread - Live and SingleFile modes remain unchanged (sequential) Performance on a 66-file / 5M-entry logarchive (release build): - Before: 1m14s wall-clock - After: 20.4s wall-clock (~3.6x speedup)
…b only Replace rayon and crossbeam-channel with standard library equivalents: - std::thread::scope + manual worker threads with Mutex<Vec> work queue - std::sync::mpsc::sync_channel (bounded) for worker→writer communication This achieves identical performance (20.2s vs 20.4s) with zero new dependencies added to the project. The work-stealing pattern is implemented via a shared Mutex<Vec> that workers pop from until empty, providing natural load balancing across uneven file sizes.
|
Hello @cvandeplas, |
|
@jrouaix That looks interesting! Would you be able to integrate some of the multiprocessing idea's from this PR and raise a new PR for having those nice things included here? |
Well right now I'm just trying to land a clean PR with "only" the ambitious Then I think (My use case - SAAS - my goal is to consume less CPU, not "same in //" but we could use parallelism as an option for some environements for instance) |
Summary
Adds multi-threaded processing to the
unifiedlog_iteratorexample tool's log-archive mode,reducing wall-clock time from ~74s to ~20s on a 66-file/5M-entry logarchive (release build).
No new dependencies are added — the implementation uses only the Rust standard library.
Approach
Profiling with
perfrevealed that the original bottleneck was split between:build_log()parsing + string resolution (~18%)The changes address these in two steps:
std::io::BufWriter, cutting syscall overhead in half.reads a file, iterates chunks, calls
build_log(), serializes to JSONL bytes, and sendsbatches through a bounded channel to a dedicated writer thread.
We initially implemented this using
rayonandcrossbeam-channel, which achieved identicalperformance. We then replaced both with standard library equivalents (
std::thread::scope,Mutex<Vec>work queue,std::sync::mpsc::sync_channel) and measured no regression —keeping the dependency footprint unchanged.
Changes
BufWriterfor batched write syscallsparse_log_archive()usingstd::thread::scopewith N worker threadsMutex<Vec>work queue (natural load balancing)sync_channelto a writer threadOutputWritergainswrite_raw_bytes()for the parallel path and usesSend-compatible typesPerformance (release build, 66 tracev3 files, 5.05M log entries, 177MB)
Correctness
Verified against the single-threaded baseline output:
messages (non-deterministic by nature, both outputs equally valid)
<Missing message data>