🐦 Friendly little instrumentation profiler for Rust 🦀

Overview

🐦 puffin

The friendly little instrumentation profiler for Rust

Puffin photo by Richard Bartz

Embark Embark Crates.io Docs dependency status Build Status

How to use

fn my_function() {
    puffin::profile_function!();
    ...
    if ... {
        puffin::profile_scope!("load_image", image_name);
        ...
    }
}

The Puffin macros write data to a thread-local data stream. When the outermost scope of a thread is closed, the data stream is sent to a global profiler collector. The scopes are pretty light-weight, costing around 100-200 nanoseconds.

You have to turn on the profiler before it captures any data with a call to puffin::set_scopes_on(true);. When the profiler is off the profiler scope macros only has an overhead of 1-2 ns (and some stack space);

Once per frame you need to call puffin::GlobalProfiler::lock().new_frame();.

UI

To view the profile data in-game you can use puffin_egui.

Puffin Flamegraph using puffin_egui

If you are using the imgui crate, there is also puffin-imgui.

Remote profiling

You can use puffin_http to send profile events over TCP to puffin_viewer.

Other

Also check out the crate profiling which provides a unifying layer of abstraction on top of puffin and other profiling crates.

Contributing

Contributor Covenant

We welcome community contributions to this project.

Please read our Contributor Guide for more information on how to get started.

License

Licensed under either of

at your option.

Puffin photo by Richard Bartz

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Show/hide thread lanes and make them collapsible

    Show/hide thread lanes and make them collapsible

    Checkboxes for hiding and showing puffin flame graph threads.

    The collection is stored in Options as it is nice for it to be saved upon application closing. Also used index map such that order is preserved, we get fast insertion and reading, and only get unique thread entries are shown in thje checkbox list. By storing it in Options we do generate an index map that gets extended longer and longer with time as all threads from all profiled puffin files/applications eventually end up in there. Tho as we still iterate through the currently selected frame threads those other threads do not show up in our checkbox list. Think its not to big of a deal.

    New option to disable thread lanes:

    image

    image

    Collapsable threads:

    image

    opened by TimonPost 17
  • Add tracing integration

    Add tracing integration

    Checklist

    • [x] I have read the Contributor Guide
    • [x] I have read and agree to the Code of Conduct
    • [x] I have added a description of my changes and why I'd like them included in the section below

    Description of Changes

    This adds a new crate implementing integration with tracing. This will let puffin users benefit from other libraries that generate spans with the tracing crate, which I believe is quite extensively used in the Rust ecosystem.

    I was initially going to publish it to a separate repository, but I thought it would probably be a better addition to this one, to make sure this integration is always up to date, advertise it as an official one if you see it fit here.. and pass the maintenance burden to you guys. 😄

    I wrote up the documentation a bit hastily, I'm not sure how sufficient it is. So I'm open to suggestions (and I left the edits allowed as well).

    And thank you for such an awesome tool. I'm also looking forward to it being used by Bevy, which also relies on tracing - so hopefully tracing support in puffin will make Bevy integration much closer to becoming real.

    opened by mvlabat 9
  • Update egui to 0.19

    Update egui to 0.19

    Checklist

    • [x] I have read the Contributor Guide
    • [x] I have read and agree to the Code of Conduct
    • [x] I have added a description of my changes and why I'd like them included in the section below

    Description of Changes

    I've updated egui to 0.19 to make puffin_egui compatible with that version.

    Related Issues

    N/A

    opened by sidit77 8
  • Upgrade to egui 0.20

    Upgrade to egui 0.20

    Checklist

    • [x] I have read the Contributor Guide
    • [x] I have read and agree to the Code of Conduct
    • [x] I have added a description of my changes and why I'd like them included in the section below

    Description of Changes

    Upgrade egui, eframe to 0.20. And upgrade path version rather then minor version.

    opened by TimonPost 6
  • Add max_recent_frames argument

    Add max_recent_frames argument

    Checklist

    (I am getting an error running cargo fmt,

    thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src\libcore\option.rs:335:20
    

    so I have not run rustfmt on this code. I don't normally use rustfmt, so not sure if my setup or rustfmt is broken?)

    • [x] I have read and agree to the Code of Conduct
    • [x] I have added a description of my changes and why I'd like them included in the section below

    Description of Changes

    Adds --max_recent_frames argument to CLI to set the maximum number of frames. Only makes sense to me for HTTP version.

    Note: It looks like the recent frames view behaves weirdly when the max_recent_frames is less than 18,000 (the default) - it starts on the left alright, then jumps to the right (with varying amounts of blank space on the left), then back to the right looking good, seemingly at random. Probably related to something in the EGUI renderer buffering & clearing at intervals or on some event?

    image

    Related Issues

    This is an enhancement. The viewer was eating my memory when using the defaults, 80% of the time I don't want the last 5-10 hours of frames...

    opened by dxenonb 4
  • Run `puffin` and `puffin_egui` on wasm32 on web

    Run `puffin` and `puffin_egui` on wasm32 on web

    Checklist

    • [x] I have read the Contributor Guide
    • [x] I have read and agree to the Code of Conduct
    • [x] I have added a description of my changes and why I'd like them included in the section below

    Description of Changes

    This makes puffin and puffin_egui compile and run on wasm32 compiled for web if you enable the "web" feature.

    The timer resolution on web sucks - it is only 1 ms due to meltdown/spectre mitigation, but having the same code compile and run on both native and web is quite nice regardless.

    I tested this by quickly hacking in to my eframe_template project, and it works!

    opened by emilk 3
  • Don't merge scopes that have different data

    Don't merge scopes that have different data

    Previously we would merge all scopes that have the same id, but if you have multiple scopes after each that have same id but different dynamic data field they would be merged together and we wouldn't display the data field.

    This is something we ran into in our codebase that made it harder to see why a certain heavy operation was happening as we were missing the context for it. Which we did specify but was merged together and not shown here as merging scopes is on by default (and is a general good idea).

    Adds a simple visual test for in the imgui and egui clients.

    Resolves: #73

    Example

    This is how it looks like now:

    image

    from the following code:

    // test to verify these spikes timers are not merged together as they have different data
    for (name, ms) in [("First".to_string(), 20), ("Second".to_string(), 15)] {
        puffin::profile_scope!("Spike", name);
        std::thread::sleep(std::time::Duration::from_millis(ms))
    }
    // these are however fine to merge together as data is the same
    for (_name, ms) in [("First".to_string(), 20), ("Second".to_string(), 15)] {
        puffin::profile_scope!("Spike");
        std::thread::sleep(std::time::Duration::from_millis(ms))
    }
    

    Before this PR this would have been a single "4x Spike"

    opened by repi 3
  • Don't merge scopes that have non-matching dynamic data

    Don't merge scopes that have non-matching dynamic data

    Scopes can have dynamic data, like this:

    puffin::profile_scope!("my_scope_id", my_dynamic_data);
    

    However, puffin's UI still happily merges blocks with different dynamic data together if merging is enabled. It would be nice with a mode that would only merge identical blocks if their dynamic data is also identical, not if it's different.

    enhancement 
    opened by hrydgard 3
  • Simple example app for puffin-imgui?

    Simple example app for puffin-imgui?

    Background

    I have attempted to integrate puffin into an application, but I am struggling. The instructions in the README are a little sparse, so I had to guess a few parts:

    1. Added puffin and puffin-imgui as dependencies
    2. Before my main event loop, did this:
    let mut pui = puffin_imgui::ProfilerUi::default();
    puffin::set_scopes_on(true);
    
    1. In some interesting functions, added puffin::profile_function!(); in the first line and added puffin::profile_scope_data!("thing", "example"); in interesting loops etc
    2. Inside end of main loop I called pui.window(ui);

    However this ends up with a window appearing, but only ever contains "No profiling data"

    My suggestions

    1. It would be very useful to have a simple example of how to use this. Something only slightly more complex than https://github.com/imgui-rs/imgui-rs/blob/master/imgui-examples/examples/hello_world.rs showing how to correctly wire up everything

    2. Minor thing: The example code in README has : instead of ; at end of lines

    3. Having the little crates.io badge in the puffin-imgui README would be helpful (I put in puffin = "0.3" in Cargo.toml and I incorrectly assumed puffin-imgui was version-locked to this)

    Thanks!

    enhancement 
    opened by dbr 3
  • Change chrono dep to time

    Change chrono dep to time

    Reason:

    • Chrono depends on very old time 1.43 dep that has security issues.
    • By having chrono we require to have two version of time 1.43 and 0.3.9
    • Chrono Includes quite a few deps that can be ignored if one only needs to depend on egui puffin.
    • Time is lower level and we only use it for date parsing which can easily be done by time crate only
    opened by TimonPost 2
  • GlobalProfiler::lock().new_frame() can be very expensive due to compression

    GlobalProfiler::lock().new_frame() can be very expensive due to compression

    Here's a small cutout from a Superluminal profile of an app that uses puffin scopes quite extensively:

    image

    The pack() call here takes around 1ms.

    Looks like the pack() call from add_frame() gets very expensive. Partly because of zstd compression (can we turn down the compression level?) Also bincode serialization doesn't look cheap, maybe there's something faster we could switch to?

    Ideally, it would be nice to run pack() on a separate thread, not sure how easy that would be but sure would help "main thread" performance.

    enhancement 
    opened by hrydgard 2
  • puffin_viewer fails to start under NVIDIA Wayland.

    puffin_viewer fails to start under NVIDIA Wayland.

    Describe the bug puffin_viewer fails to start under NVIDIA Wayland.

    To Reproduce Steps to reproduce the behavior:

    1. Install puffin_viewer wirh cargo
    2. Try to run it under wayland plasma session.

    Device:

    • OS: Opensuse tumbleweed
    • Nvidia driver: nvidia-525-53
    • KDE Plasma 5

    Additional context Backtrace

    ❯ RUST_BACKTRACE=1 puffin_viewer --url 127.0.0.1:8585
    INFO [puffin_http::client] Connecting to 127.0.0.1:8585…
    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: NoAvailablePixelFormat', /home/mark/.cargo/registry/src/github.com-1ecc6299db9ec823/eframe-0.19.0/src/native/run.rs:45:14
    stack backtrace:
       0: rust_begin_unwind
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:584:5
       1: core::panicking::panic_fmt
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:142:14
       2: core::result::unwrap_failed
                 at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/result.rs:1785:5
       3: eframe::native::run::create_display
       4: eframe::native::run::glow_integration::GlowWinitApp::new
       5: std::thread::local::LocalKey<T>::with
       6: eframe::native::run::glow_integration::run_glow
       7: eframe::run_native
       8: puffin_viewer::main
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    

    Looks like it is an eframe bug https://github.com/emilk/egui/issues/2018

    bug 
    opened by markusgod 0
  • Merging child scopes gives skewed timeline view

    Merging child scopes gives skewed timeline view

    When one uses the default "Merge children with same ID" it merges a child scopes regardless of the time offset they are on, which gives a skewed view over how the execution worked.

    For example this:

    image

    Becomes:

    image

    Which can be confusing an unexpected because on the latter (which is default) it looks like there is single large block that is missing smaller profiler scopes on it.

    Expected behavior

    I did expect it to only merge child scopes that were next to each other on the time line, maybe not exactly (due to timing precision) but not fundamentally change the timing view.

    Let's discuss how to proceed with this or if we simply should disable "Merge children with same ID" by default and describe this gotcha, as believe we've internally run into this quite a few times causing confusion as the profiler with it is not showing the correct time perspective on things

    bug 
    opened by repi 0
  • Tracking: Make puffin integrate with GPU, async tasks, and thread profiling data.

    Tracking: Make puffin integrate with GPU, async tasks, and thread profiling data.

    Besides the main frame in the game loop, a game engine can have asynchronous tasks, threads, or GPU-related work during a frame. Currently, puffin categorizes all scopes under the same puffin frame, which is a problem when it comes to those three situations.

    • GPU work is executed in parallel to the frame.
    • Asynchronous tasks might take multiple frames to complete.
    • Threads are not dependent on frames at all.

    This results in a problem described in #59 where the frame time of GPU and CPU is added up when in reality it should not be and where the timing of CPU and GPU need to be aligned. In some of Embark's internal code bases, we have large spikes for threads that take a significant amount of time which in turn make the slowest frame summary window dysfunctional because the normal frames are relatively low compared to them.

    Potential suggested solutions:

    • Separate timelines of CPU/GPU with potentially relating both timelines together. Potentially do this by reporting CPU and GPU to different places. Then use two different profilers UIs to visualize them.
    • Simple effort to go around the frame time calculation is to only measure the main thread.
    enhancement 
    opened by TimonPost 2
  • Support easily associating .puffin files with Puffin Viewer

    Support easily associating .puffin files with Puffin Viewer

    Maybe even suggest such file association and set it up on startup of puffin viewer. So it is easy to share and open files in puffin viewer. Would require platform specifics to set up such a file association though.

    Should also default to that as an the extension when saving reports.

    enhancement 
    opened by repi 3
  • Request for Comments: puffin_http: use async local task

    Request for Comments: puffin_http: use async local task

    Checklist

    • [x] I have read the Contributor Guide
    • [x] I have read and agree to the Code of Conduct
    • [x] I have added a description of my changes and why I'd like them included in the section below

    Description of Changes

    Use async Rust to manage puffin server (puffin_http) tasks. An regroup it in one dedicated thread. I think it's proper

    Changes are not totally clean, but before improve it, I like to know if your are interested by this approach.

    I have tested this change with my dedicated app : https://github.com/gwen-lg/puffin-test-app, but I think it's need test with real application/running game.

    Also I have identified this think to do before merge it :

    • tried to have task name management
    • clean commented code
    • remove comment of crossbeam_channel
    • finish rewrite of architecture section of puffin_http/readme.md

    Related Issues

    This change are not related to a github issue. But this change permit to implement

    A captures of result : image image

    opened by gwen-lg 4
  • puffin_http clients can't get firsts frame if they are short

    puffin_http clients can't get firsts frame if they are short

    Describe the bug When firsts frames are short, puffin_http client (example: puffin_viewer) can't get firsts frames.

    To Reproduce Steps to reproduce the behavior:

    1. start puffin_viewer
    2. start an app with puffin_http server with short frames (and numbered frames)
    3. look-at frame in viewer, there isn't the first frame(s)

    Expected behavior I expect to be able to get first frame in puffin_viewer

    Device:

    • OS: Fedora
    • Version 36
    bug 
    opened by gwen-lg 1
Releases(0.14.0)
Owner
Embark
The future belongs to the curious
Embark
Malloc frequency profiler

Malloc frequency profiler This malloc frequency profiler helps detect program hotspots that perform a large number of memory allocations.

Leonid Ryzhyk 7 Jan 7, 2022
A tracing profiler for the Sega MegaDrive/Genesis

md-profiler, a tracing profiler for the Sega MegaDrive/Genesis This program, meant to be used with this fork of BlastEm, helps you finding bottlenecks

null 15 Nov 3, 2022
Simple timings profiler

profl Simple timings profiler Example fn main() -> std::io::Result<()> { profl::init("timings.data"); let mut total = 0; for i in 0..1000

Broxus 1 Dec 9, 2021
Py-spy - Sampling profiler for Python programs

py-spy: Sampling profiler for Python programs py-spy is a sampling profiler for Python programs. It lets you visualize what your Python program is spe

Ben Frederickson 9.5k Jan 8, 2023
The axiom profiler for exploring and visualizing SMT solver quantifier instantiations (made via E-matching).

Axiom Profiler A tool for visualising, analysing and understanding quantifier instantiations made via E-matching in a run of an SMT solver (at present

Viper Project 18 Oct 18, 2022
A memory profiler for Linux.

Bytehound - a memory profiler for Linux Features Can be used to analyze memory leaks, see where exactly the memory is being consumed, identify tempora

Koute 3.3k Dec 25, 2022
Sampling profiler and tracer for Ruby (CRuby) which runs in BPF

rbperf rbperf is a low-overhead sampling profiler and tracer for Ruby (CRuby) which runs in BPF Build To build rbperf you would need a Linux machine w

Javier Honduvilla Coto 75 Dec 19, 2022
A little CLI written in rust to improve your dirty commits into conventional ones.

Simple commits A little CLI written in rust to improve your dirty commits into conventional ones. ?? Demo (coming soon) ✨ Features Fully conventional

romandev 5 Mar 16, 2024
hado-rshado — A little macro for writing haskell-like do expressions without too much ceremony

hado Monadic haskell-like expressions brought to rust via the hado! macro What? A little macro for writing haskell-like do expressions without too muc

Lucas David Traverso 44 Jul 31, 2022
Watches changes in a rust project, runs test and shows friendly notification

Cargo testify Automatically runs tests on your Rust project and notifies about the result. Install Install prerequisites (for Debian/Ubuntu): apt-get

Sergey Potapov 77 May 16, 2022
A strict, yet friendly mocking library for Rust 2018

Mockiato A strict, yet friendly mocking library for Rust 2018 ⚠️ Disclaimer for working with stable rust Mockiato relies on the unstable proc_macro_di

Mockiato 228 Dec 30, 2022
Rust Util Collection, a simple and friendly error-chain

RUC Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition. The painful experience of using error-chain gave b

漢 8 Dec 8, 2022
Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition.

RUC Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition. The painful experience of using error-chain gave b

漢 6 Mar 27, 2022
Minimal, flexible & user-friendly X and Wayland tiling window manager with rust

SSWM Minimal, flexible & user-friendly X and Wayland tiling window manager but with rust. Feel free to open issues and make pull requests. [Overview]

Linus Walker 19 Aug 28, 2023
Byte is a blazingly fast🚀 Discord Bot with a user-friendly design using twilight written in rust🦀.

Byte Byte is a blazingly fast?? Discord Bot with a user-friendly design using twilight written in rust??. How To Run There is a public version of the

TakoTheDev 3 Nov 15, 2023
dbt Cloud™️ infrastructure-as-code that is friendly to analysts

dbterra dbt Cloud ™️ infrastructure-as-code that is friendly to analysts, bizops, etc Motivation While there are Terraform ™️ plugins that can be used

Instawork 6 May 2, 2023
k-mer counter in Rust using the rust-bio and rayon crates

krust is a k-mer counter written in Rust and run from the command line that will output canonical k-mers and their frequency across the records in a f

null 14 Jan 7, 2023
Experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code

Diplomat is an experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code. With Diplomat, you can simply define Rust APIs to be exposed over FFI and get high-level C, C++, and JavaScript bindings automatically!

null 255 Dec 30, 2022
Aws-sdk-rust - AWS SDK for the Rust Programming Language

The AWS SDK for Rust This repo contains the new AWS SDK for Rust (the SDK) and its public roadmap. Please Note: The SDK is currently released as a dev

Amazon Web Services - Labs 2k Jan 3, 2023