auto merge of #808 : tikue/servo/master, r=metajack

* Use ProfilerBucket structs instead of (ProfilerCategory, ~[Float]) tuples
* Simplify the order check of bucket categories
This commit is contained in:
bors-servo 2013-08-28 22:06:27 -07:00
commit 65c6435902

View file

@ -8,6 +8,7 @@ use std::cell::Cell;
use std::comm::{Port, SharedChan}; use std::comm::{Port, SharedChan};
use extra::sort::tim_sort; use extra::sort::tim_sort;
use std::iterator::AdditiveIterator; use std::iterator::AdditiveIterator;
use extra::treemap::TreeMap;
// front-end representation of the profiler used to communicate with the profiler // front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)] #[deriving(Clone)]
@ -26,7 +27,14 @@ impl ProfilerChan {
} }
} }
#[deriving(Eq, Clone)] pub enum ProfilerMsg {
// Normal message used for reporting time
TimeMsg(ProfilerCategory, float),
// Message used to force print the profiling metrics
PrintMsg,
}
#[deriving(Eq, Clone, TotalEq, TotalOrd)]
pub enum ProfilerCategory { pub enum ProfilerCategory {
CompositingCategory, CompositingCategory,
LayoutQueryCategory, LayoutQueryCategory,
@ -41,65 +49,36 @@ pub enum ProfilerCategory {
RenderingDrawingCategory, RenderingDrawingCategory,
RenderingPrepBuffCategory, RenderingPrepBuffCategory,
RenderingCategory, RenderingCategory,
// hackish but helps prevent errors when adding new categories // FIXME(rust#8803): workaround for lack of CTFE function on enum types to return length
NUM_BUCKETS, NumBuckets,
}
// FIXME(#5873) this should be initialized by a NUM_BUCKETS cast,
static BUCKETS: uint = 13;
type ProfilerBuckets = [(ProfilerCategory, ~[float]), ..BUCKETS];
pub enum ProfilerMsg {
// Normal message used for reporting time
TimeMsg(ProfilerCategory, float),
// Message used to force print the profiling metrics
PrintMsg,
}
// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
port: Port<ProfilerMsg>,
buckets: ProfilerBuckets,
last_msg: Option<ProfilerMsg>,
} }
impl ProfilerCategory { impl ProfilerCategory {
// convenience function to not have to cast every time // convenience function to not have to cast every time
pub fn num_buckets() -> uint { pub fn num_buckets() -> uint {
NUM_BUCKETS as uint NumBuckets as uint
} }
// enumeration of all ProfilerCategory types // enumeration of all ProfilerCategory types
// TODO(tkuehn): is there a better way to ensure proper order of categories?
fn empty_buckets() -> ProfilerBuckets { fn empty_buckets() -> ProfilerBuckets {
let buckets = [ let mut buckets = TreeMap::new();
(CompositingCategory, ~[]), buckets.insert(CompositingCategory, ~[]);
(LayoutQueryCategory, ~[]), buckets.insert(LayoutQueryCategory, ~[]);
(LayoutPerformCategory, ~[]), buckets.insert(LayoutPerformCategory, ~[]);
(LayoutAuxInitCategory, ~[]), buckets.insert(LayoutAuxInitCategory, ~[]);
(LayoutSelectorMatchCategory, ~[]), buckets.insert(LayoutSelectorMatchCategory, ~[]);
(LayoutTreeBuilderCategory, ~[]), buckets.insert(LayoutTreeBuilderCategory, ~[]);
(LayoutMainCategory, ~[]), buckets.insert(LayoutMainCategory, ~[]);
(LayoutShapingCategory, ~[]), buckets.insert(LayoutShapingCategory, ~[]);
(LayoutDispListBuildCategory, ~[]), buckets.insert(LayoutDispListBuildCategory, ~[]);
(GfxRegenAvailableFontsCategory, ~[]), buckets.insert(GfxRegenAvailableFontsCategory, ~[]);
(RenderingDrawingCategory, ~[]), buckets.insert(RenderingDrawingCategory, ~[]);
(RenderingPrepBuffCategory, ~[]), buckets.insert(RenderingPrepBuffCategory, ~[]);
(RenderingCategory, ~[]), buckets.insert(RenderingCategory, ~[]);
];
ProfilerCategory::check_order(&buckets);
buckets buckets
} }
// ensure that the order of the buckets matches the order of the enum categories
fn check_order(vec: &ProfilerBuckets) {
for &(category, _) in vec.iter() {
if category != vec[category as uint].first() {
fail!("Enum category does not match bucket index. This is a bug.");
}
}
}
// some categories are subcategories of LayoutPerformCategory // some categories are subcategories of LayoutPerformCategory
// and should be printed to indicate this // and should be printed to indicate this
pub fn format(self) -> ~str { pub fn format(self) -> ~str {
@ -112,6 +91,15 @@ impl ProfilerCategory {
} }
} }
type ProfilerBuckets = TreeMap<ProfilerCategory, ~[float]>;
// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
port: Port<ProfilerMsg>,
buckets: ProfilerBuckets,
last_msg: Option<ProfilerMsg>,
}
impl Profiler { impl Profiler {
pub fn create(port: Port<ProfilerMsg>) { pub fn create(port: Port<ProfilerMsg>) {
let port = Cell::new(port); let port = Cell::new(port);
@ -141,14 +129,11 @@ impl Profiler {
fn handle_msg(&mut self, msg: ProfilerMsg) { fn handle_msg(&mut self, msg: ProfilerMsg) {
match msg { match msg {
TimeMsg(category, t) => match self.buckets[category as uint] { TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
//TODO(tkuehn): would be nice to have tuple.second_mut()
(_, ref mut data) => data.push(t),
},
PrintMsg => match self.last_msg { PrintMsg => match self.last_msg {
// only print if more data has arrived since the last printout // only print if more data has arrived since the last printout
Some(TimeMsg(*)) => self.print_buckets(), Some(TimeMsg(*)) => self.print_buckets(),
_ => {} _ => ()
}, },
}; };
self.last_msg = Some(msg); self.last_msg = Some(msg);
@ -158,11 +143,10 @@ impl Profiler {
println(fmt!("%31s %15s %15s %15s %15s %15s", println(fmt!("%31s %15s %15s %15s %15s %15s",
"_category_", "_mean (ms)_", "_median (ms)_", "_category_", "_mean (ms)_", "_median (ms)_",
"_min (ms)_", "_max (ms)_", "_bucket size_")); "_min (ms)_", "_max (ms)_", "_bucket size_"));
for bucket in self.buckets.mut_iter() { for (category, data) in self.buckets.iter() {
let (category, data) = match *bucket { // FIXME(XXX): TreeMap currently lacks mut_iter()
(category, ref mut data) => (category, data), let mut data = data.clone();
}; tim_sort(data);
tim_sort(*data);
let data_len = data.len(); let data_len = data.len();
if data_len > 0 { if data_len > 0 {
let (mean, median, &min, &max) = let (mean, median, &min, &max) =
@ -202,4 +186,12 @@ pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
return val; return val;
} }
#[cfg(test)]
mod test {
// ensure that the order of the buckets matches the order of the enum categories
#[test]
fn check_order() {
let buckets = ProfilerCategory::empty_buckets();
assert!(buckets.len() == NumBuckets as uint);
}
}