Profiling with Tracy
cargo run --release --features trace_tracy, with the Tracy UI
(https://github.com/wolfpld/tracy) already open and “Connect” clicked.
How it hangs together
trace_tracy (Cargo.toml) just forwards to bevy/trace_tracy, which already wraps every ECS system
call in its own info_span!("system", name = ..) — most of what shows up
in Tracy needs no manual instrumentation at all. Two things this crate adds
on top:
main.rs’sLogPluginis feature-gated: the everyday filter ("warn,bevy_render::camera=error") sets the default level belowinfo, which silently drops every span (Bevy’s own and ours) before any backend — Tracy included — ever sees them (seeLogPlugin::build_filter_layer, which foldsfilter’s own bare directives overlevel). Atrace_tracybuild swaps in a filter with no bare-level directive belowinfo, so the configuredLevel::INFOdefault actually holds.- Manual spans cover the paths automatic per-system instrumentation can’t
reach — anything that isn’t itself a system call. Two categories so far:
- Off the ECS schedule entirely: the cpal capture callback
(
audio_input::push_chunks) runs on its own real-time thread; the only customAssetLoader(song::loader::SongChartLoader::load) runs as a future on the AssetServer’s IO task pool. Both get a manual span for the same reason — Bevy’s per-system spans only wrap systems the schedule itself calls, so anything running elsewhere (another thread, another executor) is otherwise invisible no matter how expensive it is. A span held across an.awaitneedstracing::Instrument(viabevy::log::tracing::Instrument) rather than a plain.entered()guard — anEnteredSpanisn’tSend, which the loader’s returned future must be;SongChartLoader::loadis a thin wrapper that instruments aload_innerfor exactly this reason. - A hot inner loop worth breaking out of its system’s own total time:
pipeline::process_audio’s per-chunk work;pitch_detect::analyze’s FFT transform and per-algorithm dispatch;build_nmf_dict(the priciest one-off, rebuilt only when the NMF dictionary goes stale);waveform::analyze_ogg_waveform/analyze_wav_waveform(a whole-file decode — also called from the off-schedule asset loader above, so it carries both reasons at once). Add spans the same way for any other code that runs off the main schedule (more asset loaders, decode threads, the asset watcher — thoughassets_management::watch’s debouncer thread runs onlynotify-debouncer-full’s own code, nothing of ours, so there’s nothing to instrument there) or burns real time inside a single system call.
- Off the ECS schedule entirely: the cpal capture callback
(