Make the Tracy layer optional, even when compiled with feature = "tracing-tracy"#24109
Open
nfagerlund wants to merge 3 commits intobevyengine:mainfrom
Open
Make the Tracy layer optional, even when compiled with feature = "tracing-tracy"#24109nfagerlund wants to merge 3 commits intobevyengine:mainfrom
feature = "tracing-tracy"#24109nfagerlund wants to merge 3 commits intobevyengine:mainfrom
Conversation
Tracy integration is currently controlled at compile time with the `tracing-tracy` feature, so you don't have to build it if you don't use it. Rad. But once it's compiled in, you have to _always_ connect the profiler or collector when your app is running, or else the Tracy client'll blow out your RAM with its tracing event buffer. This is annoying enough to have been worth a `warn`-level log in the LogPlugin build method. If it's annoying enough to warn, perhaps it's annoying enough for an opt-out switch. I'd love to have the option to disable the client by default, enable the profiler whenever I want to check something, and NOT have to recompile bevy_log and everything downstream of it in order to switch modes. Luckily, it turns out `Option<impl Layer>` implements `Layer`, so this is easy.
This function already returns an Option and has two paths that might return None (macos for some reason, and the .ok() on a fallible constructor), so it should use ? instead of crashing the app.
amtep
approved these changes
May 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Objective
Tracy integration is currently controlled at compile time with the
tracing-tracyfeature, so you don't have to build it if you don't use it. Rad. But once it's compiled in, you have to always connect the profiler or collector when your app is running, or else the Tracy client'll blow out your RAM with its tracing event buffer. This is annoying enough to have been worth awarn-level log in the LogPlugin build method.If it's annoying enough to warn, perhaps it's annoying enough for an opt-out switch. I'd love to have the option to disable the client by default, enable the profiler whenever I want to check something, and NOT have to recompile bevy_log and everything downstream of it in order to switch modes.
Solution
Luckily, it turns out
Option<impl Layer>implementsLayer, so this is easy.I left the default as "on", to match existing behavior.
Testing
Yeah — I originally made this patch to a fork of 0.18.1, so I could use it in the game I'm working on, and I tested that. I confirmed that it doesn't send the regular profiling data to Tracy if I don't pass
--profileto the app (I used that cli flag to set theenable_tracyfield). I also confirmed that memory usage is under much better control! It quickly grows to multiple GB if you enable Tracy and don't start the profiler, but if you refrain from enabling it, it stays down in the low hundreds of megs. (It grows a tiny bit over time, but it seems likely that's normal ECS allocation stuff happening.)However, it does still seem to wake up the Tracy profiler (if it's listening) and get it to start logging global CPU, and I'm not sure what's up with that! Other apps that don't have a Tracy client compiled in don't do that. But I can't find where in the engine or dependencies it would actually initialize a Tracy client if we never construct a subscriber layer. 🤔
The GPU context thingie is different between main and 0.18.1 -- the Option return type was added sometime since then. So I haven't tested the current approach.
However, before I fixed that (slightly differently) in my 0.18 fork, it actually still didn't explode... which means the
Client::running().unwrap()must have found a running client, bringing us back to the question above of who the heck is initializing that. Oh -- or else it means that GPU diagnostics path never ran; it looked to me like it should always included in the default plugins when the tracing-tracy feature is live, but I could easily have misinterpreted it.Just gotta rig up a way to toggle that boolean field at runtime. I went with
let enable_tracy = std::env::args().any(|arg| &arg == "--profile");.I've only tested on mac so far, gonna test on my windows potato later. (The potato was the motivating use case.)works good on the windows potato.