From 4da8e373d91650d5111e72fd4c91af3006d1b741 Mon Sep 17 00:00:00 2001 From: Zoltan Farkas Date: Thu, 9 Jan 2025 12:44:58 -0800 Subject: [PATCH] Optimization: remove unnecessary string concatenation in ODS dynamic stats. Summary: Current macro does an extra join operation when prefix is available(most common case), this diff eliminates this operation to construct the key string in one shot eliminating a extra temp string allocation+free and the resulting fragmentation. this operation is about 30% of the key generation (join + free): https://fburl.com/strobelight/nr0vzg42 {F1974221233} Motivated by the inefficiency from D67604234 in Re, but the app that will be benefit the most will be fb_monitord (a wdb) this optimization should account for ~0.23% CPU util improvement for fb_monitord. (the eliminated operation takes about 0.23% of the strobe-light samples) __key_generator cost is currently around [40k $CPU-T1-equiv/year Q4 2024](https://fburl.com/strobelight/nk9vzdjd) so this is a 10k$/year optimization if I understand [the doc](https://www.internalfb.com/wiki/Capacity_Management_Internal/Capacity_Efficiency_pillar/Efficiency_Management_Framework/Measuring_Horizontal_CPU_Wins/) correctly. Reviewed By: edward-shen Differential Revision: D67913458 fbshipit-source-id: 08ddaa4de59f43744d202f4c71339580431290b6 --- shed/stats/src/macros.rs | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/shed/stats/src/macros.rs b/shed/stats/src/macros.rs index 4caf902c..69f42f1d 100644 --- a/shed/stats/src/macros.rs +++ b/shed/stats/src/macros.rs @@ -218,16 +218,62 @@ macro_rules! define_stats { #[doc(hidden)] #[macro_export] macro_rules! __define_key_generator { + ($name:ident($prefix:literal, $key:expr; $( $placeholder:ident: $type:ty ),+)) => ( + fn $name(&($( ref $placeholder, )+): &($( $type, )+)) -> String { + if $prefix.is_empty() { + format!($key, $( $placeholder ),+) + } else { + format!(concat!($prefix, ".", $key), $( $placeholder ),+) + } + } + ); + ($name:ident($prefix:expr, $key:expr)) => ( + fn $name() -> String { + if $prefix.is_empty() { + $key + } else { + format!("{0}.{1}", $prefix, $key) + } + } + ); + ($name:ident($prefix:expr, $key:expr; $placeholder:ident: $type:ty )) => ( + fn $name(&( ref $placeholder, ): &( $type, )) -> String { + if $prefix.is_empty() { + format!($key, $placeholder) + } else { + format!(concat!("{1}.", $key), $placeholder, $prefix ) + } + } + ); + ($name:ident($prefix:expr, $key:expr; $placeholder1:ident: $type1:ty, $placeholder2:ident: $type2:ty )) => ( + fn $name(&( ref $placeholder1, ref $placeholder2, ): &( $type1, $type2, )) -> String { + if $prefix.is_empty() { + format!($key, $placeholder1, $placeholder2) + } else { + format!(concat!("{2}.", $key), $placeholder1, $placeholder2, $prefix ) + } + } + ); + ($name:ident($prefix:expr, $key:expr; $placeholder1:ident: $type1:ty, $placeholder2:ident: $type2:ty, $placeholder3:ident: $type3:ty )) => ( + fn $name(&( ref $placeholder1, ref $placeholder2, ref $placeholder3,): &( $type1, $type2, $type3,)) -> String { + if $prefix.is_empty() { + format!($key, $placeholder1, $placeholder2, $placeholder3) + } else { + format!(concat!("{3}.", $key), $placeholder1, $placeholder2, $placeholder3, $prefix ) + } + } + ); ($name:ident($prefix:expr, $key:expr; $( $placeholder:ident: $type:ty ),+)) => ( fn $name(&($( ref $placeholder, )+): &($( $type, )+)) -> String { let key = format!($key, $( $placeholder ),+); if $prefix.is_empty() { key } else { - [$prefix, &key].join(".") + format!("{0}.{1}", $prefix, key) } } ); + } #[doc(hidden)]