123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
- use std::thread;
- /// This benchmark simulates sending a bunch of strings over a channel. It's
- /// intended to simulate the sort of workload that a `thingbuf` is intended
- /// for, where the type of element in the buffer is expensive to allocate,
- /// copy, or drop, but they can be re-used in place without
- /// allocating/deallocating.
- ///
- /// So, this may not be strictly representative of performance in the case of,
- /// say, sending a bunch of integers over the channel; instead it simulates
- /// the kind of scenario that `thingbuf` is optimized for.
- fn bench_spsc_try_send_reusable(c: &mut Criterion) {
- let mut group = c.benchmark_group("sync/spsc/try_send_reusable");
- static THE_STRING: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
- aaaaaaaaaaaaaa";
- for size in [100, 500, 1_000, 5_000, 10_000] {
- group.throughput(Throughput::Elements(size));
- group.bench_with_input(BenchmarkId::new("ThingBuf", size), &size, |b, &i| {
- b.iter(|| {
- use thingbuf::mpsc::{blocking, errors::TrySendError};
- let (tx, rx) = blocking::channel::<String>(100);
- let producer = thread::spawn(move || loop {
- match tx.try_send_ref() {
- Ok(mut slot) => {
- slot.clear();
- slot.push_str(THE_STRING)
- }
- Err(TrySendError::Closed(_)) => break,
- _ => thread::yield_now(),
- }
- });
- for _ in 0..i {
- let val = rx.recv_ref().unwrap();
- criterion::black_box(val);
- }
- drop(rx);
- producer.join().unwrap();
- })
- });
- #[cfg(feature = "std-sync")]
- group.bench_with_input(BenchmarkId::new("std::sync::mpsc", size), &size, |b, &i| {
- b.iter(|| {
- use std::sync::mpsc::{self, TrySendError};
- let (tx, rx) = mpsc::sync_channel(100);
- let producer = thread::spawn(move || loop {
- match tx.try_send(String::from(THE_STRING)) {
- Ok(()) => {}
- Err(TrySendError::Disconnected(_)) => break,
- _ => thread::yield_now(),
- }
- });
- for _ in 0..i {
- let val = rx.recv().unwrap();
- criterion::black_box(&val);
- }
- drop(rx);
- producer.join().unwrap();
- })
- });
- #[cfg(feature = "crossbeam")]
- group.bench_with_input(
- BenchmarkId::new("crossbeam::channel::bounded", size),
- &size,
- |b, &i| {
- b.iter(|| {
- use crossbeam::channel::{self, TrySendError};
- let (tx, rx) = channel::bounded(100);
- let producer = thread::spawn(move || loop {
- match tx.try_send(String::from(THE_STRING)) {
- Ok(()) => {}
- Err(TrySendError::Disconnected(_)) => break,
- _ => thread::yield_now(),
- }
- });
- for _ in 0..i {
- let val = rx.recv().unwrap();
- criterion::black_box(&val);
- }
- drop(rx);
- producer.join().unwrap();
- })
- },
- );
- }
- group.finish();
- }
- fn bench_spsc_blocking_send_reusable(c: &mut Criterion) {
- let mut group = c.benchmark_group("sync/spsc/blocking_send_reusable");
- static THE_STRING: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
- aaaaaaaaaaaaaa";
- for size in [100, 500, 1_000, 5_000, 10_000] {
- group.throughput(Throughput::Elements(size));
- group.bench_with_input(BenchmarkId::new("ThingBuf", size), &size, |b, &i| {
- b.iter(|| {
- use thingbuf::mpsc::blocking;
- let (tx, rx) = blocking::channel::<String>(100);
- let producer = thread::spawn(move || {
- while let Ok(mut slot) = tx.send_ref() {
- slot.clear();
- slot.push_str(THE_STRING);
- }
- });
- for _ in 0..i {
- let val = rx.recv_ref().unwrap();
- criterion::black_box(val);
- }
- drop(rx);
- producer.join().unwrap();
- })
- });
- #[cfg(feature = "std-sync")]
- group.bench_with_input(BenchmarkId::new("std::sync::mpsc", size), &size, |b, &i| {
- b.iter(|| {
- use std::sync::mpsc;
- let (tx, rx) = mpsc::sync_channel(100);
- let producer =
- thread::spawn(move || while tx.send(String::from(THE_STRING)).is_ok() {});
- for _ in 0..i {
- let val = rx.recv().unwrap();
- criterion::black_box(&val);
- }
- drop(rx);
- producer.join().unwrap();
- })
- });
- #[cfg(feature = "crossbeam")]
- group.bench_with_input(
- BenchmarkId::new("crossbeam::channel::bounded", size),
- &size,
- |b, &i| {
- b.iter(|| {
- use crossbeam::channel;
- let (tx, rx) = channel::bounded(100);
- let producer =
- thread::spawn(move || while tx.send(String::from(THE_STRING)).is_ok() {});
- for _ in 0..i {
- let val = rx.recv().unwrap();
- criterion::black_box(&val);
- }
- drop(rx);
- producer.join().unwrap();
- })
- },
- );
- }
- group.finish();
- }
- criterion_group!(
- benches,
- bench_spsc_try_send_reusable,
- bench_spsc_blocking_send_reusable
- );
- criterion_main!(benches);
|