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
71 changes: 0 additions & 71 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,79 +379,8 @@ pub trait AnalyzeData {

#[cfg(test)]
mod tests {
#[cfg(target_os = "linux")]
use crate::data_collection::DataCollector;

use super::TimeEnum;
use chrono::prelude::*;
#[cfg(target_os = "linux")]
use {
super::cpu_utilization::CpuUtilizationRaw, super::Data, crate::data_file_path, std::fs,
std::path::PathBuf,
};

#[cfg(target_os = "linux")]
#[test]
fn test_data_type_init() {
let run_data_dir = PathBuf::from("./performance_data_init_test");
fs::DirBuilder::new()
.recursive(true)
.create(&run_data_dir)
.unwrap();

// Constructing a DataCollector creates and opens the data file.
let data = CpuUtilizationRaw::new();
let _dc = DataCollector::new(
"cpu_utilization",
Data::CpuUtilizationRaw(data),
&run_data_dir,
);

let expected_path = data_file_path("cpu_utilization", &run_data_dir);
assert!(expected_path.exists());

fs::remove_dir_all(&run_data_dir).unwrap();
}

#[cfg(target_os = "linux")]
#[test]
fn test_print() {
let run_data_dir = PathBuf::from("./performance_data_print_test");
fs::DirBuilder::new()
.recursive(true)
.create(&run_data_dir)
.unwrap();

let data = CpuUtilizationRaw::new();
let mut dc = DataCollector::new(
"cpu_utilization",
Data::CpuUtilizationRaw(data),
&run_data_dir,
);

let data_file_path = data_file_path("cpu_utilization", &run_data_dir);
assert!(data_file_path.exists());
dc.write_to_file().unwrap();

// Re-open the file to read back what was serialized (the collector's own handle is in
// append mode).
let read_handle = fs::File::open(&data_file_path).unwrap();
loop {
match bincode::deserialize_from::<_, Data>(&read_handle) {
Ok(v) => match v {
Data::CpuUtilizationRaw(ref value) => assert!(value.data.is_empty()),
_ => unreachable!(),
},
Err(e) => match *e {
bincode::ErrorKind::Io(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
break
}
_ => unreachable!(),
},
};
}
fs::remove_dir_all(&run_data_dir).unwrap();
}

#[test]
fn test_time_diff_second() {
Expand Down
57 changes: 47 additions & 10 deletions src/data/aperf_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ impl AperfStat {
}
}

pub fn for_time(time: TimeEnum) -> Self {
AperfStat {
time,
name: String::new(),
data: HashMap::new(),
}
}

pub fn measure<F>(&mut self, name: String, mut func: F) -> Result<()>
where
F: FnMut() -> Result<()>,
Expand Down Expand Up @@ -69,20 +77,49 @@ impl ProcessData for AperfStat {
};
}

let mut collection_started = false;
for value in values {
time_series_data_processor.proceed_to_time(value.time);
// Ignore the time diff for data before the collection started, as time_diff
// computation would have been corrupted and these data are not time-series anyway.
if !collection_started
&& report_params
.collection_start
.map_or(true, |collection_start_time| {
value.time >= collection_start_time
})
{
collection_started = true;
}
if collection_started {
time_series_data_processor.proceed_to_time(value.time);
}

for (name, stat) in value.data {
let datatype: Vec<&str> = name.split('-').collect();
let metric_name = datatype[0];
let mut series_name = datatype.get(1).unwrap_or(&metric_name).to_string();
// Make the series name easier to understand - since it's essentially to write the
// collected data to disk
if series_name == "print" {
series_name = "write".to_string();
for (stat_key, stat_value) in value.data {
let stat_key_components: Vec<&str> = stat_key.split('-').collect();
let data_name = stat_key_components[0];
let mut stat_name = stat_key_components.get(1).unwrap_or(&data_name).to_string();
// Backward compatibility - the previous stat name was "print"
if stat_name == "print" {
stat_name = "write".to_string();
}

time_series_data_processor.add_data_point(metric_name, &series_name, stat as f64);
if stat_name == "collect" || stat_name == "write" {
// The stats for APerf collecting time-series data, which should be
// processed as regular time-series data as well.
time_series_data_processor.add_data_point(
data_name,
&stat_name,
stat_value as f64,
);
} else {
// For non-time-series stats, group them in a dummy metric by stat_name as different
// series by data_name.
time_series_data_processor.add_data_point(
&stat_name,
data_name,
stat_value as f64,
);
}
}
}

Expand Down
29 changes: 21 additions & 8 deletions src/data/common/time_series_data_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,7 @@ impl TimeSeriesDataProcessor {
series.values.push(metric_value);

// Every series value in the metric accounts for its value range
let (min, max) = self
.per_metric_value_range
.entry(metric_name.to_string())
.or_insert((metric_value, metric_value));
*min = (*min).min(metric_value);
*max = (*max).max(metric_value);
update_metric_value_range(&mut self.per_metric_value_range, metric_name, metric_value);

if self.aggregate_mode == TimeSeriesDataAggregateMode::Average
|| self.aggregate_mode == TimeSeriesDataAggregateMode::Sum
Expand Down Expand Up @@ -243,7 +238,7 @@ impl TimeSeriesDataProcessor {
_ => "aggregate",
});

for (metric_name, (sum, count)) in &mut self.per_metric_sum_count {
for (metric_name, (sum, count)) in &self.per_metric_sum_count {
let aggregate_series = self
.per_metric_series
.entry(metric_name.clone())
Expand All @@ -259,7 +254,10 @@ impl TimeSeriesDataProcessor {
0.0
}
}
TimeSeriesDataAggregateMode::Sum => *sum,
TimeSeriesDataAggregateMode::Sum => {
update_metric_value_range(&mut self.per_metric_value_range, metric_name, *sum);
*sum
}
_ => break,
};
aggregate_series.values.push(aggregate_value);
Expand Down Expand Up @@ -397,6 +395,18 @@ impl TimeSeriesDataProcessor {
}
}

fn update_metric_value_range(
per_metric_value_range: &mut HashMap<String, (f64, f64)>,
metric_name: &str,
metric_value: f64,
) {
let (min, max) = per_metric_value_range
.entry(metric_name.to_string())
.or_insert_with(|| (metric_value, metric_value));
*min = (*min).min(metric_value);
*max = (*max).max(metric_value);
}

fn compress_all_zero_time_series_metric(time_series_metric: &mut TimeSeriesMetric) {
if time_series_metric.stats.min == 0.0 && time_series_metric.stats.max == 0.0 {
for series in &mut time_series_metric.series {
Expand Down Expand Up @@ -806,6 +816,9 @@ mod tests {
// Sum: 10+20+30=60, 40+50+60=150
assert_eq!(agg.values, vec![60.0, 150.0]);
assert_eq!(agg.series_name.as_str(), "sum");
// The value range must account for the aggregate sum (max 150), not just the
// individual series data points (max 60).
assert_eq!(ts.metrics["m"].value_range, (10, 150));
}

#[test]
Expand Down
Loading
Loading