tracing-context: optimize Visit impl (#94)

* tracing-context: optimize Visit impl
This commit is contained in:
Toby Lawrence 2020-09-27 15:32:10 -04:00 committed by GitHub
parent 1ed5f7fd63
commit 72602ce6fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 229 additions and 21 deletions

View File

@ -24,7 +24,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
rust_version: ['1.36.0', 'stable', 'nightly']
rust_version: ['1.42.0', 'stable', 'nightly']
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1

3
metrics-tracing-context/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock

View File

@ -15,12 +15,21 @@ readme = "README.md"
categories = ["development-tools::debugging"]
keywords = ["metrics", "tracing"]
[lib]
bench = false
[[bench]]
name = "visit"
harness = false
[dependencies]
metrics = { version = "0.13.0-alpha.1", path = "../metrics", features = ["std"] }
metrics-util = { version = "0.4.0-alpha.1", path = "../metrics-util" }
tracing = "0.1"
tracing-core = "0.1"
tracing-subscriber = "0.2"
itoa = "0.4"
[dev-dependencies]
criterion = "0.3"
parking_lot = "0.11"

View File

@ -0,0 +1,183 @@
use criterion::{criterion_group, criterion_main, BatchSize, Benchmark, Criterion};
use metrics_tracing_context::Labels;
use tracing::Metadata;
use tracing_core::{
field::Visit,
metadata,
metadata::{Kind, Level},
Callsite, Interest,
};
const BATCH_SIZE: usize = 1000;
static CALLSITE: TestCallsite = TestCallsite;
static CALLSITE_METADATA: Metadata = metadata! {
name: "test",
target: module_path!(),
level: Level::DEBUG,
fields: &["test"],
callsite: &CALLSITE,
kind: Kind::SPAN,
};
fn visit_benchmark(c: &mut Criterion) {
c.bench(
"visit",
Benchmark::new("record_str", |b| {
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_str(&field, "test test");
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_bool[true]", |b| {
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_bool(&field, true);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_bool[false]", |b| {
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_bool(&field, false);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_i64", |b| {
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_i64(&field, -3423432);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_u64", |b| {
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_u64(&field, 3423432);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_debug", |b| {
let debug_struct = DebugStruct::new();
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_debug(&field, &debug_struct);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_debug[bool]", |b| {
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_debug(&field, &true);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_debug[i64]", |b| {
let value: i64 = -3423432;
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_debug(&field, &value);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
})
.with_function("record_debug[u64]", |b| {
let value: u64 = 3423432;
let field = CALLSITE
.metadata()
.fields()
.field("test")
.expect("test field missing");
b.iter_batched_ref(
|| Labels(Vec::with_capacity(BATCH_SIZE)),
|labels| {
labels.record_debug(&field, &value);
},
BatchSize::NumIterations(BATCH_SIZE as u64),
)
}),
);
}
#[derive(Debug)]
struct DebugStruct {
field1: String,
field2: u64,
}
impl DebugStruct {
pub fn new() -> DebugStruct {
DebugStruct {
field1: format!("yeehaw!"),
field2: 324242343243,
}
}
}
struct TestCallsite;
impl Callsite for TestCallsite {
fn set_interest(&self, _interest: Interest) {}
fn metadata(&self) -> &Metadata<'_> {
&CALLSITE_METADATA
}
}
criterion_group!(benches, visit_benchmark);
criterion_main!(benches);

View File

@ -63,7 +63,7 @@ pub mod label_filter;
mod tracing_integration;
pub use label_filter::LabelFilter;
pub use tracing_integration::{MetricsLayer, SpanExt};
pub use tracing_integration::{Labels, MetricsLayer, SpanExt};
/// [`TracingContextLayer`] provides an implementation of a [`metrics::Layer`]
/// for [`TracingContext`].

View File

@ -6,7 +6,12 @@ use tracing_core::span::{Attributes, Id, Record};
use tracing_core::{field::Visit, Dispatch, Field, Subscriber};
use tracing_subscriber::{layer::Context, registry::LookupSpan, Layer};
struct Labels(Vec<Label>);
/// Per-span extension for collecting labels from fields.
///
/// Hidden from documentation as there is no need for end users to ever touch this type, but it must
/// be public in order to be pulled in by external benchmark code.
#[doc(hidden)]
pub struct Labels(pub Vec<Label>);
impl Visit for Labels {
fn record_str(&mut self, field: &Field, value: &str) {
@ -14,6 +19,27 @@ impl Visit for Labels {
self.0.push(label);
}
fn record_bool(&mut self, field: &Field, value: bool) {
let label = Label::new(field.name(), if value { "true" } else { "false " });
self.0.push(label);
}
fn record_i64(&mut self, field: &Field, value: i64) {
// Maximum length is 20 characters but 32 is a nice power-of-two number.
let mut s = String::with_capacity(32);
itoa::fmt(&mut s, value).expect("failed to format/write i64");
let label = Label::new(field.name(), s);
self.0.push(label);
}
fn record_u64(&mut self, field: &Field, value: u64) {
// Maximum length is 20 characters but 32 is a nice power-of-two number.
let mut s = String::with_capacity(32);
itoa::fmt(&mut s, value).expect("failed to format/write u64");
let label = Label::new(field.name(), s);
self.0.push(label);
}
fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
let value_string = format!("{:?}", value);
let label = Label::new(field.name(), value_string);

View File

@ -1,10 +1,5 @@
#[macro_use]
extern crate criterion;
#[macro_use]
extern crate lazy_static;
use criterion::{Benchmark, Criterion, Throughput};
use criterion::{criterion_group, criterion_main, Benchmark, Criterion, Throughput};
use lazy_static::lazy_static;
use metrics_util::AtomicBucket;
lazy_static! {

View File

@ -1,7 +1,4 @@
#[macro_use]
extern crate criterion;
use criterion::{BatchSize, Benchmark, Criterion};
use criterion::{criterion_group, criterion_main, BatchSize, Benchmark, Criterion};
use metrics::{Key, KeyData, Label, OnceKeyData};
use metrics_util::Registry;

View File

@ -1,10 +1,5 @@
#[macro_use]
extern crate criterion;
#[macro_use]
extern crate lazy_static;
use criterion::{Benchmark, Criterion, Throughput};
use criterion::{criterion_group, criterion_main, Benchmark, Criterion, Throughput};
use lazy_static::lazy_static;
use metrics_util::StreamingIntegers;
use rand::{distributions::Distribution, rngs::SmallRng, SeedableRng};
use rand_distr::Gamma;