From 02be567b48cf39aadbdf314ba5f39ebc0deaed10 Mon Sep 17 00:00:00 2001 From: Mindaugas Vinkelis Date: Thu, 24 Oct 2024 11:40:00 +0300 Subject: [PATCH] Metrics collect stress test --- opentelemetry-sdk/benches/metric.rs | 39 +--- .../src/testing/metrics/metric_reader.rs | 35 ++++ opentelemetry-sdk/src/testing/metrics/mod.rs | 1 - stress/Cargo.toml | 40 +--- stress/src/attributes.rs | 13 ++ stress/src/{ => bin}/logs.rs | 2 +- stress/src/bin/metrics_collect.rs | 176 ++++++++++++++++++ stress/src/bin/metrics_counter.rs | 36 ++++ stress/src/bin/metrics_gauge.rs | 33 ++++ stress/src/bin/metrics_histogram.rs | 39 ++++ stress/src/bin/metrics_overflow.rs | 28 +++ stress/src/{ => bin}/random.rs | 15 +- stress/src/{ => bin}/traces.rs | 40 ++-- stress/src/globals.rs | 17 ++ stress/src/lib.rs | 3 + stress/src/metrics_counter.rs | 69 ------- stress/src/metrics_gauge.rs | 66 ------- stress/src/metrics_histogram.rs | 69 ------- stress/src/metrics_overflow.rs | 46 ----- 19 files changed, 410 insertions(+), 357 deletions(-) create mode 100644 stress/src/attributes.rs rename stress/src/{ => bin}/logs.rs (98%) create mode 100644 stress/src/bin/metrics_collect.rs create mode 100644 stress/src/bin/metrics_counter.rs create mode 100644 stress/src/bin/metrics_gauge.rs create mode 100644 stress/src/bin/metrics_histogram.rs create mode 100644 stress/src/bin/metrics_overflow.rs rename stress/src/{ => bin}/random.rs (65%) rename stress/src/{ => bin}/traces.rs (61%) create mode 100644 stress/src/globals.rs create mode 100644 stress/src/lib.rs delete mode 100644 stress/src/metrics_counter.rs delete mode 100644 stress/src/metrics_gauge.rs delete mode 100644 stress/src/metrics_histogram.rs delete mode 100644 stress/src/metrics_overflow.rs diff --git a/opentelemetry-sdk/benches/metric.rs b/opentelemetry-sdk/benches/metric.rs index aaf3e6c017..3937d70411 100644 --- a/opentelemetry-sdk/benches/metric.rs +++ b/opentelemetry-sdk/benches/metric.rs @@ -1,9 +1,8 @@ use rand::Rng; -use std::sync::{Arc, Weak}; use criterion::{criterion_group, criterion_main, Bencher, Criterion}; use opentelemetry::{ - metrics::{Counter, Histogram, MeterProvider as _, Result}, + metrics::{Counter, Histogram, MeterProvider}, Key, KeyValue, }; use opentelemetry_sdk::{ @@ -14,34 +13,10 @@ use opentelemetry_sdk::{ Aggregation, Instrument, InstrumentKind, ManualReader, Pipeline, SdkMeterProvider, Stream, View, }, + testing::metrics::metric_reader::SharedReader, Resource, }; -#[derive(Clone, Debug)] -struct SharedReader(Arc); - -impl MetricReader for SharedReader { - fn register_pipeline(&self, pipeline: Weak) { - self.0.register_pipeline(pipeline) - } - - fn collect(&self, rm: &mut ResourceMetrics) -> Result<()> { - self.0.collect(rm) - } - - fn force_flush(&self) -> Result<()> { - self.0.force_flush() - } - - fn shutdown(&self) -> Result<()> { - self.0.shutdown() - } - - fn temporality(&self, kind: InstrumentKind) -> Temporality { - self.0.temporality(kind) - } -} - // * Summary * // rustc 1.68.0 (2c8cc3432 2023-03-06) @@ -112,13 +87,13 @@ impl MetricReader for SharedReader { // time: [726.87 ns 736.52 ns 747.09 ns] fn bench_counter(view: Option>, temporality: &str) -> (SharedReader, Counter) { let rdr = if temporality == "cumulative" { - SharedReader(Arc::new(ManualReader::builder().build())) + SharedReader::new(ManualReader::builder().build()) } else { - SharedReader(Arc::new( + SharedReader::new( ManualReader::builder() .with_temporality(Temporality::Delta) .build(), - )) + ) }; let mut builder = SdkMeterProvider::builder().with_reader(rdr.clone()); if let Some(view) = view { @@ -336,7 +311,7 @@ fn bench_histogram(bound_count: usize) -> (SharedReader, Histogram) { .unwrap(), ); - let r = SharedReader(Arc::new(ManualReader::default())); + let r = SharedReader::new(ManualReader::default()); let mut builder = SdkMeterProvider::builder().with_reader(r.clone()); if let Some(view) = view { builder = builder.with_view(view); @@ -377,7 +352,7 @@ fn histograms(c: &mut Criterion) { } fn benchmark_collect_histogram(b: &mut Bencher, n: usize) { - let r = SharedReader(Arc::new(ManualReader::default())); + let r = SharedReader::new(ManualReader::default()); let mtr = SdkMeterProvider::builder() .with_reader(r.clone()) .build() diff --git a/opentelemetry-sdk/src/testing/metrics/metric_reader.rs b/opentelemetry-sdk/src/testing/metrics/metric_reader.rs index 0b67b155a3..87182c43eb 100644 --- a/opentelemetry-sdk/src/testing/metrics/metric_reader.rs +++ b/opentelemetry-sdk/src/testing/metrics/metric_reader.rs @@ -57,3 +57,38 @@ impl MetricReader for TestMetricReader { Temporality::default() } } + +/// Allow to clone [`MetricReader`], so it could be accessed in tests +#[derive(Clone, Debug)] +pub struct SharedReader(Arc); + +impl SharedReader { + pub fn new(reader: R) -> Self + where + R: MetricReader, + { + Self(Arc::new(reader)) + } +} + +impl MetricReader for SharedReader { + fn register_pipeline(&self, pipeline: Weak) { + self.0.register_pipeline(pipeline) + } + + fn collect(&self, rm: &mut ResourceMetrics) -> Result<()> { + self.0.collect(rm) + } + + fn force_flush(&self) -> Result<()> { + self.0.force_flush() + } + + fn shutdown(&self) -> Result<()> { + self.0.shutdown() + } + + fn temporality(&self, kind: InstrumentKind) -> Temporality { + self.0.temporality(kind) + } +} diff --git a/opentelemetry-sdk/src/testing/metrics/mod.rs b/opentelemetry-sdk/src/testing/metrics/mod.rs index cac9f58ce4..96d1ed8422 100644 --- a/opentelemetry-sdk/src/testing/metrics/mod.rs +++ b/opentelemetry-sdk/src/testing/metrics/mod.rs @@ -7,4 +7,3 @@ pub use in_memory_exporter::{InMemoryMetricsExporter, InMemoryMetricsExporterBui #[doc(hidden)] pub mod metric_reader; -pub use metric_reader::TestMetricReader; diff --git a/stress/Cargo.toml b/stress/Cargo.toml index 0591cde7eb..5b6790ca0a 100644 --- a/stress/Cargo.toml +++ b/stress/Cargo.toml @@ -4,53 +4,19 @@ version = "0.1.0" edition = "2021" publish = false -[[bin]] # Bin to run the metrics stress tests for Counter -name = "metrics" -path = "src/metrics_counter.rs" -doc = false - -[[bin]] # Bin to run the metrics stress tests for Gauge -name = "metrics_gauge" -path = "src/metrics_gauge.rs" -doc = false - -[[bin]] # Bin to run the metrics stress tests for Histogram -name = "metrics_histogram" -path = "src/metrics_histogram.rs" -doc = false - -[[bin]] # Bin to run the metrics overflow stress tests -name = "metrics_overflow" -path = "src/metrics_overflow.rs" -doc = false - -[[bin]] # Bin to run the logs stress tests -name = "logs" -path = "src/logs.rs" -doc = false - -[[bin]] # Bin to run the traces stress tests -name = "traces" -path = "src/traces.rs" -doc = false - -[[bin]] # Bin to run the stress tests to show the cost of random number generation -name = "random" -path = "src/random.rs" -doc = false - [dependencies] ctrlc = "3.2.5" lazy_static = "1.4.0" num_cpus = "1.15.0" opentelemetry = { path = "../opentelemetry", features = ["metrics", "logs", "trace", "logs_level_enabled"] } -opentelemetry_sdk = { path = "../opentelemetry-sdk", features = ["metrics", "logs", "trace", "logs_level_enabled"] } +opentelemetry_sdk = { path = "../opentelemetry-sdk", features = ["metrics", "logs", "trace", "logs_level_enabled", "testing"] } opentelemetry-appender-tracing = { path = "../opentelemetry-appender-tracing"} rand = { version = "0.8.4", features = ["small_rng"] } tracing = { workspace = true, features = ["std"]} tracing-subscriber = { workspace = true, features = ["registry", "std"] } num-format = "0.4.4" sysinfo = { version = "0.30.12", optional = true } +clap = { version = "4.5.20", features = ["derive"] } [features] -stats = ["sysinfo"] \ No newline at end of file +stats = ["sysinfo"] diff --git a/stress/src/attributes.rs b/stress/src/attributes.rs new file mode 100644 index 0000000000..3c855bf284 --- /dev/null +++ b/stress/src/attributes.rs @@ -0,0 +1,13 @@ +use opentelemetry::KeyValue; +use rand::{rngs::SmallRng, Rng}; + +pub fn random_attribute_set3(rng: &mut SmallRng, values: &[&'static str]) -> [KeyValue; 3] { + let len = values.len(); + unsafe { + [ + KeyValue::new("attribute1", *values.get_unchecked(rng.gen_range(0..len))), + KeyValue::new("attribute2", *values.get_unchecked(rng.gen_range(0..len))), + KeyValue::new("attribute3", *values.get_unchecked(rng.gen_range(0..len))), + ] + } +} diff --git a/stress/src/logs.rs b/stress/src/bin/logs.rs similarity index 98% rename from stress/src/logs.rs rename to stress/src/bin/logs.rs index 7744708db9..38fae42374 100644 --- a/stress/src/logs.rs +++ b/stress/src/bin/logs.rs @@ -15,7 +15,7 @@ use opentelemetry_sdk::logs::{LogProcessor, LoggerProvider}; use tracing::error; use tracing_subscriber::prelude::*; -mod throughput; +use stress::throughput; #[derive(Debug)] pub struct NoOpLogProcessor; diff --git a/stress/src/bin/metrics_collect.rs b/stress/src/bin/metrics_collect.rs new file mode 100644 index 0000000000..615a7ecc2c --- /dev/null +++ b/stress/src/bin/metrics_collect.rs @@ -0,0 +1,176 @@ +use std::{ + ops::DerefMut, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Barrier, + }, + time::{Duration, Instant}, +}; + +use opentelemetry::metrics::{Histogram, MeterProvider}; +use opentelemetry_sdk::{ + metrics::{ + data::{ResourceMetrics, Temporality}, + reader::MetricReader, + ManualReader, SdkMeterProvider, + }, + testing::metrics::metric_reader::SharedReader, + Resource, +}; + +use stress::{ + attributes::random_attribute_set3, + globals::{ATTRIBUTE_VALUES, CURRENT_RNG}, +}; + +use clap::{Parser, ValueEnum}; + +#[derive(Debug, Clone, Copy, ValueEnum)] +enum CliTemporality { + Cumulative, + Delta, +} + +/// Simple program to greet a person +#[derive(Parser, Debug)] +#[command( + version, + about = "Measure metrics performance while collecting", + long_about = "The purpose of this test is to see how collecing interferre with measurements.\n\ + Most of the test measure how fast is collecting phase, but more important is\n\ + that it doesn't \"stop-the-world\" while collection phase is running." +)] +struct Cli { + /// Select collection phase temporality + temporality: CliTemporality, +} + +fn main() { + let cli = Cli::parse(); + let temporality = match cli.temporality { + CliTemporality::Cumulative => Temporality::Cumulative, + CliTemporality::Delta => Temporality::Delta, + }; + let reader = SharedReader::new( + ManualReader::builder() + .with_temporality(temporality) + .build(), + ); + let provider = SdkMeterProvider::builder() + .with_reader(reader.clone()) + .build(); + // use histogram, as it is a bit more complicated during + let histogram = provider.meter("test").u64_histogram("hello").build(); + + calculate_measurements_during_collection(histogram, reader).print_results(); +} + +fn calculate_measurements_during_collection( + histogram: Histogram, + reader: SharedReader, +) -> MeasurementResults { + // we don't need to use every single CPU, better leave other CPU for operating system work, + // so our running threads could be much more stable in performance. + // just for the record, this is has HUGE effect on my machine (laptop intel i7-1355u) + let num_threads = num_cpus::get() / 2; + + let mut res = MeasurementResults { + total_measurements_count: 0, + total_time_collecting: 0, + num_iterations: 0, + }; + let start = Instant::now(); + while start.elapsed() < Duration::from_secs(3) { + res.num_iterations += 1; + let is_collecting = AtomicBool::new(false); + let measurements_while_collecting = AtomicUsize::new(0); + let time_while_collecting = AtomicUsize::new(0); + let barrier = Barrier::new(num_threads + 1); + std::thread::scope(|s| { + // first create bunch of measurements, + // so that collection phase wouldn't be "empty" + let mut handles = Vec::new(); + for _t in 0..num_threads { + handles.push(s.spawn(|| { + for _i in 0..1000 { + CURRENT_RNG.with(|rng| { + histogram.record( + 1, + &random_attribute_set3( + rng.borrow_mut().deref_mut(), + ATTRIBUTE_VALUES.as_ref(), + ), + ); + }); + } + })); + } + for handle in handles { + handle.join().unwrap(); + } + + // simultaneously start collecting and creating more measurements + for _ in 0..num_threads - 1 { + s.spawn(|| { + barrier.wait(); + let now = Instant::now(); + let mut count = 0; + while is_collecting.load(Ordering::Acquire) { + CURRENT_RNG.with(|rng| { + histogram.record( + 1, + &random_attribute_set3( + rng.borrow_mut().deref_mut(), + ATTRIBUTE_VALUES.as_ref(), + ), + ); + }); + count += 1; + } + measurements_while_collecting.fetch_add(count, Ordering::AcqRel); + time_while_collecting + .fetch_add(now.elapsed().as_micros() as usize, Ordering::AcqRel); + }); + } + + let collect_handle = s.spawn(|| { + let mut rm = ResourceMetrics { + resource: Resource::empty(), + scope_metrics: Vec::new(), + }; + is_collecting.store(true, Ordering::Release); + barrier.wait(); + reader.collect(&mut rm).unwrap(); + is_collecting.store(false, Ordering::Release); + }); + barrier.wait(); + collect_handle.join().unwrap(); + }); + res.total_measurements_count += measurements_while_collecting.load(Ordering::Acquire); + res.total_time_collecting += time_while_collecting.load(Ordering::Acquire); + } + res +} + +struct MeasurementResults { + total_measurements_count: usize, + total_time_collecting: usize, + num_iterations: usize, +} + +impl MeasurementResults { + fn print_results(&self) { + println!( + "{:>10.2} measurements/ms", + self.total_measurements_count as f32 / (self.total_time_collecting as f32 / 1000.0f32) + ); + println!( + "{:>10.2} measurements/it", + self.total_measurements_count as f32 / self.num_iterations as f32, + ); + println!( + "{:>10.2} μs/it", + self.total_time_collecting as f32 / self.num_iterations as f32, + ); + } +} diff --git a/stress/src/bin/metrics_counter.rs b/stress/src/bin/metrics_counter.rs new file mode 100644 index 0000000000..0b53565beb --- /dev/null +++ b/stress/src/bin/metrics_counter.rs @@ -0,0 +1,36 @@ +/* + Stress test results: + OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) + Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, + RAM: 64.0 GB + ~9.5 M /sec + + Hardware: AMD EPYC 7763 64-Core Processor - 2.44 GHz, 16vCPUs, + ~20 M /sec +*/ + +use std::ops::DerefMut; + +use opentelemetry::metrics::MeterProvider; +use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; + +use stress::{ + attributes::random_attribute_set3, + globals::{ATTRIBUTE_VALUES, CURRENT_RNG}, + throughput, +}; + +fn main() { + let provider = SdkMeterProvider::builder() + .with_reader(ManualReader::builder().build()) + .build(); + let counter = provider.meter("test").u64_counter("hello").build(); + throughput::test_throughput(move || { + CURRENT_RNG.with(|rng| { + counter.add( + 1, + &random_attribute_set3(rng.borrow_mut().deref_mut(), ATTRIBUTE_VALUES.as_ref()), + ); + }); + }); +} diff --git a/stress/src/bin/metrics_gauge.rs b/stress/src/bin/metrics_gauge.rs new file mode 100644 index 0000000000..5b8fbb0326 --- /dev/null +++ b/stress/src/bin/metrics_gauge.rs @@ -0,0 +1,33 @@ +/* + Stress test results: + OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) + Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, + RAM: 64.0 GB + ~11.5 M/sec +*/ + +use std::ops::DerefMut; + +use opentelemetry::metrics::MeterProvider; +use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; + +use stress::{ + attributes::random_attribute_set3, + globals::{ATTRIBUTE_VALUES, CURRENT_RNG}, + throughput, +}; + +fn main() { + let provider = SdkMeterProvider::builder() + .with_reader(ManualReader::builder().build()) + .build(); + let gauge = provider.meter("test").u64_gauge("test_gauge").build(); + throughput::test_throughput(move || { + CURRENT_RNG.with(|rng| { + gauge.record( + 1, + &random_attribute_set3(rng.borrow_mut().deref_mut(), ATTRIBUTE_VALUES.as_ref()), + ); + }); + }); +} diff --git a/stress/src/bin/metrics_histogram.rs b/stress/src/bin/metrics_histogram.rs new file mode 100644 index 0000000000..a04809dba7 --- /dev/null +++ b/stress/src/bin/metrics_histogram.rs @@ -0,0 +1,39 @@ +/* + Stress test results: + OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) + Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, + RAM: 64.0 GB + ~9.0 M/sec + + Hardware: AMD EPYC 7763 64-Core Processor - 2.44 GHz, 16vCPUs, + ~12.0 M /sec +*/ + +use std::ops::DerefMut; + +use opentelemetry::metrics::MeterProvider; +use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; + +use stress::{ + attributes::random_attribute_set3, + globals::{ATTRIBUTE_VALUES, CURRENT_RNG}, + throughput, +}; + +fn main() { + let provider = SdkMeterProvider::builder() + .with_reader(ManualReader::builder().build()) + .build(); + let histogram = provider + .meter("test") + .u64_histogram("test_histogram") + .build(); + throughput::test_throughput(move || { + CURRENT_RNG.with(|rng| { + histogram.record( + 1, + &random_attribute_set3(rng.borrow_mut().deref_mut(), ATTRIBUTE_VALUES.as_ref()), + ); + }); + }); +} diff --git a/stress/src/bin/metrics_overflow.rs b/stress/src/bin/metrics_overflow.rs new file mode 100644 index 0000000000..aa8c7fa894 --- /dev/null +++ b/stress/src/bin/metrics_overflow.rs @@ -0,0 +1,28 @@ +/* + Stress test results: + OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) + Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, + RAM: 64.0 GB + ~1.9 M/sec +*/ + +use opentelemetry::{metrics::MeterProvider, KeyValue}; +use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; + +use rand::Rng; +use stress::{globals::CURRENT_RNG, throughput}; + +fn main() { + // The main goal of this test is to ensure that OTel SDK is not growing its + // memory usage indefinitely even when user code misbehaves by producing + // unbounded metric points (unique time series). + // It also checks that SDK's internal logging is also done in a bounded way. + let provider = SdkMeterProvider::builder() + .with_reader(ManualReader::builder().build()) + .build(); + let counter = provider.meter("test").u64_counter("hello").build(); + throughput::test_throughput(move || { + let rand = CURRENT_RNG.with(|rng| rng.borrow_mut().gen_range(0..100000000)); + counter.add(1, &[KeyValue::new("A", rand)]); + }); +} diff --git a/stress/src/random.rs b/stress/src/bin/random.rs similarity index 65% rename from stress/src/random.rs rename to stress/src/bin/random.rs index 9d4b7f997e..b6b8a592d8 100644 --- a/stress/src/random.rs +++ b/stress/src/bin/random.rs @@ -6,19 +6,8 @@ ~540 M/sec */ -use rand::{ - rngs::{self}, - Rng, SeedableRng, -}; - -mod throughput; - -use std::cell::RefCell; - -thread_local! { - /// Store random number generator for each thread - static CURRENT_RNG: RefCell = RefCell::new(rngs::SmallRng::from_entropy()); -} +use rand::Rng; +use stress::{globals::CURRENT_RNG, throughput}; fn main() { throughput::test_throughput(test_random_generation); diff --git a/stress/src/traces.rs b/stress/src/bin/traces.rs similarity index 61% rename from stress/src/traces.rs rename to stress/src/bin/traces.rs index 62598b10ad..30a7fba6ce 100644 --- a/stress/src/traces.rs +++ b/stress/src/bin/traces.rs @@ -9,7 +9,6 @@ ~10.6 M /sec */ -use lazy_static::lazy_static; use opentelemetry::{ trace::{Span, SpanBuilder, TraceResult, Tracer, TracerProvider as _}, Context, KeyValue, @@ -19,15 +18,7 @@ use opentelemetry_sdk::{ trace::{self as sdktrace, SpanProcessor}, }; -mod throughput; - -lazy_static! { - static ref PROVIDER: sdktrace::TracerProvider = sdktrace::TracerProvider::builder() - .with_config(sdktrace::Config::default().with_sampler(sdktrace::Sampler::AlwaysOn)) - .with_span_processor(NoOpSpanProcessor {}) - .build(); - static ref TRACER: sdktrace::Tracer = PROVIDER.tracer("stress"); -} +use stress::throughput; #[derive(Debug)] pub struct NoOpSpanProcessor; @@ -51,17 +42,20 @@ impl SpanProcessor for NoOpSpanProcessor { } fn main() { - throughput::test_throughput(test_span); -} - -fn test_span() { - let span_builder = SpanBuilder::from_name("test_span").with_attributes(vec![ - KeyValue::new("attribute_at_span_start1", "value1"), - KeyValue::new("attribute_at_span_start2", "value2"), - ]); - - let mut span = TRACER.build(span_builder); - span.set_attribute(KeyValue::new("key3", "value3")); - span.set_attribute(KeyValue::new("key4", "value4")); - span.end(); + let provider = sdktrace::TracerProvider::builder() + .with_config(sdktrace::Config::default().with_sampler(sdktrace::Sampler::AlwaysOn)) + .with_span_processor(NoOpSpanProcessor {}) + .build(); + let tracer = provider.tracer("stress"); + throughput::test_throughput(move || { + let span_builder = SpanBuilder::from_name("test_span").with_attributes(vec![ + KeyValue::new("attribute_at_span_start1", "value1"), + KeyValue::new("attribute_at_span_start2", "value2"), + ]); + + let mut span = tracer.build(span_builder); + span.set_attribute(KeyValue::new("key3", "value3")); + span.set_attribute(KeyValue::new("key4", "value4")); + span.end(); + }); } diff --git a/stress/src/globals.rs b/stress/src/globals.rs new file mode 100644 index 0000000000..fefead86a0 --- /dev/null +++ b/stress/src/globals.rs @@ -0,0 +1,17 @@ +use std::cell::RefCell; + +use lazy_static::lazy_static; +use rand::{rngs, SeedableRng}; + +lazy_static! { + pub static ref ATTRIBUTE_VALUES: [&'static str; 10] = [ + "value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8", "value9", + "value10" + ]; +} + +thread_local! { + + /// Store random number generator for each thread + pub static CURRENT_RNG: RefCell = RefCell::new(rngs::SmallRng::from_entropy()); +} diff --git a/stress/src/lib.rs b/stress/src/lib.rs new file mode 100644 index 0000000000..8ea89201ce --- /dev/null +++ b/stress/src/lib.rs @@ -0,0 +1,3 @@ +pub mod attributes; +pub mod globals; +pub mod throughput; diff --git a/stress/src/metrics_counter.rs b/stress/src/metrics_counter.rs deleted file mode 100644 index d64f2d11f8..0000000000 --- a/stress/src/metrics_counter.rs +++ /dev/null @@ -1,69 +0,0 @@ -/* - Stress test results: - OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) - Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, - RAM: 64.0 GB - ~9.5 M /sec - - Hardware: AMD EPYC 7763 64-Core Processor - 2.44 GHz, 16vCPUs, - ~20 M /sec -*/ - -use lazy_static::lazy_static; -use opentelemetry::{ - metrics::{Counter, MeterProvider as _}, - KeyValue, -}; -use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; -use rand::{ - rngs::{self}, - Rng, SeedableRng, -}; -use std::cell::RefCell; - -mod throughput; - -lazy_static! { - static ref PROVIDER: SdkMeterProvider = SdkMeterProvider::builder() - .with_reader(ManualReader::builder().build()) - .build(); - static ref ATTRIBUTE_VALUES: [&'static str; 10] = [ - "value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8", "value9", - "value10" - ]; - static ref COUNTER: Counter = PROVIDER.meter("test").u64_counter("hello").build(); -} - -thread_local! { - /// Store random number generator for each thread - static CURRENT_RNG: RefCell = RefCell::new(rngs::SmallRng::from_entropy()); -} - -fn main() { - throughput::test_throughput(test_counter); -} - -fn test_counter() { - let len = ATTRIBUTE_VALUES.len(); - let rands = CURRENT_RNG.with(|rng| { - let mut rng = rng.borrow_mut(); - [ - rng.gen_range(0..len), - rng.gen_range(0..len), - rng.gen_range(0..len), - ] - }); - let index_first_attribute = rands[0]; - let index_second_attribute = rands[1]; - let index_third_attribute = rands[2]; - - // each attribute has 10 possible values, so there are 1000 possible combinations (time-series) - COUNTER.add( - 1, - &[ - KeyValue::new("attribute1", ATTRIBUTE_VALUES[index_first_attribute]), - KeyValue::new("attribute2", ATTRIBUTE_VALUES[index_second_attribute]), - KeyValue::new("attribute3", ATTRIBUTE_VALUES[index_third_attribute]), - ], - ); -} diff --git a/stress/src/metrics_gauge.rs b/stress/src/metrics_gauge.rs deleted file mode 100644 index d69efb3c4f..0000000000 --- a/stress/src/metrics_gauge.rs +++ /dev/null @@ -1,66 +0,0 @@ -/* - Stress test results: - OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) - Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, - RAM: 64.0 GB - ~11.5 M/sec -*/ - -use lazy_static::lazy_static; -use opentelemetry::{ - metrics::{Gauge, MeterProvider as _}, - KeyValue, -}; -use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; -use rand::{ - rngs::{self}, - Rng, SeedableRng, -}; -use std::cell::RefCell; - -mod throughput; - -lazy_static! { - static ref PROVIDER: SdkMeterProvider = SdkMeterProvider::builder() - .with_reader(ManualReader::builder().build()) - .build(); - static ref ATTRIBUTE_VALUES: [&'static str; 10] = [ - "value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8", "value9", - "value10" - ]; - static ref GAUGE: Gauge = PROVIDER.meter("test").u64_gauge("test_gauge").build(); -} - -thread_local! { - /// Store random number generator for each thread - static CURRENT_RNG: RefCell = RefCell::new(rngs::SmallRng::from_entropy()); -} - -fn main() { - throughput::test_throughput(test_gauge); -} - -fn test_gauge() { - let len = ATTRIBUTE_VALUES.len(); - let rands = CURRENT_RNG.with(|rng| { - let mut rng = rng.borrow_mut(); - [ - rng.gen_range(0..len), - rng.gen_range(0..len), - rng.gen_range(0..len), - ] - }); - let index_first_attribute = rands[0]; - let index_second_attribute = rands[1]; - let index_third_attribute = rands[2]; - - // each attribute has 10 possible values, so there are 1000 possible combinations (time-series) - GAUGE.record( - 1, - &[ - KeyValue::new("attribute1", ATTRIBUTE_VALUES[index_first_attribute]), - KeyValue::new("attribute2", ATTRIBUTE_VALUES[index_second_attribute]), - KeyValue::new("attribute3", ATTRIBUTE_VALUES[index_third_attribute]), - ], - ); -} diff --git a/stress/src/metrics_histogram.rs b/stress/src/metrics_histogram.rs deleted file mode 100644 index 860d2bdd20..0000000000 --- a/stress/src/metrics_histogram.rs +++ /dev/null @@ -1,69 +0,0 @@ -/* - Stress test results: - OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) - Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, - RAM: 64.0 GB - ~9.0 M/sec - - Hardware: AMD EPYC 7763 64-Core Processor - 2.44 GHz, 16vCPUs, - ~12.0 M /sec -*/ - -use lazy_static::lazy_static; -use opentelemetry::{ - metrics::{Histogram, MeterProvider as _}, - KeyValue, -}; -use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; -use rand::{ - rngs::{self}, - Rng, SeedableRng, -}; -use std::cell::RefCell; - -mod throughput; - -lazy_static! { - static ref PROVIDER: SdkMeterProvider = SdkMeterProvider::builder() - .with_reader(ManualReader::builder().build()) - .build(); - static ref ATTRIBUTE_VALUES: [&'static str; 10] = [ - "value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8", "value9", - "value10" - ]; - static ref HISTOGRAM: Histogram = PROVIDER.meter("test").u64_histogram("hello").build(); -} - -thread_local! { - /// Store random number generator for each thread - static CURRENT_RNG: RefCell = RefCell::new(rngs::SmallRng::from_entropy()); -} - -fn main() { - throughput::test_throughput(test_histogram); -} - -fn test_histogram() { - let len = ATTRIBUTE_VALUES.len(); - let rands = CURRENT_RNG.with(|rng| { - let mut rng = rng.borrow_mut(); - [ - rng.gen_range(0..len), - rng.gen_range(0..len), - rng.gen_range(0..len), - ] - }); - let index_first_attribute = rands[0]; - let index_second_attribute = rands[1]; - let index_third_attribute = rands[2]; - - // each attribute has 10 possible values, so there are 1000 possible combinations (time-series) - HISTOGRAM.record( - 1, - &[ - KeyValue::new("attribute1", ATTRIBUTE_VALUES[index_first_attribute]), - KeyValue::new("attribute2", ATTRIBUTE_VALUES[index_second_attribute]), - KeyValue::new("attribute3", ATTRIBUTE_VALUES[index_third_attribute]), - ], - ); -} diff --git a/stress/src/metrics_overflow.rs b/stress/src/metrics_overflow.rs deleted file mode 100644 index bbd79db780..0000000000 --- a/stress/src/metrics_overflow.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* - Stress test results: - OS: Ubuntu 22.04.4 LTS (5.15.153.1-microsoft-standard-WSL2) - Hardware: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz, 16vCPUs, - RAM: 64.0 GB - ~1.9 M/sec -*/ - -use lazy_static::lazy_static; -use opentelemetry::{ - metrics::{Counter, MeterProvider as _}, - KeyValue, -}; -use opentelemetry_sdk::metrics::{ManualReader, SdkMeterProvider}; -use rand::{ - rngs::{self}, - Rng, SeedableRng, -}; -use std::cell::RefCell; - -mod throughput; - -lazy_static! { - static ref PROVIDER: SdkMeterProvider = SdkMeterProvider::builder() - .with_reader(ManualReader::builder().build()) - .build(); - static ref COUNTER: Counter = PROVIDER.meter("test").u64_counter("hello").build(); -} - -thread_local! { - /// Store random number generator for each thread - static CURRENT_RNG: RefCell = RefCell::new(rngs::SmallRng::from_entropy()); -} - -fn main() { - throughput::test_throughput(test_counter); -} - -fn test_counter() { - // The main goal of this test is to ensure that OTel SDK is not growing its - // memory usage indefinitely even when user code misbehaves by producing - // unbounded metric points (unique time series). - // It also checks that SDK's internal logging is also done in a bounded way. - let rand = CURRENT_RNG.with(|rng| rng.borrow_mut().gen_range(0..100000000)); - COUNTER.add(1, &[KeyValue::new("A", rand)]); -}