optimize NameParts::to_string

This commit is contained in:
Toby Lawrence 2020-11-15 15:13:47 -05:00
parent db02cd80da
commit 2cd4e9e100
3 changed files with 48 additions and 19 deletions

View File

@ -27,6 +27,10 @@ bench = false
name = "macros"
harness = false
[[bench]]
name = "key"
harness = false
[dependencies]
beef = "0.4"
metrics-macros = { version = "0.1.0-alpha.1", path = "../metrics-macros" }

28
metrics/benches/key.rs Normal file
View File

@ -0,0 +1,28 @@
use criterion::{criterion_group, criterion_main, Benchmark, Criterion};
use metrics::{NameParts, SharedString};
fn key_benchmark(c: &mut Criterion) {
c.bench(
"key",
Benchmark::new("name_parts/to_string", |b| {
static NAME_PARTS: [SharedString; 2] = [
SharedString::const_str("part1"),
SharedString::const_str("part2"),
];
let name = NameParts::from_static_names(&NAME_PARTS);
b.iter(|| name.to_string())
})
.with_function("name_parts/Display::to_string", |b| {
static NAME_PARTS: [SharedString; 2] = [
SharedString::const_str("part1"),
SharedString::const_str("part2"),
];
let name = NameParts::from_static_names(&NAME_PARTS);
b.iter(|| std::fmt::Display::to_string(&name))
}),
);
}
criterion_group!(benches, key_benchmark);
criterion_main!(benches);

View File

@ -45,16 +45,20 @@ impl NameParts {
/// Renders the name parts as a dot-delimited string.
pub fn to_string(&self) -> String {
// This is suboptimal since we're allocating in a bunch of ways.
//
// Might be faster to figure out the string length and then allocate a single string with
// the required capacity, and write into it, potentially pooling them? Dunno, we should
// actually benchmark this. :P
self.0
.iter()
.map(|s| s.as_ref())
.collect::<Vec<_>>()
.join(".")
// It's faster to allocate the string by hand instead of collecting the parts and joining
// them, or deferring to Dsiplay::to_string, or anything else. This may change in the
// future, or benefit from some sort of string pooling, but otherwise, this seemingly
// suboptimal approach -- oh no, a single allocation! :P -- works pretty well overall.
let mut first = false;
let mut s = String::with_capacity(16);
for p in self.0.iter() {
if first {
s.push_str(".");
first = false;
}
s.push_str(p.as_ref());
}
s
}
}
@ -72,15 +76,8 @@ impl From<&'static str> for NameParts {
impl fmt::Display for NameParts {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut first = true;
for s in self.parts() {
if !first {
write!(f, ".{}", s)?;
first = false;
} else {
write!(f, "{}", s)?;
}
}
let s = self.to_string();
f.write_str(s.as_str())?;
Ok(())
}
}