Skip to content

Commit 2405e52

Browse files
bryangarzathekeys93
andcommitted
appender: add initial set of benches
This patch adds blocking and nonblocking benchmarks. This code is from an old PR (tokio-rs#703) that was never merged, and now ported to TOT so that it compiles. Co-authored-by: Zeki Sherif <[email protected]>
1 parent 1e414b3 commit 2405e52

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

tracing-appender/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ default-features = false
3232
features = ["fmt", "std"]
3333

3434
[dev-dependencies]
35+
criterion = { version = "0.3", default_features = false }
3536
tracing = { path = "../tracing", version = "0.2" }
3637
time = { version = "0.3", default-features = false, features = ["formatting", "parsing"] }
3738
tempfile = "3"
39+
40+
[[bench]]
41+
name = "bench"
42+
harness = false

tracing-appender/benches/bench.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
use crossbeam_channel::{unbounded, Receiver, Sender};
3+
use std::sync::{Arc, Mutex};
4+
use std::thread;
5+
use std::thread::JoinHandle;
6+
use std::time::Instant;
7+
use tracing::{event, Level};
8+
use tracing_appender::non_blocking;
9+
use tracing_subscriber::fmt::MakeWriter;
10+
11+
#[derive(Clone)]
12+
struct SynchronousWriter {
13+
writer: Arc<Mutex<Vec<u8>>>,
14+
}
15+
16+
impl SynchronousWriter {
17+
fn new() -> SynchronousWriter {
18+
SynchronousWriter {
19+
writer: Arc::new(Mutex::new(Vec::new())),
20+
}
21+
}
22+
}
23+
24+
impl<'a> MakeWriter<'a> for SynchronousWriter {
25+
type Writer = SynchronousWriter;
26+
27+
fn make_writer(&self) -> Self::Writer {
28+
self.clone()
29+
}
30+
}
31+
32+
impl std::io::Write for SynchronousWriter {
33+
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
34+
let buf_len = buf.len();
35+
match self.writer.lock() {
36+
Ok(mut guard) => {
37+
guard.extend_from_slice(buf);
38+
}
39+
Err(e) => {
40+
eprintln!("Failed to acquire lock: {:?}", e);
41+
}
42+
}
43+
Ok(buf_len)
44+
}
45+
46+
fn flush(&mut self) -> std::io::Result<()> {
47+
Ok(())
48+
}
49+
}
50+
51+
/// A cheap writer so that we don't spam console if we had used stdout
52+
#[derive(Clone)]
53+
struct SilentWriter {
54+
tx: Sender<String>,
55+
}
56+
57+
impl SilentWriter {
58+
fn new() -> (Self, Receiver<String>) {
59+
let (tx, rx) = unbounded();
60+
(Self { tx }, rx)
61+
}
62+
}
63+
64+
impl std::io::Write for SilentWriter {
65+
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
66+
let buf_len = buf.len();
67+
let _ = self.tx.send(String::from_utf8_lossy(buf).to_string());
68+
Ok(buf_len)
69+
}
70+
71+
fn flush(&mut self) -> std::io::Result<()> {
72+
Ok(())
73+
}
74+
}
75+
76+
impl<'a> MakeWriter<'a> for SilentWriter {
77+
type Writer = SilentWriter;
78+
79+
fn make_writer(&self) -> Self::Writer {
80+
self.clone()
81+
}
82+
}
83+
84+
fn synchronous_benchmark(c: &mut Criterion) {
85+
let mut group = c.benchmark_group("synchronous");
86+
group.bench_function("single_thread", |b| {
87+
let subscriber = tracing_subscriber::fmt().with_writer(SynchronousWriter::new());
88+
tracing::collect::with_default(subscriber.finish(), || {
89+
b.iter(|| event!(Level::INFO, "event"))
90+
});
91+
});
92+
93+
group.bench_function("multiple_writers", |b| {
94+
b.iter_custom(|iters| {
95+
let mut handles: Vec<JoinHandle<()>> = Vec::new();
96+
97+
let start = Instant::now();
98+
99+
let make_writer = SynchronousWriter::new();
100+
let cloned_make_writer = make_writer.clone();
101+
102+
handles.push(thread::spawn(move || {
103+
let subscriber = tracing_subscriber::fmt().with_writer(make_writer);
104+
tracing::collect::with_default(subscriber.finish(), || {
105+
for _ in 0..iters {
106+
event!(Level::INFO, "event");
107+
}
108+
});
109+
}));
110+
111+
handles.push(thread::spawn(move || {
112+
let subscriber = tracing_subscriber::fmt().with_writer(cloned_make_writer);
113+
tracing::collect::with_default(subscriber.finish(), || {
114+
for _ in 0..iters {
115+
event!(Level::INFO, "event");
116+
}
117+
});
118+
}));
119+
120+
for handle in handles {
121+
let _ = handle.join();
122+
}
123+
124+
start.elapsed()
125+
});
126+
});
127+
}
128+
129+
fn non_blocking_benchmark(c: &mut Criterion) {
130+
let mut group = c.benchmark_group("non_blocking");
131+
132+
group.bench_function("single_thread", |b| {
133+
let (silent_writer, _rx) = SilentWriter::new();
134+
let (non_blocking, _guard) = non_blocking(silent_writer);
135+
let subscriber = tracing_subscriber::fmt().with_writer(non_blocking);
136+
137+
tracing::collect::with_default(subscriber.finish(), || {
138+
b.iter(|| event!(Level::INFO, "event"))
139+
});
140+
});
141+
142+
group.bench_function("multiple_writers", |b| {
143+
b.iter_custom(|iters| {
144+
let (silent_writer, _rx) = SilentWriter::new();
145+
let (non_blocking, _guard) = non_blocking(silent_writer);
146+
147+
let mut handles: Vec<JoinHandle<()>> = Vec::new();
148+
149+
let start = Instant::now();
150+
151+
let cloned_make_writer = non_blocking.clone();
152+
153+
handles.push(thread::spawn(move || {
154+
let subscriber = tracing_subscriber::fmt().with_writer(non_blocking);
155+
tracing::collect::with_default(subscriber.finish(), || {
156+
for _ in 0..iters {
157+
event!(Level::INFO, "event");
158+
}
159+
});
160+
}));
161+
162+
handles.push(thread::spawn(move || {
163+
let subscriber = tracing_subscriber::fmt().with_writer(cloned_make_writer);
164+
tracing::collect::with_default(subscriber.finish(), || {
165+
for _ in 0..iters {
166+
event!(Level::INFO, "event");
167+
}
168+
});
169+
}));
170+
171+
for handle in handles {
172+
let _ = handle.join();
173+
}
174+
175+
start.elapsed()
176+
});
177+
});
178+
}
179+
180+
criterion_group!(benches, synchronous_benchmark, non_blocking_benchmark);
181+
criterion_main!(benches);

0 commit comments

Comments
 (0)