Skip to content

orenbenkiki/flameview

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

flameview

Generate a flame graph view.

REQUIREMENTS

flameview.py requires Python 3.6 or above. It does not require the installation of any supporting modules.

INSTALLATION

Download flameview.py and place it in your path. You might need to tweak the #! line to execute the correct python interpreter; by default it invokes python3.

STATUS

This is a beta version 0.1-b7. It provides the basic functionality and seems to work in Firefox, Chrome and Edge. However, it hasn't been heavily tested. Feedback is welcome.

EXAMPLES

The example.fg was copied from one of the example files in flamegraph.pl. The generated HTML (using the command line flameview.py example.fg > example.html), is in example.fg.html.

Hover over any cell to view its data in a tooltip.

If you hover over any cell, you will see how much it takes and its percentage of the total and the visible graph.

You can change what is visible by selecting cells. If you click on a cell, it will toggle its selection. Selected cell names are shown in bold. If you double-click on a cell, it will toggle all (visible) cells with the same name. If you double-click the background, all selections will be cleared and you will see the whole graph again. Initially no cells are selected and all are visible.

If you select some cells, the graph will only show everything relevant to them. The tooltips will be updated to show percentages of the visible graph, as well as percentages of the total.

For example, click on "simplelog::termlog::TermLogger::new::h94d15a7bc0cbc21f". You will in its tooltip it takes 35.14% of the total, as before. If you hover over "term::terminfo::TermInfo::from_name::h721edfed0d4e6840" you will see it takes 69.23% out of this (which is 24.32% of the total). Click on "simplelog::termlog::TermLogger::new::h94d15a7bc0cbc21f" again to see the whole graph.

Then, you hover over the collections::vec::from_elem::... cell. You will see it takes 21.62% of the samples. You will notice that additional cells are highlighted - all the cells with the same name. If you double-click any of them, you will see the same function is invoked in three different call chains. Hover over the bottom "all" cell to see these take 32.43% of the total samples. Double-click on the graph background to clear the selection and see the whole graph.

A useful technique is to click the "all" cell at the bottom. This will force all cells to be visible. Then, click or double-click several cells of interest, selecting them. Clicking (deselecting) "all" will show only the selected subset of cells. Clicking (reselecting) "all" again allows refining the set of selected cells. This allows dynamically building arbitrary subset views of the graphs, and seeing which calls take the most time in these subsets.

The example.fg was generated especially for use by flameview.py, that is, it makes use of its additional features. It was captured from an execution of a bio-informatics pipeline. The execution is parallelized across multiple processes. Each spawn point is marked with a "-" cell (single-letter cells appear in gray). If you double-click on any "(sync)" cell, and then hover over the bottom "all" cell, you will see the total overhead of synchronization between these processes is 8.98%. The cell tooltips contain the number of invocations. Cells in parallel processes show the average measurements in each process, and their tooltip also list the number of processes used.

USAGE

The output of flameview.py -h is:

usage: flameview.py [-h] [--minpercent PERCENT] [--sortby SORT_KEY]
                    [--inverted] [--title TITLE] [--sizename NAME]
                    [--nodefaultcss] [--addcss CSS] [--colors PALETTE]
                    [--seed SEED] [--strict] [--output HTML] [--version]
                    [FLAMEGRAPH]

Generate a flamegraph view.

positional arguments:
  FLAMEGRAPH            The flamegraph data file to read; default: "-", read
                        from standard input

optional arguments:
  -h, --help            show this help message and exit
  --minpercent PERCENT  The minimal percent of the entries to display;
                        default: 0.1 (1/1000 of the total)
  --sortby SORT_KEY     How to sort nodes: name (default) - lexicographically,
                        size - by the size data, input - by input order
  --reverse             If specified, reverse all call stacks.
  --inverted            If specified, generate an inverted (icicles) graph.
  --title TITLE         An optional title for the HTML document; default:
                        "Flame Graph" or "Icicle Graph"
  --sizename NAME       The name of the size data; default: "samples".
  --nodefaultcss        If specified, the default appearance CSS is omitted,
                        probably to avoid interfering with --addcss
  --addcss CSS          The name of a CSS file to embed into the output HTML
  --colors PALETTE      The color palette(s) to use, subset of flamegraph.pl.
                        Default: "hot", other choices are: cold, mem, io,
                        red, green, blue, aqua, yellow, purple, nd orange.
                        You can specify multiple palettes separated by ";",
                        e.g. "hot;cold". Node names that end with _[N] will
                        use the Nth palette (e.g. _[1]). Note that only the
                        final name in each call stack can/needs to be so
                        annotated. Node names w/o a suffix will use the 0th
                        (first) palette. If not enough palettes are specified
                        in the command line, the last palette will be used
                        for a too-high palette index in a node.
  --seed SEED           An optional seed for repeatable random color
                        generation; default: None
  --strict              If specified, abort with an error on invalid input
                        lines.
  --output HTML         The HTML file to write; default: "-", write to
                        standard output
  --version             Print the version information (0.1-b7) and exit

INPUT: A flamegraph file. Each line must be in the format:

    name;...;name size [difference] [#tooltip_html]

OUTPUT: An HTML file visualizing the flame graph.

DESCRIPTION

flameview.py is inspired by the flamegraph.pl program, which you can obtain from https://github.com/brendangregg/FlameGraph. The flamegraph program is much more mature, contains a detailed description of what flame graphs are, and provides many features that flameview lacks: support for differential graphs, flamecharts, stable hash-based colors, automatic language-specific color palettes, ...

The flameview program does provide some features that flamegraph lacks:

  • Each input line may end with a # character followed by an arbitrary HTML string. This string will be placed in the tooltip displayed when hovering above the relevant graph cell. This allows attaching arbitrary data to each cell. For example, it is possible to display both CPU time (as the sizes) and invocations count (in the tooltip), similarly to the output of gprof.

  • Size data may be float rather than only integer. This allows, for example, to directly use wall clock time, in seconds, as the size measure.

  • Size data is optional. This allows attaching tooltip information to cells that don't have direct measurements (but have sub-cells that do).

  • The output is an interactive file, using HTML rather than SVG. As a result, there is no need to specify the size of the graph in advance. Instead it always spans the full width of the browser's window.

  • Selecting (clicking on) a cell restricts the view to the subset of the graph rooted in the selected cell(s). Selecting the bottom "all" cell views all the graph.

    Double-clicking a cell allows for de/selecting all (visible) cells with the same name. Double-clicking the background clears all selections. The currently selected cell(s) are highlighted using a bold name.

  • Hovering over any cell highlights all other cells with the same name. These are the cells that will toggle if you double-click the cell.

    Hovering over any cell will display a tooltip containing its name, its size, the percentage of this size out of the total and visible graph, and the additional tooltip HTML, if any, from the input file. Since tooltips are intrusive alt-clicking on a tooltip or a cell toggles them.

    Hovering over the "all" cell when a subset of the graph is visible will display a tooltip with the percentages of the currently visible (selected) graph out of the total graph.

  • Explicit "(self)" cells are created when some call chain has both its own size and also sizes for further nested call chains. In such a case, the self cell will display the input tooltip and the sizes for the call chain; the lower level cell will display the sum of the self size and all the nested invocations.

The above allows the result flame graph to provide all the information one would get from a gprof output (and more), in a visual form:

  • The tooltips may provide the invocations count, or any other data which is associated with the call chain.

  • Self nodes allow viewing the sizes of the function itself, as opposed to the sum of the function and everything it invokes (which is also available).

  • if you double-click to select a function "foo", you will see all the invocations of the "foo" function anywhere in the graph, each one above its caller chain. This makes it easy to see the both total measure of "foo", what percentage this is of the program's total, and which percentage is due to which caller.

In general, by de/selecting multiple cells it is possible to gain valuable additional insights about the execution, which are impossible to obtain using the output of flamegraph.pl, even though the data is present in the graph. Yes, you can generate a seperate inverse graphs to get some of this information, but this is clunky and not as powerful.

TWEAKING

The output of flameview tries to be well-behaved CSS-annotated HTML 5 (clean according to https://validator.w3.org/), with the inevitable embedded javascript code (clean according to https://jslint.com/ except for containing long generated data lines). The file requires no external resources, and contains hopefully helpful comments to help tweaking it.

The HTML uses absolute positioning to control the horizontal location of the cells, and lets HTML automatically determine the height of each row (one "normal" text line height). I tried using both table and CSS grid layout but neither approach gave me the needed control across browsers.

It should be "easy" to tweak the appearance of the graph by tweaking the CSS. The embedded CSS stylesheet is given in two parts. The first part controls the layout, which you probably don't want to mess with (unless you want to try switching to CSS grid layout).

The second part controls appearance, using the following CSS selectors:

  • #graph: The div containing the whole graph.

  • #width: An empty div following the graph, used to detect the available vertical space. If you force its width, the graph will adjust accordingly.

  • .row: Class for a div containing a single graph row. Uses relative positioning.

  • .height: An invisible div containing   to force the height of the row. If you adjust its height, the row will adjust accordingly. Note the actual row cells do not affect the height because they use absolute positioning.

  • .self, .leaf, .sum: Classes for div elements, reflecting the kind of cell. Currently simple border/centering rules are applied to all cells.

    The background color of cells is hard-coded in the div element according to the chosen color palette. It might arguably make sense to define some color classes instead, and switch palettes using CSS instead.

  • .name: Class for a span inside the tooltip div, which holds the name of the cell. Note the name may be different from the label; specifically, when the label is "(self)", the name is "name;(self)". Currently the CSS just makes the name font italic.

  • .basic: Class for a div inside the tooltip, which holds the basic computed data about the cell. Currently this has no special formatting.

  • .computed: Class for an empty span inside the basic div, which is automatically filled with the computed size sum and percentage depending on the visible cells. Currently this has no special formatting.

  • .extra: Class for a div inside the tooltip, which holds the extra tooltip HTML from the input file. Currently this has no special formatting.

  • .label: Class for the div contained in each cell to hold the label. Making this a sibling rather than a parent of the tooltip makes it easier to apply CSS rules only to it.

  • .group_hover: Class applied to each cell that has the same name as the one under the mouse. Currently this turns the cell(s) background color to ivory, which makes them stand out of the rest of the colored cells.

  • .selected: Class for the currently selected cell(s). Currently this just makes the label font bold. This might be too subtle an effect.

You can append additional CSS rules into the HTML to tweak the default appearance CSS, or omit the default and provide a full replacement CSS instead.

FURTHER WORK

  • If HTML is preferable to SVG, then it would make sense to further develop flameview.py to become a true replacement for flamegraph.pl. This would require re-implementing all the features already present in flamegraph. None of the features seem terribly complex, but their total is far from trivial.

    Otherwise, it might make more sense to enhance the SVG output of flamegraph.pl to provide for multiple cell selection and explicit "(self)" nodes. This would have to be done in Perl though ;-)

  • The default CSS appearance rules could definitely be improved. It is also technically trivial to provide a selection between several built-in --csstheme options. Actually designing such options is much more work.

  • Using absolute positioning for layout is basically giving up on the CSS layout engine. It would be nice if CSS grid layout could be made to handle this for us instead.

The code is pretty simple and short (~1K LOC total, including the Python, CSS, Javascript and HTML). It gets a clean bill of health from mypy and pylint. Pull requests are welcome.

LICENSE

flameview.py is available under the MIT license.

About

Generate a flame graph view.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors