blob: 8052e6076f92c876801ccc42f7778272d0663a61 [file]
use std::collections::HashMap;
use super::metrics::group::{from_individual_metrics, from_producers_and_consumers_statistics};
use crate::utils::get_server_stats;
use chrono::{DateTime, Utc};
use iggy::{
models::stats::{CacheMetrics, CacheMetricsKey, Stats},
utils::timestamp::IggyTimestamp,
};
use iggy_bench_report::{
actor_kind::ActorKind,
benchmark_kind::BenchmarkKind,
hardware::BenchmarkHardware,
individual_metrics::BenchmarkIndividualMetrics,
params::BenchmarkParams,
report::BenchmarkReport,
server_stats::{BenchmarkCacheMetrics, BenchmarkCacheMetricsKey, BenchmarkServerStats},
};
pub struct BenchmarkReportBuilder;
impl BenchmarkReportBuilder {
pub async fn build(
hardware: BenchmarkHardware,
mut params: BenchmarkParams,
mut individual_metrics: Vec<BenchmarkIndividualMetrics>,
moving_average_window: u32,
) -> BenchmarkReport {
let uuid = uuid::Uuid::new_v4();
let timestamp =
DateTime::<Utc>::from_timestamp_micros(IggyTimestamp::now().as_micros() as i64)
.map(|dt| dt.to_rfc3339())
.unwrap_or_else(|| String::from("unknown"));
let transport = params.transport;
let server_addr = params.server_address.clone();
let server_stats = get_server_stats(&transport, &server_addr)
.await
.expect("Failed to get server stats");
if params.gitref.is_none() {
params.gitref = Some(server_stats.iggy_server_version.clone());
};
if params.gitref_date.is_none() {
params.gitref_date = Some(timestamp.clone());
}
let mut group_metrics = Vec::new();
// Sort metrics by actor type and ID
individual_metrics.sort_by_key(|m| (m.summary.actor_kind, m.summary.actor_id));
// Split metrics by actor type
let producer_metrics: Vec<BenchmarkIndividualMetrics> = individual_metrics
.iter()
.filter(|m| m.summary.actor_kind == ActorKind::Producer)
.cloned()
.collect();
let consumer_metrics: Vec<BenchmarkIndividualMetrics> = individual_metrics
.iter()
.filter(|m| m.summary.actor_kind == ActorKind::Consumer)
.cloned()
.collect();
let producing_consumers_metrics: Vec<BenchmarkIndividualMetrics> = individual_metrics
.iter()
.filter(|m| m.summary.actor_kind == ActorKind::ProducingConsumer)
.cloned()
.collect();
if !producer_metrics.is_empty() {
if let Some(metrics) = from_individual_metrics(&producer_metrics, moving_average_window)
{
group_metrics.push(metrics);
}
}
if !consumer_metrics.is_empty() {
if let Some(metrics) = from_individual_metrics(&consumer_metrics, moving_average_window)
{
group_metrics.push(metrics);
}
}
if !producing_consumers_metrics.is_empty() {
if let Some(metrics) =
from_individual_metrics(&producing_consumers_metrics, moving_average_window)
{
group_metrics.push(metrics);
}
}
if matches!(
params.benchmark_kind,
BenchmarkKind::PinnedProducerAndConsumer
| BenchmarkKind::BalancedProducerAndConsumerGroup
) && !producer_metrics.is_empty()
&& !consumer_metrics.is_empty()
{
if let Some(metrics) = from_producers_and_consumers_statistics(
&producer_metrics,
&consumer_metrics,
moving_average_window,
) {
group_metrics.push(metrics);
}
}
BenchmarkReport {
uuid,
server_stats: stats_to_benchmark_server_stats(server_stats),
timestamp,
hardware,
params,
group_metrics,
individual_metrics,
}
}
}
/// This function is a workaround.
/// See server_stats.rs in `iggy_bench_report` crate for more details.
fn stats_to_benchmark_server_stats(stats: Stats) -> BenchmarkServerStats {
BenchmarkServerStats {
process_id: stats.process_id,
cpu_usage: stats.cpu_usage,
total_cpu_usage: stats.total_cpu_usage,
memory_usage: stats.memory_usage.as_bytes_u64(),
total_memory: stats.total_memory.as_bytes_u64(),
available_memory: stats.available_memory.as_bytes_u64(),
run_time: stats.run_time.into(),
start_time: stats.start_time.into(),
read_bytes: stats.read_bytes.as_bytes_u64(),
written_bytes: stats.written_bytes.as_bytes_u64(),
messages_size_bytes: stats.messages_size_bytes.as_bytes_u64(),
streams_count: stats.streams_count,
topics_count: stats.topics_count,
partitions_count: stats.partitions_count,
segments_count: stats.segments_count,
messages_count: stats.messages_count,
clients_count: stats.clients_count,
consumer_groups_count: stats.consumer_groups_count,
hostname: stats.hostname,
os_name: stats.os_name,
os_version: stats.os_version,
kernel_version: stats.kernel_version,
iggy_server_version: stats.iggy_server_version,
iggy_server_semver: stats.iggy_server_semver,
cache_metrics: cache_metrics_to_benchmark_cache_metrics(stats.cache_metrics),
}
}
/// This function is a workaround.
/// See server_stats.rs in `iggy_bench_report` crate for more details.
fn cache_metrics_to_benchmark_cache_metrics(
cache_metrics: HashMap<CacheMetricsKey, CacheMetrics>,
) -> HashMap<BenchmarkCacheMetricsKey, BenchmarkCacheMetrics> {
cache_metrics
.into_iter()
.map(|(k, v)| {
(
BenchmarkCacheMetricsKey {
stream_id: k.stream_id,
topic_id: k.topic_id,
partition_id: k.partition_id,
},
BenchmarkCacheMetrics {
hits: v.hits,
misses: v.misses,
hit_ratio: v.hit_ratio,
},
)
})
.collect()
}