From a63d99fd11b9a8dc6b65789058f516011032faf4 Mon Sep 17 00:00:00 2001 From: sakridge Date: Mon, 16 May 2022 15:39:33 -0500 Subject: [PATCH] Use write! to fix clippy and save heap allocation (#25220) --- metrics/benches/metrics.rs | 22 ++++++++++++++++- metrics/src/metrics.rs | 49 ++++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/metrics/benches/metrics.rs b/metrics/benches/metrics.rs index 7afa48786e..112d0c2035 100644 --- a/metrics/benches/metrics.rs +++ b/metrics/benches/metrics.rs @@ -8,12 +8,32 @@ use { solana_metrics::{ counter::CounterPoint, datapoint::DataPoint, - metrics::{test_mocks::MockMetricsWriter, MetricsAgent}, + metrics::{serialize_points, test_mocks::MockMetricsWriter, MetricsAgent}, }, std::{sync::Arc, time::Duration}, test::Bencher, }; +#[bench] +fn bench_write_points(bencher: &mut Bencher) { + let points = (0..10) + .into_iter() + .map(|_| { + DataPoint::new("measurement") + .add_field_i64("i", 0) + .add_field_i64("abc123", 2) + .add_field_i64("this-is-my-very-long-field-name", 3) + .clone() + }) + .collect(); + let host_id = "benchmark-host-id"; + bencher.iter(|| { + for _ in 0..10 { + test::black_box(serialize_points(&points, host_id)); + } + }) +} + #[bench] fn bench_datapoint_submission(bencher: &mut Bencher) { let writer = Arc::new(MockMetricsWriter::new()); diff --git a/metrics/src/metrics.rs b/metrics/src/metrics.rs index e9e4fc2ed2..48c97101f4 100644 --- a/metrics/src/metrics.rs +++ b/metrics/src/metrics.rs @@ -12,6 +12,7 @@ use { collections::HashMap, convert::Into, env, + fmt::Write, sync::{Arc, Barrier, Mutex, Once, RwLock}, thread, time::{Duration, Instant, UNIX_EPOCH}, @@ -77,6 +78,35 @@ impl InfluxDbMetricsWriter { } } +pub fn serialize_points(points: &Vec, host_id: &str) -> String { + const TIMESTAMP_LEN: usize = 20; + const HOST_ID_LEN: usize = 8; // "host_id=".len() + const EXTRA_LEN: usize = 2; // "=,".len() + let mut len = 0; + for point in points { + for (name, value) in &point.fields { + len += name.len() + value.len() + EXTRA_LEN; + } + len += point.name.len(); + len += TIMESTAMP_LEN; + len += host_id.len() + HOST_ID_LEN; + } + let mut line = String::with_capacity(len); + for point in points { + let _ = write!(line, "{},host_id={}", &point.name, host_id); + + let mut first = true; + for (name, value) in point.fields.iter() { + let _ = write!(line, "{}{}={}", if first { ' ' } else { ',' }, name, value); + first = false; + } + let timestamp = point.timestamp.duration_since(UNIX_EPOCH); + let nanos = timestamp.unwrap().as_nanos(); + let _ = writeln!(line, " {}", nanos); + } + line +} + impl MetricsWriter for InfluxDbMetricsWriter { fn write(&self, points: Vec) { if let Some(ref write_url) = self.write_url { @@ -84,24 +114,7 @@ impl MetricsWriter for InfluxDbMetricsWriter { let host_id = HOST_ID.read().unwrap(); - let mut line = String::new(); - for point in points { - line.push_str(&format!("{},host_id={}", &point.name, &host_id)); - - let mut first = true; - for (name, value) in point.fields { - line.push_str(&format!( - "{}{}={}", - if first { ' ' } else { ',' }, - name, - value - )); - first = false; - } - let timestamp = point.timestamp.duration_since(UNIX_EPOCH); - let nanos = timestamp.unwrap().as_nanos(); - line.push_str(&format!(" {}\n", nanos)); - } + let line = serialize_points(&points, &host_id); let client = reqwest::blocking::Client::builder() .timeout(Duration::from_secs(5))