Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/bin/flamegraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct Opt {
short = "c",
long = "colors",
default_value = defaults::COLORS,
possible_values = &["aqua","blue","green","hot","io","java","js","mem","orange","perl","purple","red","wakeup","yellow"],
possible_values = &["annotated","aqua","blue","green","hot","io","java","js","mem","orange","perl","purple","red","wakeup","yellow","grey","gray"],
value_name = "STRING"
)]
colors: Palette,
Expand Down
18 changes: 15 additions & 3 deletions src/flamegraph/color/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,21 @@ impl Default for BackgroundColor {

/// A flame graph color palette.
///
/// Defaults to [`BasicPalette::Hot`].
/// Defaults to [`MultiPalette::Annotated`].
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Palette {
/// A plain color palette in which the color is not chosen based on function semantics.
///
/// See [`BasicPalette`] for details.
Basic(BasicPalette),
/// A semantic color palette in which different hues are used to signifiy semantic aspects of
/// A semantic color palette in which different hues are used to signify semantic aspects of
/// different function names (kernel functions, JIT functions, etc.).
Multi(MultiPalette),
}

impl Default for Palette {
fn default() -> Self {
Palette::Basic(BasicPalette::Hot)
Palette::Multi(MultiPalette::Annotated)
}
}

Expand Down Expand Up @@ -112,12 +112,16 @@ pub enum BasicPalette {
Purple,
/// A palette in which colors are chosen from a orange spectrum.
Orange,
/// A palette in which colors are chosen from a gray spectrum.
Gray,
}

/// A semantic color palette in which different hues are used to signifiy semantic aspects of
/// different function names (kernel functions, JIT functions, etc.).
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MultiPalette {
/// Use function annotations with no specific language heuristics to color frames.
Annotated,
/// Use Java semantics to color frames.
Java,
/// Use JavaScript semantics to color frames.
Expand Down Expand Up @@ -193,6 +197,7 @@ impl FromStr for Palette {
"mem" => Ok(Palette::Basic(BasicPalette::Mem)),
"io" => Ok(Palette::Basic(BasicPalette::Io)),
"wakeup" => Ok(Palette::Multi(MultiPalette::Wakeup)),
"annotated" => Ok(Palette::Multi(MultiPalette::Annotated)),
"java" => Ok(Palette::Multi(MultiPalette::Java)),
"js" => Ok(Palette::Multi(MultiPalette::Js)),
"perl" => Ok(Palette::Multi(MultiPalette::Perl)),
Expand All @@ -203,6 +208,7 @@ impl FromStr for Palette {
"yellow" => Ok(Palette::Basic(BasicPalette::Yellow)),
"purple" => Ok(Palette::Basic(BasicPalette::Purple)),
"orange" => Ok(Palette::Basic(BasicPalette::Orange)),
"gray" | "grey" => Ok(Palette::Basic(BasicPalette::Gray)),
unknown => Err(format!("unknown color palette: {}", unknown)),
}
}
Expand Down Expand Up @@ -304,6 +310,7 @@ macro_rules! color {
fn rgb_components_for_palette(palette: Palette, name: &str, v1: f32, v2: f32, v3: f32) -> Color {
let basic_palette = match palette {
Palette::Basic(basic) => basic,
Palette::Multi(MultiPalette::Annotated) => palettes::annotated::resolve(name),
Palette::Multi(MultiPalette::Java) => palettes::java::resolve(name),
Palette::Multi(MultiPalette::Perl) => palettes::perl::resolve(name),
Palette::Multi(MultiPalette::Js) => palettes::js::resolve(name),
Expand All @@ -325,6 +332,11 @@ fn rgb_components_for_palette(palette: Palette, name: &str, v1: f32, v2: f32, v3
}
BasicPalette::Aqua => color!(t!(50, 60_f32, v1), t!(165, 55_f32, v1), t!(165, 55_f32, v1)),
BasicPalette::Orange => color!(t!(190, 65_f32, v1), t!(90, 65_f32, v1), t!(0, 0_f32, v1)),
BasicPalette::Gray => color!(
t!(190, 40_f32, v1),
t!(190, 40_f32, v1),
t!(190, 40_f32, v1)
),
}
}

Expand Down
68 changes: 51 additions & 17 deletions src/flamegraph/color/palettes.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,57 @@
enum Annotation {
Kernel,
Inline,
Jit,
}

fn resolve_annotation(name: &str) -> Option<Annotation> {
if name.ends_with(']') {
if let Some(ai) = name.rfind("_[") {
if name[ai..].len() == 4 {
match &name[ai + 2..ai + 3] {
"k" => return Some(Annotation::Kernel),
"i" => return Some(Annotation::Inline),
"j" => return Some(Annotation::Jit),
_ => {}
}
}
}
}

None
}

pub(super) mod annotated {
use super::Annotation;
use crate::flamegraph::color::BasicPalette;

/// Handle annotations (_[j], _[i], ...; which are
/// accurate) in a generic way.
pub fn resolve(name: &str) -> BasicPalette {
match super::resolve_annotation(name) {
Some(Annotation::Kernel) => BasicPalette::Gray,
Some(Annotation::Inline) => BasicPalette::Aqua,
Some(Annotation::Jit) => BasicPalette::Green,
None => BasicPalette::Hot,
}
}
}

pub(super) mod java {
use super::Annotation;
use crate::flamegraph::color::BasicPalette;

/// Handle both annotations (_[j], _[i], ...; which are
/// accurate), as well as input that lacks any annotations, as
/// best as possible. Without annotations, we get a little hacky
/// and match on java|org|com, etc.
pub fn resolve(name: &str) -> BasicPalette {
if name.ends_with(']') {
if let Some(ai) = name.rfind("_[") {
if name[ai..].len() == 4 {
match &name[ai + 2..ai + 3] {
// kernel annotation
"k" => return BasicPalette::Orange,
// inline annotation
"i" => return BasicPalette::Aqua,
// jit annotation
"j" => return BasicPalette::Green,
_ => {}
}
}
}
if let Some(annotation) = super::resolve_annotation(name) {
return match annotation {
Annotation::Kernel => BasicPalette::Orange,
Annotation::Inline => BasicPalette::Aqua,
Annotation::Jit => BasicPalette::Green,
};
}

let java_prefix = if name.starts_with('L') {
Expand Down Expand Up @@ -51,7 +83,7 @@ pub(super) mod perl {
use crate::flamegraph::color::BasicPalette;

pub fn resolve(name: &str) -> BasicPalette {
if name.ends_with("_[k]") {
if let Some(super::Annotation::Kernel) = super::resolve_annotation(name) {
BasicPalette::Orange
} else if name.contains("Perl") || name.contains(".pl") {
BasicPalette::Green
Expand All @@ -67,11 +99,13 @@ pub(super) mod js {
use crate::flamegraph::color::BasicPalette;

pub fn resolve(name: &str) -> BasicPalette {
let annotation = super::resolve_annotation(name);

if !name.is_empty() && name.trim().is_empty() {
return BasicPalette::Green;
} else if name.ends_with("_[k]") {
} else if let Some(super::Annotation::Kernel) = annotation {
return BasicPalette::Orange;
} else if name.ends_with("_[j]") {
} else if let Some(super::Annotation::Jit) = annotation {
if name.contains('/') {
return BasicPalette::Green;
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/flamegraph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub mod defaults {
}

define! {
COLORS: &str = "hot",
COLORS: &str = "annotated",
SEARCH_COLOR: &str = "#e600e6",
TITLE: &str = "Flame Graph",
CHART_TITLE: &str = "Flame Chart",
Expand Down