src/data/aperf_stats.rs (154 lines of code) (raw):
extern crate ctor;
use crate::data::{ProcessedData, TimeEnum};
use crate::utils::{add_metrics, DataMetrics, Metric};
use crate::visualizer::{DataVisualizer, GetData, GraphLimitType, GraphMetadata, ReportParams};
use crate::VISUALIZATION_DATA;
use anyhow::Result;
use chrono::prelude::*;
use ctor::ctor;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
pub static APERF_RUN_STATS_FILE_NAME: &str = "aperf_run_stats";
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AperfStat {
pub time: TimeEnum,
pub name: String,
pub data: HashMap<String, u64>,
}
impl AperfStat {
fn new() -> Self {
AperfStat {
time: TimeEnum::DateTime(Utc::now()),
name: String::new(),
data: HashMap::new(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PerDataTypeStat {
pub name: String,
pub collect: Vec<DataPoint>,
pub print: Vec<DataPoint>,
pub metadata: GraphMetadata,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DataPoint {
pub time: TimeEnum,
pub time_taken: u64,
}
fn get_key_data(values: Vec<AperfStat>, key: String, metrics: &mut DataMetrics) -> Result<String> {
let mut metric = Metric::new(key.clone());
let mut end_value = PerDataTypeStat {
name: key.clone(),
collect: Vec::new(),
print: Vec::new(),
metadata: GraphMetadata::new(),
};
let time_zero = &values[0].time;
for value in &values {
let time_now = value.time - *time_zero;
for (k, v) in &value.data {
if !k.contains(&key) {
continue;
}
let datapoint = DataPoint {
time: time_now,
time_taken: *v,
};
metric.insert_value(*v as f64);
end_value.metadata.update_limits(GraphLimitType::UInt64(*v));
if k.contains(&key) {
if k.contains("print") {
end_value.print.push(datapoint);
} else {
end_value.collect.push(datapoint);
}
}
}
}
add_metrics(
key,
&mut metric,
metrics,
APERF_RUN_STATS_FILE_NAME.to_string(),
)?;
Ok(serde_json::to_string(&end_value)?)
}
impl GetData for AperfStat {
fn custom_raw_data_parser(&mut self, params: ReportParams) -> Result<Vec<ProcessedData>> {
let mut raw_data: Vec<ProcessedData> = Vec::new();
let file: Result<fs::File> = Ok(fs::OpenOptions::new()
.read(true)
.open(params.data_file_path)
.expect("Could not open APerf Stats file"));
loop {
match bincode::deserialize_from::<_, AperfStat>(file.as_ref().unwrap()) {
Ok(v) => raw_data.push(ProcessedData::AperfStat(v)),
Err(e) => match *e {
// EOF
bincode::ErrorKind::Io(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
break
}
e => panic!("Error when Deserializing APerf Stats data: {}", e),
},
};
}
Ok(raw_data)
}
fn get_calls(&mut self) -> Result<Vec<String>> {
Ok(vec!["keys".to_string(), "values".to_string()])
}
fn get_data(
&mut self,
buffer: Vec<ProcessedData>,
query: String,
metrics: &mut DataMetrics,
) -> Result<String> {
let mut values = Vec::new();
for data in buffer {
match data {
ProcessedData::AperfStat(ref value) => values.push(value.clone()),
_ => unreachable!(),
}
}
let param: Vec<(String, String)> = serde_urlencoded::from_str(&query).unwrap();
let (_, req_str) = ¶m[1];
match req_str.as_str() {
"keys" => {
let mut names = Vec::new();
names.push("aperf".to_string());
let keys = values[0].data.keys().clone();
for k in keys {
let datatype: Vec<&str> = k.split('-').collect();
if !names.contains(&datatype[0].to_string()) {
names.push(datatype[0].to_string());
}
}
Ok(serde_json::to_string(&names)?)
}
"values" => {
let (_, key) = ¶m[2];
get_key_data(values, key.to_string(), metrics)
}
_ => panic!("Unsupported API"),
}
}
}
#[ctor]
fn init_aperf_stats() {
let file_name = APERF_RUN_STATS_FILE_NAME.to_string();
let js_file_name = file_name.clone() + ".js";
let aperf_stat = AperfStat::new();
let mut dv = DataVisualizer::new(
ProcessedData::AperfStat(aperf_stat.clone()),
file_name.clone(),
js_file_name,
include_str!(concat!(env!("JS_DIR"), "/aperf_run_stats.js")).to_string(),
file_name.clone(),
);
dv.has_custom_raw_data_parser();
VISUALIZATION_DATA
.lock()
.unwrap()
.add_visualizer(file_name.clone(), dv);
}