diff --git a/crossbeam-channel/benchmarks/Cargo.toml b/crossbeam-channel/benchmarks/Cargo.toml index d42c645ce..8c86d8582 100644 --- a/crossbeam-channel/benchmarks/Cargo.toml +++ b/crossbeam-channel/benchmarks/Cargo.toml @@ -5,16 +5,15 @@ edition = "2018" publish = false [dependencies] -atomicring = "1.1.1" -bus = "2.0.1" -chan = "0.1.23" +atomicring = "1.2.9" +bus = "2.3.0" crossbeam = { path = "../.." } crossbeam-channel = { path = ".." } crossbeam-deque = { path = "../../crossbeam-deque" } flume = "0.10" futures = { version = "0.3", features = ["thread-pool"] } lockfree = "0.5.1" -mpmc = "0.1.5" +mpmc = "0.1.6" [[bin]] name = "atomicring" @@ -31,11 +30,6 @@ name = "bus" path = "bus.rs" doc = false -[[bin]] -name = "chan" -path = "chan.rs" -doc = false - [[bin]] name = "crossbeam-channel" path = "crossbeam-channel.rs" diff --git a/crossbeam-channel/benchmarks/README.md b/crossbeam-channel/benchmarks/README.md index c5aa3439f..c558fab62 100644 --- a/crossbeam-channel/benchmarks/README.md +++ b/crossbeam-channel/benchmarks/README.md @@ -24,20 +24,20 @@ Runs benchmarks, stores results into `*.txt` files, and generates `plot.png`: Dependencies: -- Rust (nightly) +- Rust - Go - Bash -- Python 2 +- Python - Matplotlib ### Results -Machine: Intel(R) Core(TM) i7-5600U (2 physical cores, 4 logical cores) +Machine: Intel(R) Core(TM) i7-5500U (2 physical cores, 4 logical cores) -Rust: `rustc 1.33.0-nightly (a7be40c65 2018-12-26)` +Rust: `rustc 1.63.0 (4b91a6ea7 2022-08-08)` -Go: `go version go1.11.1 linux/amd64` +Go: `go version go1.19 linux/amd64` -Commit: `779bae9` (2018-12-30) +Commit: `7070018` (2022-08-24) -![Benchmark results](https://i.imgur.com/KFb9GvV.png) +![Benchmark results](plot.png) diff --git a/crossbeam-channel/benchmarks/chan.rs b/crossbeam-channel/benchmarks/chan.rs deleted file mode 100644 index 17f4d9932..000000000 --- a/crossbeam-channel/benchmarks/chan.rs +++ /dev/null @@ -1,201 +0,0 @@ -use chan::chan_select; - -mod message; - -const MESSAGES: usize = 5_000_000; -const THREADS: usize = 4; - -fn new(cap: Option) -> (chan::Sender, chan::Receiver) { - match cap { - None => chan::r#async(), - Some(cap) => chan::sync(cap), - } -} - -fn seq(cap: Option) { - let (tx, rx) = new(cap); - - for i in 0..MESSAGES { - tx.send(message::new(i)); - } - - for _ in 0..MESSAGES { - rx.recv().unwrap(); - } -} - -fn spsc(cap: Option) { - let (tx, rx) = new(cap); - - crossbeam::scope(|scope| { - scope.spawn(|_| { - for i in 0..MESSAGES { - tx.send(message::new(i)); - } - }); - - for _ in 0..MESSAGES { - rx.recv().unwrap(); - } - }) - .unwrap(); -} - -fn mpsc(cap: Option) { - let (tx, rx) = new(cap); - - crossbeam::scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..MESSAGES / THREADS { - tx.send(message::new(i)); - } - }); - } - - for _ in 0..MESSAGES { - rx.recv().unwrap(); - } - }) - .unwrap(); -} - -fn mpmc(cap: Option) { - let (tx, rx) = new(cap); - - crossbeam::scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..MESSAGES / THREADS { - tx.send(message::new(i)); - } - }); - } - - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..MESSAGES / THREADS { - rx.recv().unwrap(); - } - }); - } - }) - .unwrap(); -} - -fn select_rx(cap: Option) { - assert_eq!(THREADS, 4); - let chans = (0..THREADS).map(|_| new(cap)).collect::>(); - - crossbeam::scope(|scope| { - for (tx, _) in &chans { - let tx = tx.clone(); - scope.spawn(move |_| { - for i in 0..MESSAGES / THREADS { - tx.send(message::new(i)); - } - }); - } - - let rx0 = &chans[0].1; - let rx1 = &chans[1].1; - let rx2 = &chans[2].1; - let rx3 = &chans[3].1; - for _ in 0..MESSAGES { - chan_select! { - rx0.recv() -> m => assert!(m.is_some()), - rx1.recv() -> m => assert!(m.is_some()), - rx2.recv() -> m => assert!(m.is_some()), - rx3.recv() -> m => assert!(m.is_some()), - } - } - }) - .unwrap(); -} - -fn select_both(cap: Option) { - assert_eq!(THREADS, 4); - let chans = (0..THREADS).map(|_| new(cap)).collect::>(); - - crossbeam::scope(|scope| { - for _ in 0..THREADS { - let chans = chans.clone(); - scope.spawn(move |_| { - let tx0 = &chans[0].0; - let tx1 = &chans[1].0; - let tx2 = &chans[2].0; - let tx3 = &chans[3].0; - - for i in 0..MESSAGES / THREADS { - chan_select! { - tx0.send(message::new(i)) => {}, - tx1.send(message::new(i)) => {}, - tx2.send(message::new(i)) => {}, - tx3.send(message::new(i)) => {}, - } - } - }); - } - - for _ in 0..THREADS { - let chans = chans.clone(); - scope.spawn(move |_| { - let rx0 = &chans[0].1; - let rx1 = &chans[1].1; - let rx2 = &chans[2].1; - let rx3 = &chans[3].1; - - for _ in 0..MESSAGES / THREADS { - chan_select! { - rx0.recv() -> m => assert!(m.is_some()), - rx1.recv() -> m => assert!(m.is_some()), - rx2.recv() -> m => assert!(m.is_some()), - rx3.recv() -> m => assert!(m.is_some()), - } - } - }); - } - }) - .unwrap(); -} - -fn main() { - macro_rules! run { - ($name:expr, $f:expr) => { - let now = ::std::time::Instant::now(); - $f; - let elapsed = now.elapsed(); - println!( - "{:25} {:15} {:7.3} sec", - $name, - "Rust chan", - elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1e9 - ); - }; - } - - run!("bounded0_mpmc", mpmc(Some(0))); - run!("bounded0_mpsc", mpsc(Some(0))); - run!("bounded0_select_rx", select_rx(Some(0))); - run!("bounded0_spsc", spsc(Some(0))); - - run!("bounded1_mpmc", mpmc(Some(1))); - run!("bounded1_mpsc", mpsc(Some(1))); - run!("bounded1_select_both", select_both(Some(1))); - run!("bounded1_select_rx", select_rx(Some(1))); - run!("bounded1_spsc", spsc(Some(1))); - - run!("bounded_mpmc", mpmc(Some(MESSAGES))); - run!("bounded_mpsc", mpsc(Some(MESSAGES))); - run!("bounded_select_both", select_both(Some(MESSAGES))); - run!("bounded_select_rx", select_rx(Some(MESSAGES))); - run!("bounded_seq", seq(Some(MESSAGES))); - run!("bounded_spsc", spsc(Some(MESSAGES))); - - run!("unbounded_mpmc", mpmc(None)); - run!("unbounded_mpsc", mpsc(None)); - run!("unbounded_select_both", select_both(None)); - run!("unbounded_select_rx", select_rx(None)); - run!("unbounded_seq", seq(None)); - run!("unbounded_spsc", spsc(None)); -} diff --git a/crossbeam-channel/benchmarks/plot.png b/crossbeam-channel/benchmarks/plot.png new file mode 100644 index 000000000..f5ea13ac4 Binary files /dev/null and b/crossbeam-channel/benchmarks/plot.png differ diff --git a/crossbeam-channel/benchmarks/plot.py b/crossbeam-channel/benchmarks/plot.py index 98c733666..8d8235b62 100755 --- a/crossbeam-channel/benchmarks/plot.py +++ b/crossbeam-channel/benchmarks/plot.py @@ -116,7 +116,7 @@ def plot(results, fig, subplot, title, prefix): def plot_all(results, descriptions, labels): fig = plt.figure(figsize=(10, 10)) - # TODO support more number subplots + # TODO support more subplots subplot = [221, 222, 223, 224] for p, d, l in zip(subplot, descriptions, labels): plot(results, fig, p, d, l) diff --git a/crossbeam-channel/benchmarks/run.sh b/crossbeam-channel/benchmarks/run.sh index 099b0e4ef..32db1f0e9 100755 --- a/crossbeam-channel/benchmarks/run.sh +++ b/crossbeam-channel/benchmarks/run.sh @@ -3,10 +3,22 @@ set -euxo pipefail IFS=$'\n\t' cd "$(dirname "$0")" -cargo run --release --bin chan | tee chan.txt cargo run --release --bin crossbeam-channel | tee crossbeam-channel.txt cargo run --release --bin futures-channel | tee futures-channel.txt cargo run --release --bin mpsc | tee mpsc.txt +cargo run --release --bin flume | tee flume.txt go run go.go | tee go.txt +# These can also be run, but too many plot bars mess +# up the plot (they start to overlap). So only 5 contenders +# with the most tests are included by default. + +# cargo run --release --bin atomicringqueue | tee atomicringqueue.txt +# cargo run --release --bin atomicring | tee atomicring.txt +# cargo run --release --bin bus | tee bus.txt +# cargo run --release --bin crossbeam-deque | tee crossbeam-deque.txt +# cargo run --release --bin lockfree | tee lockfree.txt +# cargo run --release --bin segqueue | tee segqueue.txt +# cargo run --release --bin mpmc | tee mpmc.txt + ./plot.py ./*.txt