Generate self-profiler types with macros

This commit is contained in:
Wesley Wiser 2018-07-23 21:52:39 -04:00
parent 60c2e9a329
commit 2d3a0a9927

View File

@ -14,8 +14,104 @@ use std::fs;
use std::io::{self, StdoutLock, Write};
use std::time::Instant;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ProfileCategory {
macro_rules! define_categories {
($($name:ident,)*) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProfileCategory {
$($name),*
}
#[allow(bad_style)]
struct Categories<T> {
$($name: T),*
}
impl<T: Default> Categories<T> {
fn new() -> Categories<T> {
Categories {
$($name: T::default()),*
}
}
}
impl<T> Categories<T> {
fn get(&self, category: ProfileCategory) -> &T {
match category {
$(ProfileCategory::$name => &self.$name),*
}
}
fn set(&mut self, category: ProfileCategory, value: T) {
match category {
$(ProfileCategory::$name => self.$name = value),*
}
}
}
struct CategoryData {
times: Categories<u64>,
query_counts: Categories<(u64, u64)>,
}
impl CategoryData {
fn new() -> CategoryData {
CategoryData {
times: Categories::new(),
query_counts: Categories::new(),
}
}
fn print(&self, lock: &mut StdoutLock) {
writeln!(lock, "| Phase | Time (ms) | Queries | Hits (%) |")
.unwrap();
writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
.unwrap();
$(
let (hits, total) = self.query_counts.$name;
let (hits, total) = if total > 0 {
(format!("{:.2}",
(((hits as f32) / (total as f32)) * 100.0)), total.to_string())
} else {
("".into(), "".into())
};
writeln!(
lock,
"| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
stringify!($name),
self.times.$name / 1_000_000,
total,
hits
).unwrap();
)*
}
fn json(&self) -> String {
let mut json = String::from("[");
$(
let (hits, total) = self.query_counts.$name;
json.push_str(&format!(
"{{ \"category\": {}, \"time_ms\": {},
\"query_count\": {}, \"query_hits\": {} }}",
stringify!($name),
self.times.$name / 1_000_000,
total,
format!("{:.2}", (((hits as f32) / (total as f32)) * 100.0))
));
)*
json.push(']');
json
}
}
}
}
define_categories! {
Parsing,
Expansion,
TypeChecking,
@ -25,141 +121,6 @@ pub enum ProfileCategory {
Other,
}
struct Categories<T> {
parsing: T,
expansion: T,
type_checking: T,
borrow_checking: T,
codegen: T,
linking: T,
other: T,
}
impl<T: Default> Categories<T> {
fn new() -> Categories<T> {
Categories {
parsing: T::default(),
expansion: T::default(),
type_checking: T::default(),
borrow_checking: T::default(),
codegen: T::default(),
linking: T::default(),
other: T::default(),
}
}
}
impl<T> Categories<T> {
fn get(&self, category: ProfileCategory) -> &T {
match category {
ProfileCategory::Parsing => &self.parsing,
ProfileCategory::Expansion => &self.expansion,
ProfileCategory::TypeChecking => &self.type_checking,
ProfileCategory::BorrowChecking => &self.borrow_checking,
ProfileCategory::Codegen => &self.codegen,
ProfileCategory::Linking => &self.linking,
ProfileCategory::Other => &self.other,
}
}
fn set(&mut self, category: ProfileCategory, value: T) {
match category {
ProfileCategory::Parsing => self.parsing = value,
ProfileCategory::Expansion => self.expansion = value,
ProfileCategory::TypeChecking => self.type_checking = value,
ProfileCategory::BorrowChecking => self.borrow_checking = value,
ProfileCategory::Codegen => self.codegen = value,
ProfileCategory::Linking => self.linking = value,
ProfileCategory::Other => self.other = value,
}
}
}
struct CategoryData {
times: Categories<u64>,
query_counts: Categories<(u64, u64)>,
}
impl CategoryData {
fn new() -> CategoryData {
CategoryData {
times: Categories::new(),
query_counts: Categories::new(),
}
}
fn print(&self, lock: &mut StdoutLock) {
macro_rules! p {
($name:tt, $rustic_name:ident) => {
let (hits, total) = self.query_counts.$rustic_name;
let (hits, total) = if total > 0 {
(format!("{:.2}",
(((hits as f32) / (total as f32)) * 100.0)), total.to_string())
} else {
("".into(), "".into())
};
writeln!(
lock,
"| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
$name,
self.times.$rustic_name / 1_000_000,
total,
hits
).unwrap();
};
}
writeln!(lock, "| Phase | Time (ms) | Queries | Hits (%) |")
.unwrap();
writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
.unwrap();
p!("Parsing", parsing);
p!("Expansion", expansion);
p!("TypeChecking", type_checking);
p!("BorrowChecking", borrow_checking);
p!("Codegen", codegen);
p!("Linking", linking);
p!("Other", other);
}
fn json(&self) -> String {
macro_rules! j {
($category:tt, $rustic_name:ident) => {{
let (hits, total) = self.query_counts.$rustic_name;
format!(
"{{ \"category\": {}, \"time_ms\": {},
\"query_count\": {}, \"query_hits\": {} }}",
stringify!($category),
self.times.$rustic_name / 1_000_000,
total,
format!("{:.2}", (((hits as f32) / (total as f32)) * 100.0))
)
}}
}
format!("[
{},
{},
{},
{},
{},
{},
{}
]",
j!("Parsing", parsing),
j!("Expansion", expansion),
j!("TypeChecking", type_checking),
j!("BorrowChecking", borrow_checking),
j!("Codegen", codegen),
j!("Linking", linking),
j!("Other", other)
)
}
}
pub struct SelfProfiler {
timer_stack: Vec<ProfileCategory>,
data: CategoryData,