Skip to content

Conversation

mockersf
Copy link
Member

@mockersf mockersf commented Jun 2, 2025

rendered: https://github.com/bevyengine/rfcs/blob/component-guided-optimisation/rfcs/84-component-guided-optimisation.md

help improve release builds of Bevy games:

  • less CPU and RAM usage
  • lower scheduler contention
  • shorter compilation time
  • smaller binaries
  • what else?

@Atlas16A
Copy link

Atlas16A commented Jun 2, 2025

My first immediate thought is, how does this mesh with bsn? Components might be used by bsn but the rust side only has the component declaration.
This also effects the editor workflow as youd make a component, not use it in code, go to put it on stuff inside the editor only for the editor to have zero clue what it is cause it got optimized out.

@mockersf
Copy link
Member Author

mockersf commented Jun 3, 2025

My first immediate thought is, how does this mesh with bsn? Components might be used by bsn but the rust side only has the component declaration.

It should be possible to identify those components used at runtime with dynamic analysis, and it would be very easy to do it as static analysis: it's pretty much just reading the file! So no issues there, but good to mention

This also effects the editor workflow as youd make a component, not use it in code, go to put it on stuff inside the editor only for the editor to have zero clue what it is cause it got optimized out.

This doesn't affect the editor as it's targeted at final deliverable, so not while you're using the editor

@komadori
Copy link

komadori commented Jun 3, 2025

I love it! I've long thought that Bevy needed a much more fine-grained feature set and worried that increasing capabilities for dynamism and introspection in the engine would impair the ability of the compiler to remove dead code. As you point out, the registration of systems is already a big anchor for lots of functionality.

I expect that it might ordinarily be difficult to get a lot more finer-grained features implemented and merged owing to debate over the merits and precise boundaries of each such proposal, if such things are seen as having an overhead. That is the real genius of this RFC, that it envisages a systemic way of componentising Bevy using... components. By establishing a standard practice as proposed, the impact on developers working on or using the full engine should be minimal while ensuring that fine-grained features are pervasive.

I will only note that Component level granularity doesn't solve every problem as there are other confluence points where logically separate features are combined (e.g. the GLTF loader, StandardMaterial, etc). However, I think this would be a fantastic place to start.

@BD103
Copy link
Member

BD103 commented Jun 3, 2025

Although it may be overkill, you can accomplish the static analysis by creating a rustc driver, just like the Bevy Linter does. rustc drivers give you full access to type information, attributes, the AST / HIR, and some amount of compile-time evaluation, which is super useful! As a downside, however, rustc drivers require constant maintenance to to use a modern nightly toolchain and "stay ahead" of stable Rust, not to mention there's little support from the compiler devs (required unstable features, no internal changelog, no migration guide yet).

A rustc driver will definitely give you the power you need for static analysis, but it's high maintenance and very domain-specific. I'd recommend looking at alternatives first before going down this route! :)

@jdm
Copy link

jdm commented Jun 6, 2025

charon might be an alternative that would enable static analysis without requiring constant maintenance.

@cart
Copy link
Member

cart commented Oct 1, 2025

Part 1: Conditional System Compilation

This feels laborious, boilerplatey, and error prone (as it is not driving behaviors but rather attesting that these behaviors are present).

These features would also be "viral" in nature. Ex: every internal crate that uses Transform now needs a component_Transform feature, and the relevant systems using it would need to be annotated with the component_Transform CGO boilerplate.

The proposal also doesn't illustrate the effects this would have on import ergonomics, which would likely be substantial. I suspect regressions would be common, as every consumer of a component that forgets that it is a CGO component (or just missing an import) will result in a compilation failure. This would not be covered by a global "no-default-features" build as non-default crates would be skipped. This also wouldn't even be covered by crate-specific builds, as we can't possibly check every feature combination.

Current Bevy applications include significant amounts of unused code that cannot be eliminated by traditional compiler optimizations. This creates several problems

It would be helpful to quantify the wins here, given how high the cost is. I personally think this would make Bevy code tanglibly less enjoyable to read and write, so the wins would need to be huge to justify it.

Part 4: Better System Conditional Compilation
A new const boolean on the IntoScheduleConfigs trait would allow disabling adding a system to a schedule at compile time.

IntoScheduleConfig currently uses a blanket implementation for all Systems, and system functions will implement System no matter what. Pretty sure the expanded code in your proposal would result in "conflicting implementation" errors. I'm reasonably certain we can't change ENABLED on a per-system basis without generating a new type for the system and using that instead of the system function type name.

This doesn't affect the editor as it's targeted at final deliverable, so not while you're using the editor

Given that activating this fundamentally changes the behaviors of an app, it feels like a potential liability to do all of your development with everything enabled, then as a last release step flip this switch and deploy. Even if it was just scoped to a difference in performance, thats still a potential liability (albeit one of a much smaller scope). But the systems that are no longer running could have side effects outside of the scope of the conditionally compiled components they touch. I think in general we should recommend doing CGO as early as possible, if we support it.

As a whole, I see the value here and agree with the motivation to give people more tools to slim things down. However as presented the amount of boilerplate and "manual attestation" required gives me pause, as does the challenge in ensuring every possible permutation compiles.

I would be much more amenable to solutions that are fully automated and "boilerplate free". For example: writing a tool that takes an input bevy crate and produces an output bevy crate, with the relevant bits filtered out. Then motivated individuals could clone the bevy repo, run the tool on it, and patch that local pruned version of bevy in to their final apps. It could look something like:

  1. Run the user's app and dump the current schedule, including the components used by each system
  2. Analyze the user's app code (systems, commands, check as much code as possible, ideally all of it) and diff the components used there with all of the other components.
  3. Return the list of components present in the schedule but not used by the users' app. Perhaps manually filter this down for things like "default Window spawned on the users' behalf".
  4. Present it to the user as "potentially unused components". Making this "bulletproof" is a hard (and perhaps impossible task), but this is just a set of recommendations.
  5. Allow the user to select from that list the components they would like to compile out.
  6. Run the tool which identifies these components in code and filters them out at compile time (including systems), generating a new workspace with those components / systems removed.
  7. Generate the Cargo.toml "patch" boilerplate, which the developer can add to their app's Cargo.toml.

(6) has the potential to not be bulletproof (ex: a reference nested somewhere that the tool doesn't know how to identify or remove, broken references). This could be mitigated by generating empty stubs for the removed systems and components (or leaving the components themselves fully in tact). We could always be conservative and just stub out systems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants