bheisler / iai

Experimental one-shot benchmarking/profiling harness for Rust
Apache License 2.0
578 stars 23 forks source link

Iai hangs when the benchmark calls JoinHandle::join #38

Open Pr0methean opened 8 months ago

Pr0methean commented 8 months ago

This benchmark currently hangs when run with $n = 0, $threads = 2 and RESEEDING_THRESHOLD = 1024.

In addition to the two threads spawned by the benchmark code, BenchmarkSharedBufferRng::new spawns another thread (at minimum priority) that reads from OsRng in batches and writes to a bounded crossbeam channel. new_standard_rng creates ReseedingRng instances that try_recv from that channel, only calling OsRng themselves if the channel is empty. The seed-sending thread exits when the rngs are both dropped. Full source code is at https://github.com/Pr0methean/shared_buffer_rng/tree/03e0448033644bce2cd1e8d2f769fd8a8c926681. A version of this benchmark that uses fire-and-forget threads (by replacing ITERATIONS_LEFT with a function-scoped Arc) runs fine, at least when the process runs only one such benchmark.

            fn [< contended_bench_ $n _shared_buffer >]() {
                ITERATIONS_LEFT.store(2 * RESEEDING_THRESHOLD * $n.max(1), SeqCst);
                let root = BenchmarkSharedBufferRng::<$n>::new(OsRng::default());
                let rngs: Vec<_> = (0..$threads)
                    .map(|_| root.new_standard_rng(RESEEDING_THRESHOLD))
                    .collect();
                drop(root);
                let background_threads: Vec<_> = rngs.into_iter()
                    .map(|mut rng| {
                        spawn(move || {
                            while ITERATIONS_LEFT.fetch_sub(1, SeqCst) > 0 {
                                black_box(rng.next_u64());
                            }
                        })
                    })
                    .collect();
                background_threads
                    .into_iter()
                    .for_each(|handle| handle.join().unwrap());
            }