sync_mpsc.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
  2. use std::thread;
  3. /// This benchmark simulates sending a bunch of strings over a channel. It's
  4. /// intended to simulate the sort of workload that a `thingbuf` is intended
  5. /// for, where the type of element in the buffer is expensive to allocate,
  6. /// copy, or drop, but they can be re-used in place without
  7. /// allocating/deallocating.
  8. ///
  9. /// So, this may not be strictly representative of performance in the case of,
  10. /// say, sending a bunch of integers over the channel; instead it simulates
  11. /// the kind of scenario that `thingbuf` is optimized for.
  12. fn bench_spsc_reusable(c: &mut Criterion) {
  13. let mut group = c.benchmark_group("sync/spsc_reusable");
  14. static THE_STRING: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
  15. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
  16. aaaaaaaaaaaaaa";
  17. for size in [100, 500, 1_000, 5_000, 10_000] {
  18. group.throughput(Throughput::Elements(size));
  19. group.bench_with_input(BenchmarkId::new("ThingBuf", size), &size, |b, &i| {
  20. b.iter(|| {
  21. use thingbuf::{
  22. mpsc::{sync, TrySendError},
  23. ThingBuf,
  24. };
  25. let (tx, rx) = sync::channel(ThingBuf::new(100));
  26. let producer = thread::spawn(move || loop {
  27. match tx.try_send_ref() {
  28. Ok(mut r) => r.with_mut(|s: &mut String| {
  29. s.clear();
  30. s.push_str(THE_STRING)
  31. }),
  32. Err(TrySendError::Closed(_)) => break,
  33. _ => thread::yield_now(),
  34. }
  35. });
  36. for _ in 0..i {
  37. let r = rx.recv_ref().unwrap();
  38. r.with(|val| {
  39. criterion::black_box(val);
  40. });
  41. }
  42. drop(rx);
  43. producer.join().unwrap();
  44. })
  45. });
  46. group.bench_with_input(BenchmarkId::new("std::sync::mpsc", size), &size, |b, &i| {
  47. b.iter(|| {
  48. use std::sync::mpsc::{self, TrySendError};
  49. let (tx, rx) = mpsc::sync_channel(100);
  50. let producer = thread::spawn(move || loop {
  51. match tx.try_send(String::from(THE_STRING)) {
  52. Ok(()) => {}
  53. Err(TrySendError::Disconnected(_)) => break,
  54. _ => thread::yield_now(),
  55. }
  56. });
  57. for _ in 0..i {
  58. let val = rx.recv().unwrap();
  59. criterion::black_box(&val);
  60. }
  61. drop(rx);
  62. producer.join().unwrap();
  63. })
  64. });
  65. group.bench_with_input(
  66. BenchmarkId::new("crossbeam::channel::bounded", size),
  67. &size,
  68. |b, &i| {
  69. b.iter(|| {
  70. use crossbeam::channel::{self, TrySendError};
  71. let (tx, rx) = channel::bounded(100);
  72. let producer = thread::spawn(move || loop {
  73. match tx.try_send(String::from(THE_STRING)) {
  74. Ok(()) => {}
  75. Err(TrySendError::Disconnected(_)) => break,
  76. _ => thread::yield_now(),
  77. }
  78. });
  79. for _ in 0..i {
  80. let val = rx.recv().unwrap();
  81. criterion::black_box(&val);
  82. }
  83. drop(rx);
  84. producer.join().unwrap();
  85. })
  86. },
  87. );
  88. }
  89. group.finish();
  90. }
  91. criterion_group!(benches, bench_spsc_reusable);
  92. criterion_main!(benches);