Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement --factor option #65

Merged
merged 7 commits into from
Feb 28, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 7 additions & 0 deletions src/bin/flamegraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ struct Opt {
/// switch differential hues (green<->red)
#[structopt(long = "negate")]
negate: bool,

/// factor to scale sample counts by
#[structopt(long = "factor")]
factor: Option<f64>,
}

impl Into<Options> for Opt {
Expand All @@ -66,6 +70,9 @@ impl Into<Options> for Opt {
options.title = "Icicle Graph".to_string();
}
options.negate_differentials = self.negate;
if let Some(factor) = self.factor {
options.factor = factor;
}
jasonrhansen marked this conversation as resolved.
Show resolved Hide resolved
options
}
}
Expand Down
15 changes: 11 additions & 4 deletions src/flamegraph/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ pub(super) struct Frame<'a> {
pub(super) depth: usize,
}

#[derive(Debug, PartialEq, Eq, Hash)]
#[derive(Debug, PartialEq)]
pub(super) struct TimedFrame<'a> {
pub(super) location: Frame<'a>,
pub(super) start_time: usize,
pub(super) end_time: usize,
pub(super) delta: Option<isize>,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub(super) struct FrameTime {
pub(super) start_time: usize,
pub(super) delta: Option<isize>,
Expand Down Expand Up @@ -184,10 +184,17 @@ fn parse_nsamples(line: &mut &str) -> Option<usize> {
let samplesi = line.rfind(' ')?;
let mut samples = &line[(samplesi + 1)..];

// strip fractional part (if any);
// Strip fractional part (if any);
// foobar 1.klwdjlakdj
// TODO: Properly handle fractional samples (see issue #43)
//
// The Perl version keeps the fractional part but this can be problematic
// because of cumulative floating point errors. Instead we recommend to
// use the --factor option. See https://github.com/brendangregg/FlameGraph/pull/18
if let Some(doti) = samples.find('.') {
// Warn if we're stripping a non-zero fractional part.
if !samples[doti + 1..].chars().all(|c| c == '0') {
warn!("Fractional part of {} stripped. If you need to retain the extra precision you can scale up the sample data and use the --factor option to scale it back down.", samples);
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
}
samples = &samples[..doti];
}

Expand Down
19 changes: 16 additions & 3 deletions src/flamegraph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,25 @@ pub struct Options {
///
/// [differential]: http://www.brendangregg.com/blog/2014-11-09/differential-flame-graphs.html
pub negate_differentials: bool,

/// Factor to scale sample counts by in the flame graph.
///
/// This option can be useful if the sample data has fractional sample counts since the fractional
/// parts are stripped off when creating the flame graph. To work around this you can scale up the
/// sample counts to be integers, then scale them back down in the graph with the `factor` option.
///
/// For example, if you have `23.4` as a sample count you can upscale it to `234`, then set `factor`
/// to `0.1`.
///
/// Defaults to 1.0.
pub factor: f64,
}

impl Default for Options {
fn default() -> Self {
Options {
title: "Flame Graph".to_string(),
factor: 1.0,
colors: Default::default(),
bgcolors: Default::default(),
hash: Default::default(),
Expand Down Expand Up @@ -324,7 +337,7 @@ where
};
let rect = Rectangle { x1, y1, x2, y2 };

let samples = frame.end_time - frame.start_time;
let samples = ((frame.end_time - frame.start_time) as f64 * opt.factor).round() as usize;

// add thousands separators to `samples`
let _ = samples_txt_buffer.write_formatted(&samples, &Locale::en);
Expand All @@ -333,7 +346,7 @@ where
let info = if frame.location.function.is_empty() && frame.location.depth == 0 {
write!(buffer, "all ({} samples, 100%)", samples_txt)
} else {
let pct = (100 * samples) as f64 / timemax as f64;
let pct = (100 * samples) as f64 / (timemax as f64 * opt.factor);
let function = deannotate(&frame.location.function);
match frame.delta {
None => write!(
Expand All @@ -351,7 +364,7 @@ where
if opt.negate_differentials {
delta = -delta;
}
let delta_pct = (100 * delta) as f64 / timemax as f64;
let delta_pct = (100 * delta) as f64 / (timemax as f64 * opt.factor);
write!(
buffer,
"{} ({} samples, {:.2}%; {:+.2}%)",
Expand Down
Loading