Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/analytics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn get_base_run_name() -> String {

pub struct AnalyticalEngine<'a> {
// Map from a data name to its processed data across all runs
all_processed_data: HashMap<String, &'a ProcessedData>,
all_processed_data: HashMap<String, &'a mut ProcessedData>,
// Map from a data name to its defined rules
per_data_rules: HashMap<String, Vec<AnalyticalRule>>,
// All rules that require multiple data types
Expand All @@ -57,7 +57,7 @@ impl Default for AnalyticalEngine<'_> {
}

impl<'a> AnalyticalEngine<'a> {
pub fn add_processed_data(&mut self, data_name: String, processed_data: &'a ProcessedData) {
pub fn add_processed_data(&mut self, data_name: String, processed_data: &'a mut ProcessedData) {
self.all_processed_data.insert(data_name, processed_data);
}

Expand All @@ -67,7 +67,7 @@ impl<'a> AnalyticalEngine<'a> {

pub fn run(&mut self, processed_data_accessor: &mut ProcessedDataAccessor) {
for (data_name, data_rules) in &self.per_data_rules {
if let Some(&processed_data) = self.all_processed_data.get(data_name) {
if let Some(processed_data) = self.all_processed_data.get_mut(data_name) {
let data_findings = self
.findings
.entry(data_name.clone())
Expand Down Expand Up @@ -194,7 +194,7 @@ pub trait Analyze {
fn analyze(
&self,
data_findings: &mut DataFindings,
processed_data: &ProcessedData,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
);
}
Expand All @@ -206,7 +206,7 @@ pub trait MultiDataAnalyze {
fn analyze(
&self,
findings: &HashMap<String, DataFindings>,
all_processed_data: &HashMap<String, &ProcessedData>,
all_processed_data: &HashMap<String, &mut ProcessedData>,
processed_data_accessor: &mut ProcessedDataAccessor,
);
}
Expand All @@ -220,7 +220,7 @@ macro_rules! analytical_rules {
}

impl AnalyticalRule {
pub fn analyze(&self, data_findings: &mut DataFindings, processed_data: &ProcessedData, processed_data_accessor: &mut ProcessedDataAccessor) {
pub fn analyze(&self, data_findings: &mut DataFindings, processed_data: &mut ProcessedData, processed_data_accessor: &mut ProcessedDataAccessor) {
match self {
$(
AnalyticalRule::$analytical_rule(ref analytical_rule) => analytical_rule.analyze(data_findings, processed_data, processed_data_accessor),
Expand Down Expand Up @@ -253,7 +253,7 @@ macro_rules! multi_data_analytical_rules {
}

impl MultiDataAnalyticalRule {
pub fn analyze(&self, _findings: &mut HashMap<String, DataFindings>, _all_processed_data: &HashMap<String, &ProcessedData>, _processed_data_accessor: &mut ProcessedDataAccessor) {
pub fn analyze(&self, _findings: &mut HashMap<String, DataFindings>, _all_processed_data: &HashMap<String, &mut ProcessedData>, _processed_data_accessor: &mut ProcessedDataAccessor) {
match self {
$(
MultiDataAnalyticalRule::$multi_data_analytical_rule(ref multi_data_analytical_rule) => multi_data_analytical_rule.analyze(findings, all_processed_data, processed_data_accessor),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl Analyze for KeyValueKeyExpectedRule {
fn analyze(
&self,
report_findings: &mut DataFindings,
processed_data: &ProcessedData,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
for run_name in processed_data.runs.keys() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl Analyze for KeyValueKeyRunComparisonRule {
fn analyze(
&self,
report_findings: &mut DataFindings,
processed_data: &ProcessedData,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
let base_run_name = analytics::get_base_run_name();
Expand Down
84 changes: 36 additions & 48 deletions src/analytics/rule_templates/profile_metadata_comparison_rule.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::analytics;
use crate::analytics::{AnalyticalFinding, Analyze, DataFindings};
use crate::data::common::data_formats::{AperfData, ProcessedData};
use crate::data::common::data_formats::ProcessedData;
use crate::data::common::processed_data_accessor::ProcessedDataAccessor;
use log::debug;
use std::collections::HashMap;
Expand Down Expand Up @@ -56,39 +56,38 @@ impl Analyze for ProfileMetadataComparisonRule {
fn analyze(
&self,
report_findings: &mut DataFindings,
processed_data: &ProcessedData,
_processed_data_accessor: &mut ProcessedDataAccessor,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
let base_run_name = analytics::get_base_run_name();

let base_run_data = match processed_data.runs.get(&base_run_name) {
Some(data) => data,
None => {
if processed_data.runs.keys().len() > 0 {
debug!("{self} failed to analyze: base run does not exist");
}
return;
if !processed_data.runs.contains_key(&base_run_name) {
if !processed_data.runs.is_empty() {
debug!("{self} failed to analyze: base run does not exist");
}
return;
}

// Collect metadata values for a run: profiler_key -> value
let collect_values = |processed_data: &mut ProcessedData,
accessor: &mut ProcessedDataAccessor,
run_name: &str|
-> HashMap<String, String> {
let keys = accessor.profiler_keys(processed_data, run_name);
keys.into_iter()
.filter_map(|profiler_key| {
let value = accessor.profiler_value_by_key(
processed_data,
run_name,
&profiler_key,
self.key,
)?;
Some((profiler_key, value))
})
.collect()
};

// Map base values from all profiles in the first record
let base_values: HashMap<String, String> =
if let AperfData::Profile(profiling_data) = base_run_data {
profiling_data
.profilers
.iter()
.filter_map(|(key, profiler)| {
profiler
.metadata
.key_value_groups
.get(self.group)
.and_then(|group| group.key_values.get(self.key))
.map(|value| (key.clone(), value.clone()))
})
.collect()
} else {
HashMap::new()
};
let base_values = collect_values(processed_data, processed_data_accessor, &base_run_name);

if base_values.is_empty() {
if self.should_exist {
Expand All @@ -109,27 +108,16 @@ impl Analyze for ProfileMetadataComparisonRule {
return;
}

for (run_name, run_data) in &processed_data.runs {
if *run_name == base_run_name {
continue;
}
let run_names: Vec<String> = processed_data
.runs
.keys()
.filter(|r| **r != base_run_name)
.cloned()
.collect();

let AperfData::Profile(profiling_data) = run_data else {
continue;
};

let comparison_values: HashMap<String, String> = profiling_data
.profilers
.iter()
.filter_map(|(key, profiler)| {
profiler
.metadata
.key_value_groups
.get(self.group)
.and_then(|group| group.key_values.get(self.key))
.map(|value| (key.clone(), value.clone()))
})
.collect();
for run_name in &run_names {
let comparison_values =
collect_values(processed_data, processed_data_accessor, run_name);

// If both runs have exactly one key-value pair, compare values regardless of key match
if base_values.len() == 1 && comparison_values.len() == 1 {
Expand Down
27 changes: 13 additions & 14 deletions src/analytics/rule_templates/profile_metadata_expected_rule.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::analytics::{AnalyticalFinding, Analyze, DataFindings};
use crate::data::common::data_formats::{AperfData, ProcessedData};
use crate::data::common::data_formats::ProcessedData;
use crate::data::common::processed_data_accessor::ProcessedDataAccessor;
use log::debug;
use regex::Regex;
Expand Down Expand Up @@ -54,8 +54,8 @@ impl Analyze for ProfileMetadataExpectedRule {
fn analyze(
&self,
report_findings: &mut DataFindings,
processed_data: &ProcessedData,
_processed_data_accessor: &mut ProcessedDataAccessor,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
let regex = match Regex::new(self.expected_value) {
Ok(re) => Some(re),
Expand All @@ -68,17 +68,16 @@ impl Analyze for ProfileMetadataExpectedRule {
}
};

for (run_name, run_data) in &processed_data.runs {
let AperfData::Profile(profiling_data) = run_data else {
continue;
};
for (key, profiler) in &profiling_data.profilers {
let metadata_value = profiler
.metadata
.key_value_groups
.get(self.group)
.and_then(|group| group.key_values.get(self.key))
.cloned();
let run_names: Vec<String> = processed_data.runs.keys().cloned().collect();
for run_name in &run_names {
let profiler_keys = processed_data_accessor.profiler_keys(processed_data, run_name);
for key in &profiler_keys {
let metadata_value = processed_data_accessor.profiler_value_by_key(
processed_data,
run_name,
key,
self.key,
);

let field_exists = metadata_value.is_some();
let value_matches = matches!((&metadata_value, &regex), (Some(value), Some(re)) if re.is_match(value));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::analytics::{AnalyticalFinding, Analyze, DataFindings};
use crate::data::common::data_formats::{AperfData, ProcessedData};
use crate::data::common::data_formats::ProcessedData;
use crate::data::common::processed_data_accessor::ProcessedDataAccessor;
use crate::profiling::{FrameType, ThreadState};
use std::fmt;
Expand Down Expand Up @@ -66,26 +66,29 @@ impl Analyze for ProfileStackFrameThresholdRule {
fn analyze(
&self,
report_findings: &mut DataFindings,
processed_data: &ProcessedData,
_processed_data_accessor: &mut ProcessedDataAccessor,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
for (run_name, run_data) in &processed_data.runs {
let AperfData::Profile(profiling_data) = run_data else {
continue;
};

for (key, profiler) in &profiling_data.profilers {
if !profiler.profiles.contains_key(self.profile_type) {
continue;
}
let total_samples =
profiler.get_total_samples(self.profile_type, self.thread_states);
let run_names: Vec<String> = processed_data.runs.keys().cloned().collect();
for run_name in &run_names {
let profiler_keys = processed_data_accessor.profiler_keys(processed_data, run_name);
for key in &profiler_keys {
let total_samples = processed_data_accessor.profiler_total_samples(
processed_data,
run_name,
key,
self.profile_type,
self.thread_states,
);

let (sample_count, matched_pattern) =
self.stack_frame
.iter()
.fold((0u64, None), |(acc, acc_pat), pattern| {
let count = profiler.get_samples(
let count = processed_data_accessor.profiler_samples(
processed_data,
run_name,
key,
self.profile_type,
pattern,
self.frame_type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl Analyze for TimeSeriesDataPointThresholdRule {
fn analyze(
&self,
data_findings: &mut DataFindings,
processed_data: &ProcessedData,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
for run_name in processed_data.runs.keys() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl Analyze for TimeSeriesStatIntraRunComparisonRule {
fn analyze(
&self,
data_findings: &mut DataFindings,
processed_data: &ProcessedData,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
for run_name in processed_data.runs.keys() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl Analyze for TimeSeriesStatRunComparisonRule {
fn analyze(
&self,
data_findings: &mut DataFindings,
processed_data: &ProcessedData,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
let base_run_name = &get_base_run_name();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl Analyze for TimeSeriesStatThresholdRule {
fn analyze(
&self,
data_findings: &mut DataFindings,
processed_data: &ProcessedData,
processed_data: &mut ProcessedData,
processed_data_accessor: &mut ProcessedDataAccessor,
) {
for run_name in processed_data.runs.keys() {
Expand Down
9 changes: 3 additions & 6 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,7 @@ impl DataType {
}

pub fn init_data_type(&mut self, param: &InitParams) -> Result<()> {
let name = format!(
"{}_{}.{}",
self.file_name, param.time_str, APERF_FILE_FORMAT
);
let name = format!("{}.{}", self.file_name, APERF_FILE_FORMAT);

self.file_name = name.clone();
self.full_path = format!("{}/{}", param.dir_name, name);
Expand Down Expand Up @@ -530,7 +527,7 @@ mod tests {
collector_params: CollectorParams::new(),
};

param.dir_name = format!("./performance_data_init_test_{}", param.time_str);
param.dir_name = format!("./performance_data_init_test");
fs::DirBuilder::new()
.recursive(true)
.create(param.dir_name.clone())
Expand Down Expand Up @@ -559,7 +556,7 @@ mod tests {
collector_params: CollectorParams::new(),
};

param.dir_name = format!("./performance_data_print_test_{}", param.time_str);
param.dir_name = format!("./performance_data_print_test");
fs::DirBuilder::new()
.recursive(true)
.create(param.dir_name.clone())
Expand Down
3 changes: 2 additions & 1 deletion src/data/aperf_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ impl ProcessData for AperfStat {
params: ReportParams,
_raw_data: Vec<Data>,
) -> Result<AperfData> {
let mut time_series_data_processor = time_series_data_processor_with_sum_aggregate!();
let mut time_series_data_processor =
time_series_data_processor_with_sum_aggregate!(params.collection_start);
time_series_data_processor.set_aggregate_series_name("total");

let mut values = Vec::new();
Expand Down
15 changes: 13 additions & 2 deletions src/data/common/data_formats.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::computations::{serialize_f64_vec_fixed2, Statistics};
use crate::profiling::Profile;
use crate::profiling::{Profile, BUCKET_WIDTH_MS};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use strum_macros::Display;
Expand Down Expand Up @@ -177,7 +177,7 @@ pub struct ProfilingData {
pub profilers: HashMap<String, Profiler>,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Profiler {
/// Start time of the profile in milliseconds since epoch
pub start_time_ms: i64,
Expand All @@ -189,6 +189,17 @@ pub struct Profiler {
pub profiles: HashMap<String, Profile>,
}

impl Default for Profiler {
fn default() -> Self {
Profiler {
start_time_ms: 0,
block_width_ms: BUCKET_WIDTH_MS,
metadata: KeyValueData::default(),
profiles: HashMap::new(),
}
}
}

impl Profiler {
pub fn new(start_time_ms: i64, block_width_ms: u64) -> Self {
Profiler {
Expand Down
Loading
Loading