#Hotpatching Rust code π₯
1 messages Β· Page 4 of 1
Has anyone tested it on a larger project? Does it slow down a lot once you have a more complex project?
0.4 s on a toy example, 1.6 s on Foxtrot
Would interested to see @idle stone performance on hot patching Foxtrot
Whether you get 4x your time on the template or + 1.2 s flat
i'll test this tomorrow
I believe there's a way to get the incremental times down even lower, but that requires implementing workspace support. I'm going to put out a new alpha and then probably leave things alone for a bit
I think it's quite a good state now for an alpha π
Can I use hot patching while working on the engine itself?
No workspace support will make that hard
Ah rip
That's fine actually
It probably wouldn't help with writing CPU side code in the engine for me much anyways, and I already have hot reloading for shaderd
But being able to move objects around easily when writing examples would be great
Then that will work, yes π
And toggle lighting stuff without having to setup a system to spawn/despawn on key press :p
Francois' PR should enable that by just turning on a feature
yeah hotpatched code is much better for iterating when debugging, agreed π
okay so, i am back @mellow flint do u think we should show the .with_hot_patch as a secondary example within the readme itself, alongside the #[hot] macro? or no?
also is mold supposed to work now? π
and dynamic linking?
huh dynamic linking made my recompiles go from 500ms to 3 seconds lmao
Any linker setup works now, and yes, dynamic_linking should work
was any headway made on non-macro hotpatching
or did we all give up π«£
or wait..the App extension trait works
also francoi's pr doesn't require a macro
no it is!
Pit it in the advanced section
Meh, use LLD for now
oh!
Macroless is trivial upstream
Actually, I just had an idea for third party macroless
Take the schedules, wrap all systems in a hotpatched closure, rebuild schedules, replace old ones
A bit like @raven valley did, but for every system
can't do it
Make sure the app is added last and we can do that even before Startup
schedules aren't powerful enough yet
Ah heck
i think π€
i mean hmm
you can try it
i don't think schedules are powerful enough to do it
go for it
Hmm
New pr to update the readme jan
My implementation which Iβm hoping to PR the core changes which enables it to Bevy works macro less with almost no changes to users apps 
Once I push the PR Iβll put up a repo with a plugin that relies on those changes that anyone can use
There are some caveats with the approach but Iβll document them/make sure they are resolved by then
It doesnβt rely on subsecond so itβs a little more stable, at least from my experience
But I donβt have a lot of others testing with me yet 
So we will see if that lasts
omg this is like exactly what I couldn't figure out. got so frustrated π..didn't even realize that build_system calls build_any_system internally on SystemState ugh
hell yeah franΓ§ois
Yeah good design @lone token π
just recorded a 30 minute video of me using bevy hot-reloading to make flappy bird clone from scratch and i TESTED the video recording before but apparently long videos get laggy on my setup so the video is intolerably laggy
OKAY the issue is that minimized obs ( or possibly not on screen obs at all ) gets all choppy
wth
wait no way
I literally just did this not joking https://github.com/dsgallups/bevy-workshop except not recording
Code looks clean! Things like on_space can be rephrased as a run condition btw:
jump.run_if(input_just_pressed(KeyCode::Space))
That way, the function name becomes more meaningful π
But also, I realize this is for beginners, so if you want to skip run conditions, that makes sense
good catch! I also used a closure in the score plugin...but, I imagine that's also probably best left in the workshop discussion, not in the final game
lmao
i just recorded a new video
gonna edit it up and upload it
opened https://github.com/bevyengine/bevy/pull/19354 (state scoped entities enabled by default) and https://github.com/bevyengine/bevy/pull/19363 (same state transitions) to make it nicer to work with hot patched code and states
You gotta link it here @raven valley ! (Sick showcase of hotpatching)
#showcase message
Here's your B-roll, @worldly ether π
@worldly ether if you want the original footage i can hand it over too you ( non-sped-up )
wait wait π€ state scoped entities by default? does this mean spawn will auto-spawn a state scoped entity? if so we would be able to use a custom state that we enable at the start of StartupRerunHotpatch and then leave after StartupRerunHotpatch re-runs in order to auto-despawn all entities spawned in StartupRerunHotPatch? ( π€ but this would also despawn all entities spawned in the update schedule which we don't want
)
i think if we want a clean hot-reload integration with the .with_hot_patch thing as part of native bevy we would want to make some tweak tweaks to bevy to let us track which schedule an entity was spawned in, and be able to use that to clear certain entities?
( specifically for non-macro StartupRerunHotPatch schedule stuff, not for generally adding and removing systems at runtime )
ugh i'm so happy my wishlist for bevy literally was
- async systems
- natively supported hot-reloading
- bsn
- bevy editor
and 1 out of those 4 is already nearly across the finish line and is in a very usable state already
@quick bloom you didn't ping me when you finished your pr for the spawn commands! I just reviewed it, hopefully it gets in the merge train!!!!
nop, it just mean you won't have to call manually the app.enable_state_scoped_entities()
ahhh
also I'm pretty sure we won't have something like StartupRerunHotpatch in Bevy, at least I'm very against it for now
I mean it can be a third party crate thing but i think it makes sense as first party support if we make the very smooth development process showcased in my video a golden path ( which, given how terribly productive it is i would hope so! )
we'll make slower progress than a third party crate in Bevy, and the third party crate is a very good ground for experimentation. but we'll probably do rerunning startup systems differently
okie
My thoughts behind it are this:
if you make rerunning all startup systems the default ( within the closure )
then you break certain assumptions some plugins may have. it's useful to be able to create a plugin that has some startup systems that really do only run once, but that you're also editing and adding new systems to that are also startup rerun, and update and post update and such
there is a good question too about if new Startup systems should be run the first time upon reload but then not again π€
( as opposed to StartupRerunHotPatch which re-run every time )
I kinda feel right now we put way too much stuff in hot patch mechanism, when the proper interface would be a button "rerun this system", or a command to trigger it in the cli, or an API that would expose it to your code editor, ...
which Bevy already mostly support
i actually really like being able to control things through code only, but i understand the urge and it can make sense, especially once we get an editor on our hands. But personally i would always want the ability to just, adjust things in my code editor and have it have all the features of a CLI or bevy editor
( for hot reloading )
the nice thing about code is everything u see is what you get, with cli's and such i feel like one has less, control, and ability to view what's going on
it's also possible through code, it's "just" running a system which you can do in any system
yeah, that's how StartupRerunHotpatch works, it's just a new schedule that collects all the systems and runs them in another system
the update schedule in the rerun is similar ( this is actually a flaw with it currently )
it actually is mem swapped with a UpdateHotPatch schedule which we run within the update schedule
( this means you can't schedule things outside of the update within the update )
but with more powerful schedules hopefully we will be able to fix that and make it work just like a normal Update schedule
when playing with hot patch, what I'm missing currently is a way to do "run this system once after hotpatching it", which is very doable and I'll probably do as a followup in Bevy if no-one beats me to it
I believe that the macro-method does have that as an option
(playing with Bevy builtin, not bevy_simple_subsecond_system)
ahhhh
taking a step back just to clear up what i really want personally: the path of "write normal bevy plugins, and just put them in this special spot and you can write your whole game in hot-reload mode" is something i really wanna see make its way to native bevy, i want everyone to have the glory and power of rust as a scripting language level of iteration speeds.
same, but without the "put them in this special spot"
ahhaha you can't get away without putting them in this special spot, as i learned the hard way. Or at least i couldn't figure it out 
how can you add new systems without putting them in a non-standard spot?
I don't know yet, but it will happen π
i watch with great anticipation
just, more slowly than in bevy_simple_subsecond_system π
the problem is you would have to reload the entire main function, which doesn't work because app runners and winit and such. Most plugins can't handle being re-built more than once, even if u don't re-run the bevy app
not really π₯·
you hot reload building the schedule, but you don't run it, you build a graph of the original one and the new one, you isolate the differences and you focus on those
yes!
but doing so would require some pretty drastic surgery to bevy
because the original schedule gets built as part of the app build process, which also contains things that can't re-run
heh it's kinda work that is in the path of system as entities and plugins v2
yeah some massive changes to plugins in plugins v2 would make this possible, depending on how that work went 
I would far prefer that, though it would still require a macro, given how subsecond works, the macro would just have to be around the App::new() instead, ( that or put it within a hot-reload closure or such ). You have to be able to rerun the code somehow
it will happen, just probably not for the 0.17 π€·
otherwise you have no entry point to the original app build process
until then the third party crate is awesome
yeeee
Look at my implementation 
Okay gimme a couple of hours and Iβll put everything together today
What are your thoughts on "rerun this setup"? The issue with plain rerun is that any spawned entities will be spawned a second time, resulting in e.g. two GUIs.
Our current workarounds are
- Add a marker component to your entities and despawn them at the beginning.
- Issue: this goes beyond "just activate a feature and you get hot-patching"
- Use the custom schedule stuff
- Issues are apparent
Note that states would imo not be the correct tool for this, as when I need to edit my in-game HUD's layout, I don't want to also restart the level. These are orthogonal.
The "real" answer is of course to use hot-reloaded BSN for that or a bespoke Bevy UI editor, but that is not a reality yet.
- Issues are apparent
Alice mentioned maybe adding some kind of tracking to entities to know which systems spawned them. That way, you could despawn all entities that were spawned in the system that will be rerun.
Not sure how feasible that is though, I don't know the internals good enough to tell whether that is a good call or not.
actually the custom schedule stuff is specifically so i rerun stuff multiply times, i could use non-custom schedules but that limits the flexibility of building general plugins ( potentially ) idk if i mull it over enough we could go with just normal Startup schedules that re-run on hotpatch 
what we do need rn is the macro above it
That would be cool π
Yeah I also don't see a way out of that
well, one way out of it would be to track what schedule entities are spawned in
would require changes to bevy internals
adding a feature to track systems that spawned a given entity is my current favorite solution
it's useful to hot patching and the editor
Oh really?
That would be really cool then π Everything could potentially "just work" β’οΈ
not the editor people are working on, but the one that I want that is made to inspect / customize a running ECS
Yeah I want that more than the other editor too π
Pretty happy with 3rd party level creation tools so far
@raven valley another thing regarding your readme PR:
I'd like to keep the readme very clean and unintimidating, considering that new-ish users might see it now that it is linked by the jam, and highlighted by Chris, and linked in bevy_new_2d.
So as a compromise, we could leave the section in an "alternative workflow" header, but put it in <details>. Does that work?
Just need to be very upfront about what does and does not work
Yeah that's cool
nice π
Sorry! Did the PR the next day, which is longer than the 10 minutes my memory lasts
Also thinking about renaming the crate to bevy_hotpatching_prototype.
- It would better reflect the intention of the crate as a playground
- It reflects the fact that in 0.17, hotpatching will be simpler upstream
- bikeshed: I still prefer
hot_patchingfor parity withhot_reload, but since @lone token' PR useshotpatching, I believe we should use the same spelling
Also want some thoughts from @karmic current and @idle stone on this
Can't you keep track of what entities were spawned by what systems when hot patching is on?
Don't know how I would do that without changing Bevy internals right now
Oh also @languid sable of course
Yeah this is what I meant
definitely hot patching not hot reloading
Yeah that is Alice's idea, if I understand her correctly π
No strong feelings on seperate words
question is "hot patching" vs "hotpatching" π
and mostly because hot_patching is ... displeasing to my eyes, no idea why
I personally also find hotpatching way more pleasant to read than hot_patching
yeah same
It just bothers me that we spell these very similar things different
I can see users being confused when typing the features out by hand
though to be fair, hot reloading is actually called file_watcher 
so there's that
we can rename file_watcher to hotreloading
and then we'll have a feature caliente that will enable both, just to be sure it's not consistent
ship it
Clearly we need to rename it to "hotloading", then it can match with "hotpatching"
bahahha I just found 100 rustc ICE backtraces in my project from when I was trying to get hotpatching working earlier (I think they're due to turning on incremental maybe) 
very relatable
incremental compilation + Bevy tends to produce those on my machine regularly
need to have them in my gitignore π
Rust should pay Bevy for how much it works as a stress test for rustc
You're a pro ice skater I see!
Has anyone gotten "The code execution cannot proceed because clfs.sys was not found. Reinstalling the program may fix this problem" when trying to use hotpatching on windows? I cannot get it to work -.-
I am running in x64 Native tools prompt, because everything else gives linker errors.
my only comment is that we don't define "hot patch" anywhere and its not a common enough word to avoid defining it. people searching for "hot patch" will not find anything related to what this crate does at all.
currently in the broader usage "live reload" implies some kind of application reload and "hot reload" implies injecting changed bits and retaining state, so what is "hot patching"?
Itβs how dioxus calls the technology we use
I understand that, but "someone called what we do that" is not an explanation for new users
and is definitely not a recognizable branding
Ah sorry, I thought you were asking π
I'm saying if we use that in the crate name we are resposible for telling people what it is and how its different than these other common terms
Sure, that makes sense!
there's a reason i published my videos with the term hot reloading and not hot patching 
more waow factor
there doesn't seem to be an explanation in the 0.7 dioxus release either, fwiw
do you need a short explanation now, or are you just calling to add one somewhere?
I'm calling to add one somewhere in response to being asked about using the word in the crate name
we'll also have to do that on Bevy side too, and explain the different tricks we have between hot reloading assets, hot reloading shaders, and "hot patching" code
I'm curious as to why this list doesn't continue with "hot reloading code" tbh
from the perspective of a new user who will be using the technologies, why is there a difference
heh let's rename the second "hot recompiling" shaders π
I think it makes sense to call it differently since it does something fundamentally different under the hood, but I also see that from a user perspective, it all amounts to "I change something at runtime and the program updates accordingly"
its all the hot features
I'm personally not married to any terminology and will use whatever lands in Bevy upstream
bevy 0.17 is hothothot!
||I'm still a fan of giving bird names to release, so it will be Bevy 0.17 phoenix||
If we did call it "hot reloading code" we should rethink how the feature flags are called. The first two hot reloads are file_watcher atm
is source code not files? π
a single --hot flag would be cool though
We can have them all under one flag, but since their technical limitations are orthogonal, it may make sense to keep them separated
Yeah absolutely
I kind of assumed the cli was going to be necessary and the flag would need to be there, but I actually don't know that for sure
bevy run --hot // burn cpu pls
file watching and hot patching probably have different platform support
Got you fam loop {}
I can picture hot_reload_assets and hot_reload_code, both activated by a simple hot
could use a separate state type for entering levels vs spawning HUD and only reload the latter, but at that point you're structuring your code to match the hotpatching which is awkward (although that might actually be a better design π€)
i probably wouldn't rename the crate until after the jam, since it's already mentioned with its current name on the jam page
okay
i'm gonna look at adding the resource/event stuff so you can add new resources/events at compile time, and after that i'm gonna look at state stuff to see if i can support custom states
wait why does remove_resource_by_id not return an OwnedPtr
instead it returns Option<()> noooo


yesss but 3 months away
i'll go make the pr tho
i wanted to be able to hot-reload add events and resources for the jam π q
Actually my arm is killing me so im gonna pause dev, but i will get that pr done probably tmrw
File an issue / PR please!
@karmic current @lone token I guess the current feature flag names also have their problems π
Didnβt even know we had embedded_watcher
I think that has a good chance of fitting into 16.1 if you PR it
Breaking change π¦
it makes me sadge, gotta wait till 17 to be able to do everything in hot reload mode
( well i still haven't done states idk if i can do states but i probably can? )
well, hmm, actually
okay, i could just make it so u can never remove resources
lol
but u can still add them
nope wait nope
i need to remove the resource from ReloadWorld in order to stick it in the standard World
ugh frustratinggggg
not mad i just feel antsy cause i thought i was gonna be able to do this......

Understandable
Oh boi
What happens when the hot patched app does add_observer or register_type, btw? @raven valley
good questions! Rn nothing, register_type is something i can make work pretty easily, idk how add_observer works in detail 
Asking because I'm considering doing .with_hot_patch(foo::plugin) in Foxtrot for all plugins
Oh what
you just add your plugins inside the with_hotpatch
So I just do it once in the top level?
there is only one with_hot_patch, it takes in a closure to a &mut App, you just do like in my video app.add_plugins((BirdPlugins, PipePlugin))
yep, you can just move over where you add all your plugins into that closure ( as long as those plugins don't register events or add resources
)
( or do states or observers or register types
)
that's why i chose to have the Startup vs StartupReRunHotpatch distinction
That's inside the closure?

Neat π
Didnβt realize that, that makes the API massively more attractive
Could even accept a set of plugins and create the closure ourselves around app.add_plugins
6 seconds Β· Clipped by MalekiRe Β· Original video "Hot-reloading Rust Game Dev: Coding Flappy Bird in Bevy From Scratch" by MalekiRe
Clipped the section where i add both plugins in the app so u can see
right???
That would enable app.add_hot_plugins((A, B, C))
Not a fan π
The problem with doing that is that it won't update, since you'll never rerun main
The trick works because you're actually rerunning the closure you passed in
Canβt we just create the closure internally?
then when you change the add_hot_plugins to include D how are you getting that new state?
where's the entry point?
Yeah that wouldnβt work, right
No, because then when you change the values it wouldn't change the code in the internal closure, so it won't update with the new values
OH WAIT Brain blast,
brain blastttt
not sure if it would work though
no it wouldn't work
like 80% sure
But if you did app.add_hot_plugins(GamePlugin) you wouldnβt need to add a new plugin at runtime
what if we had (A, B, C) convert into a system, but that doesn't work because ur still changing stuff outside the state change
confused
If you rerun GamePlugin::build when that hotpatches, then that should work
So you can in theory add stuff to all plugins by default, just not main, which is kinda annoying
all fn are Fn, because they cannot hold state
When using the lib.rs + main.rs workflow (which subsecond does not support yet lol) you usually have a single biiig top level plugin for your game
Fn implies FnMut implies FnOnce
okay! then yeah it should work
It's the opposite of the normal way because you're talking about the parameters
Build your own closure that calls Plugin::build internally if that doesnβt work
That one can be an FnMut
no it works
Noice
Is there a way to ban adding anything except plugins in the top-level App
We could make an app wrapper that we require for the .add_hot_plugins that only exposes add_plugins and run
I guess even adding a new plugin would be confusing, so there's no getting around it
We just need to teach people that "only plugins hotpatch" I think
i do think i like the api of .add_hot_plugin more than .with_hot_patch but the issue is you have to have a game plugin which basically is just the with_hot_patch closure lol
That would mean opting into the workflow would require changing a single line.
If the resources and observers etc. are respected, I'd make that the new main recommendation for the crate
But this is genius, this should let bevy hotpatch everything eby default (as long as you're not modifying stuff in main), which is huge
well, okay this is the issue
bevy_new_2d and by extension the Bevy CLI alpha push you to do that already, so I think that's fine
lots of plugins do stuff that they only expect to happen once during their build phase
such as winit, and networking plugins, and such
But the difference is it doesn't actually change the bevy API, this is what we've been waiting for this whole time I think
You wouldn't hot patch DefaultPlugins anyway, they'd be added in main
Aaah true
yeah you should already be doing this for a few other reasons too
but if we did a .add_plugins override
if we modified bevy to make it hot-patchable
I think it's okay because those files will never change, so they'll never be hotpatched
Do we also put DefaultPlugins in GamePlugin? I forgot
OH wait no, .add_plugins isn't FnMut because it takes in a &mut to self, and then we don't get to keep the plugin after we run build once right?
this is true unless you are working on bevy itself in which case it's not true, but yeah
BUT still
no
its not true
main is just App::new().add_plugins(my_game::plugin).run() so yea
Why would you rerun the build of a plugin that didn't change?
you rerun the builds of all plugins added in .add_plugins
you don't get to know which ones changed
dioxus doesn't give you that info π
(yet)

BUT even then, it would be very complicated to deal with a partially built schedule, vs just rebuilding the whole schedule every time in the Plugins V2 francois was talking about
If people want to do stuff in main we could add a #[bevy::main] that desugars to
fn main() -> AppExit {
App::new().add_plugins(*user_main*).run()
}
if we can get plugins v2 where we have a seperation between systems added to a schedule, and resources inserted into the app ( and other misc things ) then we can pull it off
wouldn't *user_main* create its own App if it's main(){}-like?
i mean, if people wanna do stuff in main they could just do this
fn main() {
App::new()
.add_plugins(|app: &mut App| {
app.add_plugins(DefaultPlugins);
})
.run();
}
it's very unlikely you'll get that in Bevy, and it starts to become a little too foreign for an external plugin to my taste π
but we would really really need this
Yeahh π
or
fn main() -> AppExit {
App::new().add_plugins(plugin).run()
}
fn plugin(app: &mut App) { ... }
but yeah, does anyone wanna open a plugin v2 working group π so we can get bevy to the state where hot reloading is seamless
( among other improvements )
What roughly is plugin v2?
need a working group waiting list heh
ahaha
yes
if we get async systems than that would make plugins v2 SOOOO cool and awesome and epic
π₯Ί π₯Ί π₯Ί π₯Ί π₯Ί
I've heard about plugin dependencies, is there anything else?
@vivid ember how many more hands does async systems have?
factorio got hands
THAT it does my good sir
i havent written much this weekend beyond friday's slotmap draft
also things like putting all of a plugin's systems behind a .run_if(in_state) or w/e
which can be done if the plugin comes with a corresponding system set for all of its systems but otherwise not possible
Oh yeah that's good
there should be a split between the systems registration ( which should be sync ) and can be run multiple times:
and the resources added in plugins which potentially async owo? and plugins lay-out dependencies for what resources they need
( from other plugins )
i wish i was experienced enough in async-kung-foo in order to help 
It won't work without changing bevy unfortunately, but for the systems/resources split you could at least check within each add/init_resource whether you're currently hotpatching, and then become a noop for those cases
oh yeah we're gonna change bevy, but for the resources thing the issue is that there is code in the build fn that runs no matter whether or not the resource actually gets added
the resource being added being a no-op is almost entirely irrelevant to the true issue of code running in build that u can't run twice
i pass in a whole new app so all the resources added don't matter, but i still can't rebuild the winit plugin
plugins can run arbitrary code like creating files etc.
they're too flexible to reason about
i mean, and they always will be able to run arbitrary code, we'll just tell people "best practicies so ur stuff works with hot-reloading ( and just in general ) is to just add systems and stuff in the systems fn and then do all your other setup in the build fn
although i guess this will always be true wrt what they can do to the user's machine as long as they can run code
but you can at least limit what they can do to the App / World
just rn there is no split
we don't really care that much what they do with app/world, because we can control that under the hood, what really matters is just providing a sensible split so people can use it
could have like Plugin::add_systems that accepts a SystemAdder that can only add systems to app and nothing else or w/e
to enforce a split like that
But that makes every plugin much more difficult to use, and it makes every app different from main, neither of which I think is acceptable
I thought subsecond gave you a way to check if the new function ptr is the same as the old one or something, and in that case no need to rerun
we're gonna basically be doing this anyways for plugins v2 from my understanding
There's too many advantages to a structured approach
You manually store the ptrs are then check on a hotpatch whether the new ptr is still the same as the old one. If not, this function was patched.
I believe the ptr can also change if another function that was close in memory was patched, not sure. Donβt quote me on that last part.
Hi, I would love to test hot-patching out, but would love some help. I am on linux (fedora) and am usually using mold as the linker. Is there a way to try out hotpatch without symlinking the linker? I would avoid that if possible
Yeah, look at the current readme, which uses unsymlinked LLD π
Mold is not working that well on the newest version of subsecond
@raven valley do you think you could add the caveats to your readme PR? I'd like to get it in before the jam π
Im on the clock rn! Ill try to get it done after work but feel free to make a new pr how you wanna see it if u want
Thanks, I got it to work π
Few questions:
- is there a way to auto despawn entities spawned in a 'rerun_on_hot_patch' system before rerunning it? I saw discussions about this earlier, just don't know the conclusion.
- are there some tricks not in the readme, to speedup patching time? Currently 1.6 sec, which is not bad, just asking π
- yes, but you need to use the workflow shown in the
add_systemsexample. Otherwise, you need to do it manually like in thererun_setupexample - the general speedup tips:
- Use debug = false or "string-tables-only"
- compile the tip crate with cranelift
- use the -Z flags
Thereβs a config.toml in the repo you can consult π
ping me if you need help with any of that, I'm also on Fedora!
Awesome, thanks. Is there a 'OnEnterRerunHotPatch' that initially runs like a normal OnEnter, but subsequently after hotpatch, if in the specified state?
@raven valley I'm experimenting with macroless right now btw
If this works, you may be able to take some parts of that for your implementation π
Thanks for the tip about std::mem::swap
Hm?
Hm?
Explain
I have lost context π
My context window has cleared
hehe
I have an idea for how to turn the API for the basic #[hot] workflow into this:
App::new()
.add_plugins(DefaultPlugins, SimpleSubsecondPlugin)
.add_systems(......)
.enable_hotpatch()
.run()
Without requiring any macros
by hacking the schedule
Might be unsafe or even unfeasible, let's see
(You're right in your remark that Schedule's API is somewhat limiting)
ahh
If you manage to do it, then I guess OnExitRerunHotPatch would also be possible. With those two, we wouldn't need commands.queue for every case, since the cleanup can be (and usually is) in the OnExit event.
Yeye
If u wanna take a stab at it the existing code that does stuff is actually pretty small and simple
Look at the hotpatch app file
You might be able to figure out how to do it with states
Conceptually I should explain, what we are doing is we pass a whole new app we create into the closure everytime we hot reload
And then we extract out the schedules like Update, and stick em in HotPatchUpdate
And then we run HotPatchUpdate inside of the actual original app's update
So it seems like you'll wanna extract out the state based schedule(s), and also rerun whichever one we are actually in as well?
Currently getttin this error on any hotpatch:
Build failed: Runtime Error: Build panicked! JoinError::Panic(Id(47), "failed to resolve patch symbols: RuntimeError(Failed to find ___aslr_reference symbol\n\nStack backtrace:\n 0: dx::build::patch::create_undefined_symbol_stub\n 1: dx::build::request::BuildRequest::build::{{closure}}\n 2: dx::build::builder::AppBuilder::patch_rebuild::{{closure}}\n 3: tokio::runtime::task::core::Core<T,S>::poll\n 4: tokio::runtime::task::harness::Harness<T,S>::poll\n 5: tokio::runtime::scheduler::multi_thread::worker::Context::run_task\n 6: tokio::runtime::context::scoped::Scoped<T>::set\n 7: tokio::runtime::context::runtime::enter_runtime\n 8: tokio::runtime::scheduler::multi_thread::worker::run\n 9: <tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll\n 10: tokio::runtime::task::core::Core<T,S>::poll\n 11: tokio::runtime::task::harness::Harness<T,S>::poll\n 12: tokio::runtime::blocking::pool::Inner::run\n 13: std::sys::backtrace::__rust_begin_short_backtrace\n 14: core::ops::function::FnOnce::call_once{{vtable.shim}}\n 15: std::sys::pal::unix::thread::Thread::new::thread_start\n 16: start_thread\n 17: __clone3)", ...)
anyone else had this?
This happened since I upgraded to the latest master
Seems something which changed broke it on my machine.
(also the examples stopped working for me)
Ok seems the update broke when I use mold, but it could get it to work again with lld
yeah it's a bit fickle with mold :/
@raven valley plz take a look at my monstrocity: https://github.com/TheBevyFlock/bevy_simple_subsecond_system/blob/macroless/examples/experiment.rs
It doesn't actually hot-patch yet for some reason, and it wraps all systems in an exclusive system, but it's just a little proof of concept
What it does is
- Remove
Schedulesfrom the world - Get some owned systems out of the schedules via unsafe shallow clones
- Do something with the owned systems (in this case try to wrap them in a hot patched closure)
- This part here does not yet work, for some reason. It compiles and executes fine, but is not actually hot-patched
- Build and insert a new
Schedules - Leak the original
Schedulesin order to not double free memory, as the newSchedulespoint to the same systems and will calldropfor them (So this is not an actual memory leak, I believe π )
I believe you will find this exciting π
Well, I looked around, but this is beyond me. I have no knowledge on bevy internals, and don't know how I could iterate over registered state enums, so I can check if reload_schedules has an OneEnter<State> in it. But this might be a bad direction by itself. I will leave this to you wizards π§ββοΈ
ooo
wait
this compiles?
i mean it must
huh
for (_label_ref, schedule) in old_schedules.iter_mut() {
schedule.initialize(self.world_mut()).unwrap();
let interned_label = schedule.label();
for (_node_id, system) in schedule.systems().unwrap() {
// SAFETY: we now have two `Box`es pointing to the same data, so we should absolutely never ever
// touch the original `system` again. This includes not calling `drop` on it, see below.
let cloned = unsafe { system.clone_shallow() };
let hot_system = cloned.with_hotpatching();
new_schedules.add_systems(interned_label, hot_system);
}
}
@mellow flint i don't think this works? as in it totally breaks relative scheduling
this is a very cool idea though lemme see if i can think of a way for it to work
hmmm what if you instead of doing the .add_systems just got a mutable reference to the systems vec to a specific system and then did a mem swap on it with an empty system. And then you took the new system u have access to, and you wrapped it in a hot func and then you mem-swapped the same spot again?
π€
I think to add on state transitions I'll have to add a new custom with_hot_patch_replace, which i don't like 
OH
wait
maybe a way around it?
π€
eh idk if i even want to, i think i want to work on plugins v2, this is good enough and what i really want needs plugins v2
Hmm I believe you're right
makes sense π
U might be able to tweak it the way I suggested!
Not sure it will work tho
- [linux] thread '<unnamed>' panicked at .../bevy_simple_subsecond_system-968e5cd1f3afb8e1/e6ad794/src/lib.rs:71:57:
- [linux] called `Result::unwrap()` on an `Err` value: Dlopen("../target/dx/game/debug/linux/app/libinertia_protocol-patch-1748431134872.so: cannot allocate memory in static TLS block")
currently getting this error on code change.
(it is a startup system with hotpatching)
The system which changes has this signature:
#[hot(hot_patch_signature = true)]
pub fn setup_game_ui(mut commands: Commands) {
commands.queue(|commands: &mut World| {
Only uses command as a system parameter.
at first glance, looks like it's the closure
the world queue closure?
never seen that error π
I can paste the whole system if that helps?
Sure, can you achieve what you're trying to do by changing the signature of this function to take an &mut World?
or maybe...huh. I wonder what happens if you pass in a function pointer
app.with_hot_patch(|app: &mut App| { app.add_systems(StartupRerunHotPatch, setup);
app.add_systems(StartupRerunHotPatch, setup_game_ui);
Are you using thread local storage anywhere in your code?
Only use queries and resources in my systems, was hoping it would be anything with local storage.
The actual error itself is complaining about something related to thread local storage, so if you're not using that anywhere, then it must be something subsecond is doing wrong
I now also tested the same project on a mac, and I haven't had the same issue.
So it seems to be linux specific? but currently testing a little more.
after more extensive testing it seems to only happen on linux
Are you using mold or the default linker?
on linux I use lld (the current recommended one)
Sounds like a subsecond bug then. Could you open a report on the Deoxus repo?
Can I hotpatch consts correctly using the plugin?
good question, i think i tried it and it worked but don't quote me on that ( this was using the with_hot_patch functionality )
If the const is inside the function, sure.
If it's outside: good question, let us know π
That did not work for me yesterday
Modifying a const should change the function since its effectively gets inlined, so it should work
can i pass a function plugin to app.with_hot_patch like app.with_hot_patch(foo::plugin)?
also, if i add a plugin in with_hot_patch will all of the plugin's systems be automatically hot patched without #[hot]?
or does that only apply to systems added directly within the closure passed to with_hot_patch
- Yes (that was my exact same thought when Malek came up with the API haha)
- Yes
Caveat: this only works as expected when the plugin does not do anything other than add systems.
Resources donβt work yet, and weβre not really sure what happens when using register_type (let us know if you try), Also not sure what happens when you use fancy App things like configure_sets
Every Schedule contains quite a bit of data, plus the Hashmap of Schedules, still quite a leak I believe. π€
Also, nit since it is an experiment, but you only copy the systems but not the graph/configs so any ordering is lost.
I think youβre right on both accounts, yeah
I tried to reproduce is after a machine restart and couldn't up to now, so not sure what caused it in the first place π€ .
hotpatching times grow quickly with the size of the project it seems (now at around 6-7s, in a realtive small project with a few dependencies).
I suspect that we're going to need to aggressively split our projects out into subcrates in order to keep hotpatching times low
Which is consistent with the standard advice for compile times
So best to have a workspace?
No workspaces dont work yet
Btw @languid sable was the readme easy to follow?
I've been slacking on getting it set up :p
On my docket for today
Was poking at bevy_console and bevy-inspector-egui first
@mellow flint since you're in the git-blame for the readme lines regarding symlinking mold: sooooooo that broke my dkms build causing graphics driver to fail to install/update because mold doesn't support some flag or other. those readme instructions for mold seem relatively dangerous, as that left me with a system which thinks its reached graphical.target but doesn't display anything
so just blanket symlinking mold over /usr/bin/ld isn't something i would recommend to anyone
Yeah it's crap, agreed π
I should add something about "warning: this will affect and possibly break other things on your system"
The current readme at least tells you to use LLD
please for the sanity of everyone involved remove the recommendation for mold that way entirely
Symlinking cc to clang is safe at least π
there's gotta be some way to get mold working which only affects subsecond
Hmm it's not a recommendation, just a "hereβs the only way that using mold with subsecond works"
maybe adding to path temporarily
PATH shenanigans was going to be my suggestion, yeah
Fair enough
We can set it earlier in the path
Wanna do a PR? Otherwise I can do so myself when back home π
i can after testing how to do this ideally
I'd be very grateful, thanks!
And sorry for causing you trouble with your system!
i'd like some way which automatically just... only works for subsecond
ehhhhhhh better me than some of thw people i know
Yeah, I asked the Bevy CLI people if thereβs maybe a safe way to automate the setup
Since I believe Jon is not planning on tinkering with it for a while
Uhhh
We should put a big WARNING: DANGER
Label above doing that.
Lmeow
i am going to make a PR which removes that recommendation entirely
if i can make it work with PATH manipulation, great, otherwise its just gone
Yeah sounds good
i'll probably leave a warning "if you symlinked mold in the past, undo it ASAP"
The main reason it was there in the first place is that an earlier version of subsecond didnβt respect linker settings at all AND didnβt work with LD, so this or PATH shenanigans was the only way π
But since that is no longer the case, I have no problem removing it
success
minimal: linker path Output { status: ExitStatus(unix_wait_status(0)), stdout: "/home/a/.cargo/dx_bin/ld\n", stderr: "" }
any preferences for what directory to recommend people create for this? i just did $HOME/.cargo/dx_bin for testing but open to other ideas
works as an alias too!
Nice!!
Hmm sounds reasonable, but I donβt know if one is "allowed" to put stuff right in .cargo
@loud narwhal do you have a place in mind?
i've been storing a nightly-only config-fastcompiles.toml there for a while, which a function overwriting cargo switches between based on rust-toolchain.toml
its not caused issues so far so i can only assume its fine to store stuff there
so if for Mold we're gonna recommend a alias with PATH changed, why not do the same for cc/lld? overally, it feels like the far less janky solution compared to globally changing the linker binary
@mellow flint uhhh, the readme says to link mold over ld but the .cargo/config_faster_builds.toml says to link mold over cc... which one is it?
i'm assuming the latter is wrong, and linking mold over cc would not work as that makes little sense to my understanding of what cc is
Should be cc -> clang
right but for mold, theres no need to add clang?
i'm talking about these lines:
[target.x86_64-unknown-linux-gnu]
# Linker commented out due to https://github.com/DioxusLabs/dioxus/issues/4193
# Instead, the global `cc` is symlinked to `clang`
# linker = "clang"
rustflags = [
"-C",
"link-arg=-fuse-ld=mold",
This is correct
π
i fully just read 'clang' as 'mold' there
anyways, still confused
does mold setup also need cc linked to clang?
Yes
Mayyybe also works when symlinked to gcc
mine is linked to gcc and its been working anyways?
@idle stone removed the mention of gcc, he'll know why
Important thing is just to to have the actual cc as cc π
That one canβt handle linker args
now i'm confused even more: for me, it seems to sometimes use mold and sometimes not, and right now it doesnt
anyways, thats probably correct, so i can change how the docs are written again as both lld and mold need the clang symlink
i swear i had mold working before, wierd
i think
Why does the Dioxus CLI need SSL 
It actually makes sense in the broader context of their CLI, but I really want the hotpatching stuff split out
wait hmmmm no that commit is before the one the readme suggests installing...
it could be that my dx is out of date, and this just works and nothing of this symlink bullshit is neccesary. wouldn't that be nice.
well, actually, the linux setup instructions are the most cursed ones
hotpatch builds take roughly twice as long as normal builds on my machine.
Is that to be expected?
nope, i updated and thats not fixed
NO NO NO NO NO
i.. think i found the core issue why linker="clang" is broken with dx
if this works...
Not super keen on dx silently + without prompting making changes to your Cargo.toml
Absolutely, I've already opened an issue
Or the mysterious "installing tooling"
No 
Serving your Dioxus app!
This is definitely going to confuse people
I get why they would like to have prominent branding but...
Hmm. It isn't immediately working for me / on my project
I'm going to test the examples
i desperately wish strace wouldn't slow dx serve to a crawl
Try minimal.rs
Okay great, the example works for me π€
I guess it's time to make my simulation repo public and ask for help troubleshooting π
I don't fully understand, what's the reason for putting the binary in a different place than the cargo default?
Itβs a symlink to mold, there is no connection between it and cargo
And I donβt know if cargo wants to manage that dir entirely alone or whether users are allowed to out random stuff in there
I'll check at home π
Low hanging fruits:
- did you add the plugin?
- did you make sure you have no lib.rs?
Probably not the safest place to put it. The dioxus CLI has its own home dir AFAIK, maybe in there?
I still need to read through the setup instructions in the readme so I am still lacking most of the context :D
I'll hope to get that done soon
Thx π
i kinda got sidetracked by the fact theres a DX_LINKER env var it reads out and then by the fact that the reason linker="clang" doesn't work is so dumb
basically
it seems to assume linker= contains the full path
yeah
anyways, its still error-ing for me, but at a different step. trying to trace that rn
but it might turn out that theres no need for PATH-shenanigans either, just setting DX_LINKER
I asked multiple times about that env var and got no real answer about whether that is the intention or not. It was also broken on Linux at sone point
Itβs entirely possible that it all works out now, just saying π
aye, right now i'm testing what the issue with linker="/usr/bin/clang" is
Yeah I was also wondering how that could possibly fail
its some other error
I suppose itβs appending it to the working directory accidentally, maybe
the "file not found" stuff, right?
i had the strace to prove it lol
yup
oh how fun, trying something which hopefully doesn't just freeze dx right now, and it needs a DKMS module
(sysdig)
Yes and yes
i could probably get away with auditd but that cant filter by "a process and its subprocesses" which i need
my system cc was already nothing but a symlink to gcc which sees that it's named "cc" and runs in cc-compatible mode
hmm well this suggests it's only used for display purposes: https://stackoverflow.com/questions/939989/invoking-gcc-as-cc-versus-gcc
regardless, hotpatching was not working for me when leaving cc as a symlink to gcc
i thought this was still the case
It worked for me without any changes, but its possible that my nightly is already using rust-lld by default.
In any case, doing no config at all used to not work, but now it does on my system π
i couldn't get it to work without symlinking cc to clang and symlinking ld to mold after the change
ah yeah my cc on fedora was already symlinked to gcc, which worked out of the box for me.
Weird that gcc didn't work for you 
Does it work when not symlinking ld at all and instead doing the lld linker setting?
so linker = "lld"?
no, sec
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-Clink-arg=-fuse-ld=lld",
]
@late stratus I'm home now, so let me know when to review the mold instructions π
taking a look at this now
welllll since i got sidetracked it might be a second
still tryna debug the reason why it won't just work without any changes, as the source implies it should
I think you don't need to figure out the clang stuff for now. Symlinking cc is very commonplace, I have no issues recommending that for now
fair but also, i know the fix for that one
just put linker="/usr/bin/clang"
but then theres a subsequent error which may or may not happen conditionally
why in the everloving fuck is dx spamming which about 100 times per second?
@languid sable I'm pretty sure I know why! You're not using the newest version of the plugin. Unfortunately, we cannot do a new release because we are waiting for a dioxus release, so you need to depend on the hotpatching stuff as a git dependency π
Let me try that real quick
yep that was it
Use
cargo add bevy_simple_subsecond_system --git https://github.com/TheBevyFlock/bevy_simple_subsecond_system
wait no i'm an idiot. thats me. i'm spamming which that often, i edited the minmal example and forgot to put that command in the info_once
I know the feeling haha
sidenote: sysdig is cool, i can write queries for syscalls and other events like: evt.type=execve and (proc.cmdline contains dx or proc.acmdline contains dx)
wait
i swear i didn't do anythin! why does it suddenly work!
Aha!
Okay, that fixed it π Hotpatching works for me now π
Hurray! Anything in the readme or API I should change before the jam?
I saw a typo in the README (CI plz), and readme.md is all caps by convention.
I would also move features and limitations sooner
I hate files that shout at me π
But yeah fair enough
(same with licenses, btw)
BTW, may I kindly suggest you try out pub fn plugin(app: &mut App) for your simulation? I think it would cut down on quite a bit of boilerplate π
π I don't like that style!
linking failed
C'mooon, give it a try 
I have! I don't like how it clashes with the built-in plugins :p
fair enough, that it certainly does
oh, i don't need to symlink cc to clang if i do linker = "/usr/bin/clang" instead of linker = "clang"
tried from this message π
that works for you?! π
huh, I have to try again
I could have sworn I got "File not found" all the time
i think that dx just... ignores those parameters so it initially builds with mold or lld, and then tries to patch with ld
which fails
well, ofc you should add your own which clang lol
oh wow yeah i'm getting 10-16s patches
I did that :U
(it's normally 4-7s for me)
probably because its using ld
oof
i mean, the change which made this possible was committed 5 days ago
fwiw
Yeah, I tried right after Jon pinged me π
But it's possible I just fat-fingered a wrong path π
I can try again
so @late stratus the PATH approach worked for you as a replacement for the symlink approach?
if so i'll try it too
hmmm setting DX_LINKER=/usr/bin/clang and linker = "/usr/bin/clang" (and without symlinking cc to clang), i get 5s hotpatches now
i might only need the former
I think a lot of this is very possible with the eBPF suite too, but probably not so accessible
is that with DX_LINKER=/usr/bin/clang? fwiw i do have -Clink-arg=-fuse-ld=mold in my rustflags as well, and i have ld symlinked to mold
seems to need both, i got an error using only DX_LINKER
hm idk, now i got a 16s patch again and this warning:
mold: warning: unknown command line option: -znostart-stop-gc
i did try to use eBPF acceleration for strace but it could not find the dx command
ld symlinked to mold seems to be neccessary
sadly
@idle stone for me, ld symlinked to mold broke my graphics driver DKMS module, leading to a system which wouldn't render anything
which is why i'm so dead-set on not needing that
because thats dangerous to recommend
yeah that's rough
with symlink i'm now still getting this warning, but it's 5s patches
i probably just didn't notice the warning before. this is also with verbose logging on
yeah, looking at the sysdig execve traces it seems no matter what, /usr/bin/ld is hardcoded somewhere
oh lol, i traced write syscalls to the stderr file descriptor to find that
if you don't have mold symlinked, these are the errors besides that warning:
/usr/bin/ld: /home/a/rust-projects/bevy_simple_subsecond_system/target/dx/minimal/debug/linux/app/stub.o: .symtab local symbol at index 45 (>= sh_info of 1)
/usr/bin/ld: /home/a/rust-projects/bevy_simple_subsecond_system/target/dx/minimal/debug/linux/app/stub.o: error adding symbols: bad value
i have a horrible idea
intercept execve calls to /usr/bin/ld using LD_PRELOAD and direct them to Mold instead. that way the LD_PRELOAD env var can be set only for dx using an alias
i'm not seriously considering this but uhhhhhh it would probably work i think
Man needing to annotate the systems you want to hotpatch is super annoying
Since then you can't just reach into random code unless you litter your whole codebase
Can you add new systems via hotpatching yet?
yes
as seen in the add_systems.rs example
// try adding and removing systems from here! make whole new ones!
.with_hot_patch(|app: &mut App| {
// StartupRerunHotPatch is like Startup, but will rerun on hot-reload.
// You need the #[hot(hot_patch_signature = true)] macro to auto-despawn entities spawned in it!
app.add_systems(StartupRerunHotPatch, spawn_ui);
// All other systems do not require `#[hot]`.
// Try writing, adding, and removing new ones here at runtime!
app.add_systems(Update, print_hello);
app.add_systems(
Update,
change_text.run_if(input_just_pressed(KeyCode::Space)),
);
})
Thank you for indulging my lazy questions β€οΈ
its also infectious but at least not as much as #[hot]
And we should be able to fix both of those with a first party solution right?
Hotpatching constants works perfectly BTW
yeah i just got a 14s patch with both cc and ld symlinks. i think rust-analyzer check on save is interfering with the hotpatching
Vanilla #[hot] is already fully superfluous on Francois PR π
But we donβt have a macroless solution yet for adding new systems at runtime or changing their signatures
.with_hot_patch, no?
ohh you meant francois pr
my bad
Yep
Make sure you have seperate targets
And with_hot_patch is definitely not getting upstreamed, too X-Controversial
yea
should be separate ("rust-analyzer.cargo.targetDir": true), although i am also using sccache
I went through and annotated literally all my systems and observers with it 
same
i just droped most of the results of my debugging and messing around here: https://github.com/DioxusLabs/dioxus/issues/4193#issuecomment-2920448781
Highly appreciate it, thanks!
it really does seem like /usr/bin/ld is just hardcoded somewhere, so sadly symlinking (or intercepting with LD_PRELOAD) is the only way to use mold
Great! 
Can we get LLD running reliably without symlinks?
nope
nothing
no matter which option i tried, it always ended up calling /usr/bin/ld
directly
though for anything but the last step, yes.
the line which i'm quite sure keeps calling /usr/bin/ld is: https://github.com/DioxusLabs/dioxus/blob/3a5b68e56d351d5ea5f25c57c2a763b5fd8c8f18/packages/cli/src/build/request.rs#L1350C32-L1350C38
Fullstack app framework for web, desktop, mobile, and more. - DioxusLabs/dioxus
that runs the linker with stripped out linker arguments and i think this removes -fuse-ld=mold by accident
i can prove it in just a second though
i love being able to just... query syscalls and their full input/output
actually
i can't
damn clang argument strings are more than 4096 bytes, the limit of what sysdig captures
wohooo for cursed bash scripts. in this case: piping execv syscalls into a thing which quickly dumps /proc/<pid>/cmdline to get full-length arguments
#!/bin/bash
sudo sysdig "evt.type=execve and (proc.cmdline contains dx or proc.acmdline contains dx)" -p"%evt.time %proc.pid %proc.name" | while read time pid pname; do
sleep 0.02
if [ -r "/proc/$pid/cmdline" ]; then
cmdline=$(tr '\0' ' ' < /proc/$pid/cmdline)
echo "[$time] PID: $pid, Name: $pname, CMDLINE: $cmdline"
fi
done
ah yknow just your average rustc call with 48 251 characters of arguments
@mellow flint i was wrong
clang/rustc are always called with -fuse-ld=mold properly
so it comes down to this function:
https://github.com/DioxusLabs/dioxus/blob/main/packages/cli/src/build/request.rs#L1933
wait no that makes no sense, that should shortcut if we pass DX_LINKER
the hecc
oh bother
/// This means we basically ignore the linker flavor that the user configured, which could
/// cause issues with a custom linker setup. In theory, rust translates most flags to the right
/// linker format.
guess what chuckleheads, its literally commented in the source code. just above they match "mold" to LinkerFlavour::Gnu
nope i'm right!
at some point it forgets to pass -fuse-ld=mold
specifically, when starting tokio-runtime-w processes
which i assume is tokio::process::Command
it checks for -Wl,-fuse-ld in arguments to keep around, but not -fuse-ld
ahh, and i cant just set both variants in rustflags
23:06:15 [dev] Failed to generate fat binary: mold: warning: unknown command line option: -znostart-stop-gc
mold: fatal: -auxiliary may not be used without -shared
clang: error: linker command failed with exit code 1 (use -v to see invocation)
23:06:15 [dev] Build failed: Failed to write main executable
o.O
btw
i'm dixing dioxus cli
1 line change and mold works properly
gonna also fix linker="" if i can
Oh heck yeah! Pinging @worldly ether π
gimme sec, PR aint done lmao
as i said, also fixing linker
which is actually a bug from cargo_config2
they don't resolve PATH like cargo does
oh whaaa
once your fix is up, we can link to your branch in the readme
wait have you seen this before @mellow flint https://github.com/rksm/hot-lib-reloader-rs
mind blown-er
This is more along the lines of what ye-ole https://github.com/DGriffin91/ridiculous_bevy_hot_reloading does
oh wow
didn't realize, this is really cool! didn't know stuff like this had existed. really cool
Thanks! There's also https://github.com/lee-orr/dexterous_developer just in case you didn't know
Yeah this is the OG variant π
thx!
I'll try it out right away π
yeah makes sense

@late stratus pretty sure it's using mold and clang alright, but mold is still acting up on my system 
But I'll update the readme according to your PR π
i was working on a PR
hmmmm, works just fine for me, what version of mold do you have?
Oh, how far are you?
mold 2.39.1 (compatible with GNU ld)
thats how far
hmm i hav 2.40
thats such a small difference, i doubt it matters
though i have not tried it with a multi-file project yet
Just tested it, and it also works for me in isolation. The issue is from mold + some other setting
In a previous version, doing mold + a custom target dir + subsecond didn't work
So let's try that
aight
renamed by target folder to target_custom, added target-dir to config.toml, and it works
could be scccache, or maybe dynamic_linking?
i'll check
left some comments, nothing big π
I could only reproduce it on Foxtrot, so I can't test it too much, as recompiling that cold takes a while.
But I'm fairly sure the culprit were some changes you have to enable for cargo-flamegraph
Undid those and now it works with mold π
nice!
left some replies, some of them big ;)
i have β¨ opinions β¨
(tldr: don't overuse details collapse thingies, global config == bad)
@late stratus are you fine with me changing the rec to mention both global and local?
sure
i already commented on gh but do whatever you want
i care, but i dont care that much
Oh yeah, rustdoc does not like those π
LMAO they dont know gituhub markdown
Ye
doesnt crates have warning boxes too? what syntax are they?
no problem, i'm glad it turned out to just be 2 lines changed
Can't remember seeing one of those. Do you mean a quote with a warning emoji maybe?
β οΈ Like this!
though i do question the sanity of whovere wrote the CLI. making it a rustc wrapper, a linker and a otherwise many-purpose CLI in one is a bit eehhhh
It does quite a bit π
The subsecond part could definitely live in its own CLI
it needs to
the cli is 1000 crates!
TIL!
Is that literal or hyperbole?
literal
Then it's probably to do faster compilations
There was an infamous blog post about how to increase parallelism by doing literal thousands of crates automatically
not at all
i would send just the dependency block, but it'd count as spam
π I'll check later
anyways, i'm gonna sleep now. i focused on this wayyyy too much and its 2am
ahhhhhh fuck, i forgot to eat dinner didn't i
take care of you!
And I'm super grateful for it 
merging readme now
i could stand to loose the weight, its more just annoying
figure id ask here
anyone knows what going wrong here? https://github.com/ValorZard/sdl3-subsecond
for some reason, the subsecond stuff isnt getting connected
Is this a good place to post issues with bevy_simple_subsecond on Windows? Currently seems to be borked at least for me
basically with the original dx 0.7.0 alpha hot reload breaks and the new forked CLIs don't install for me because it seems this is still a problem https://github.com/DioxusLabs/dioxus/issues/3309
I don't know sdl3 enough to be sure it's the problem, but if your game loop never exit its while running, subsecond can't patch it. you should do the subsecond::call only around the iterate method
Ah gotcha
I raised an issue on the repo. It seems I'm the root cause of all the issues on the bevy_simple_subsecond repo π€£
it seems the #[hot] macro might be swallowing system validation errors currently
Can you give an example?
The parameterless version of the macro has the same signature as the system, so that seems odd
Try replacing dioxus_devtools::connect with dioxus_devtools::connect_subsecond or something like that
Hehehe
I request another cool game about whales in return π
happened in a stream i'm watching, trying to spawn a non-existent component
wait no, that can't have been it, it compiled correctly
ughhh i wish i'd taken a screenshot
Heck
related: having watched a second person (after chris) try it out live, i'm convinced that for what the plugin is, it would make more sense to recommend the .with_hot_patch variant
unless i'm missing some downside of it?
- things that look like they should work but donβt (e.g. resources)
- your code is no longer "just Bevy" but a new API.
- From chatting with @karmic current, that workflow requires remembering a surprising amount of steps when introducing it to your App
I'd like to recommend that workflow as our main one, but thereβs a couple of things I'd like to see fixed first. Which seem to be not really addressable in a satisfactory way until Plugins V2, if I understand @raven valley correctly. That said, I also want to get the readme PR merged later so that users can even get to know this workflow.
Curious about your opinions as well @languid sable
ughhh
ah well
i should also do some more readme cleanup, the way the drawbacks arr documented currently is confusing
I wonder if it's possible to emulate Plugins v2 as a crate. It would be pretty intrusive, but it might be possible to then integrate that with the hotpatching
i did try to hotpatch at the level of FunctionSystem.func before (to fix the early local state issues) and that did not work out at all
not sure if plugins v2 would be relatef
could you elaborate on the resources issues? or link to where that's brought up if you know
The closure will do weird stuff if you use it for anything other than adding systems. Also, systems that rely on locals / EventReader will have then cleared on hotpatches.
I have a branch with unsafe stuff to hack internals, but hotpatching is not working there for some reason 
wohoo my subsecond PR is merged
That was quick!!
I'll update the readme to the original repo π
I think weβll be able to do a lot in Bevy even without plugins v2, or maybe with just small changes in that direction
Anyway waiting for my pr to get merged which is waiting on Cart review which is waiting on a new subsecond release π
Yup you could do plugins v2 as a third party crate
I can put out an alpha-2 today I think
Just your PR already is 80% of what I personally need. Once we get auto-rerun that includes auto-despawning, we are pretty much there already. Signature changes and adding systems at runtime are very nice, but more like cherries on top IMO
Oooh that would be awesome
Nice that we got @late stratus's changes in in time π
Iβm pretty sure signature changes are possibleβ¦ and I have some ideas for schedule modifications, but thatβs more hazy
Setup despawn and rerun need a bit more reflectionβ¦ but weβll get there
is there anything left on the subsecond end of things beyond the workspace CWD problem and workspace support?
Don't know what CWD is, but these are some issues users have run into very recently:
- https://github.com/DioxusLabs/dioxus/issues/4191 (very prominent, pretty much a blocker on Windows imo)
moldstill fails to link sometimes, even on the newest changes. Will create an issue later.- https://github.com/DioxusLabs/dioxus/issues/4223
- From a branding / Bevy integration perspective:
- https://github.com/DioxusLabs/dioxus/issues/4168
- Don't say "Serving your Dioxus app!" when in fact this is a Bevy app
Number two is somewhat important-ish, as many Linux users use mold for Bevy, but the workaround is trivial (just use lld)
But the big one is the length issue on Windows
by the way, alpha-2? did I miss an alpha-1 somewhere?
Whoops I got the number wrong - alpha.1
@mellow flint something to investigate is how to isolate the part of the code that is rebuilt. like is it possible to have the dependencies in a dynamic lib that is not rebuilt, and just your code? that should help with larger project times
adding to the "branding/bevy integration": is there really any need to constantly take up a large section of console space with the UI? additionally, the UI breaks when the terminal width is too small. Personally i would love to just... not have any ui at all, and just output some lines of log messages instead
(i would also love if just the "dx serve --hot-patch" could be split out into a separate tool, as 1000 dependencies is ridiculous for the very small subset of dx features we need, but thats far less critical)
preach
good question / idea π€
fwiw this is how subsecond gets fast hotpatching times, and we could do this for the initial build, but currently don't push it too aggressively in case there's something in the fingerprinting we get wrong
long term I want to ship an scacche integration in dx that pulls precompiled deps from github ci/cdn, so initial builds are always hot
oh π€
I thought that wasn't the case as people are reporting longer times on projects with more dependencies
i really hope this will be optional for anything else trying to integrate subsecond. Actually, that plays into my wish to have a separated out bare version of dx serve --hot-patch which can be use independently, exactly so things like this and the dioxus tool setup stuff etc. is not going to affect other projects
from having looked at the execve syscalls done by dx serve --hot-patch for way too long yesterday: it still passes through the enormous list of dependencies, even if just as files, to every linker call.
if you're talking about what occurus was talking about, that was longer time on larger projects
not dependencies just raw amounts of code that is in the main.rs and related files
We are getting longer patches for already running projects that scale with the project size / number of dependencies.
At least I get 10 x longer hotpatch times on a big 3D project compared to a small toy project
If you need, I can send you the projects in question if you want to try for yourself
the amount of dependencies should still be relevant, as i said, i passes the entire list of dependency artifacts to each linker call
could be that doesn't take noticeable extra time, but i bet it does. but i have no clue if its even possible to not do that
It shouldn't be - we still pass the compiler's .rlib files (libstd, libcore, etc) but not pure dependencies
I'm adding some more timing/tracing to the thin linking to get a better sense but I think the scaling is just rustc, and it's likely there's not much we can do there
workspace support should let us operate on individual .o files which would be important to work on if the scaling is because the linking is slow
setup build servers that would be fast enough to offset the upload/download times π
a custom codegen backend would make it possible to delay codegen until the linking phase but uh... gonna have to wait a while until we get that
there's an --interactive false flag which disables the UI (but currently dumps everything at a higher log level, which can be customized with rustlog syntax)
TIL π
Also, let me know if it would be helpful for you if I created a tracking issue with what I wrote you before
Maybe something to ask Bjorn of cranelift, he's also on this server
on my large project, rustc takes 1.8s and linking takes 47ms where the dx side of things takes <1ms
I can't get hot reloading to work on Windows on a small/medium sized project, it panics when I save the file. The dx build also doesn't seem to reflect the code - i.e. I have a string that I change and even if I ctrl+c and run dx serve again the string isn't updated in the UI. π€·ββοΈ
dx serve seems to be about 25% slower on the initial compile compared to cargo run (6.5 mins for cargo, 8 mins for dx) although its a bit unscientific.
From memory the incremental recompilation is about 10-15 times slower too than it was before with bevy/dynamic_linking enabled. (it was about 10-15 seconds from memory recompilation now takes 2 minutes).
Can you try https://github.com/janhohenheim/foxtrot ?
Haven't tried nightly yet Jan btw its getting pretty late. I can try foxtrot tomorrow
asking Jon to try it π
Are you using the correct version of the plugin? Make sure you depend on the git version
ah ok π
I might try it as well though tbh to see if my project is the problem haha
if I do the jam would like to try hot reloading
I'll try a cargo update
that won't help
do cargo add bevy_simple_subsecond_system --git https://github.com/TheBevyFlock/bevy_simple_subsecond_system
its already in there from git, I just bumped the rev in Cargo.toml
ah alright
Hmmm I wonder if dx is ignoring the linker setting given it seems to struggle a bit with cargo workspaces π€ I'm getting this warning on build:
[dev] Failed to generate fat binary: lld is a generic driver.
Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld (WebAssembly) instead
I tried to pass dx serve --hot-patch -p tableau --rustc-args "-Clinker=rust-lld.exe" but
error: unexpected argument '-C' found
If I run the build with verbose/tracing enabled I see
Running ...rustc.exe --crate-name tableau --edition=2024 crates\tableau\src\main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type bin --emit=dep-info,link -C opt-level=1 -C embed-bitcode=no -C codegen-units=1 -C debuginfo=1 --allow=clippy::type_complexity --allow=clippy::too_many_arguments --warn=clippy::nonstandard_macro_braces -C debug-assertions=on --cfg "feature=\"default\"" --cfg "feature=\"dev\"" --cfg "feature=\"dev_native\"" --check-cfg cfg(docsrs,test) --check-cfg "cfg(feature, values(\"default\", \"dev\", \"dev_native\"))" -C metadata=86b8d89efee4cd2b <sniop> --target x86_64-pc-windows-msvc -C linker=rust-lld.exe ...
so I guess it is using rust-lld π€·ββοΈ
Well anyway time to clock off for me, thanks for all your help Jan
OK one last thing, when the hot reload fails I see some logs like this with verbose/tracing on
Ignoring file change: client is not ready to receive hotreload. Files: [ // the files ]
warning: failed to connect to jobserver from environment variable `CARGO_MAKEFLAGS="-j --jobserver-fds=__rust_jobserver_semaphore_1142413780 --jobserver-auth=__rust_jobserver_semaphore_11424137 |`: cannot open path or name __rust_jobserver_semaphore_1142413780 from the jobserver environment variable value: The system cannot find the file specified. (os error 2)
= note: the build environment is likely misconfigured
Build completed successfully in 625251us
Undefined symbols : [ <a bunch of undefined symbols> ]
Setting builder to failed state
Build failed: Runtime Error: Build panicked! JoinError::Panic(Id(1185), "failed to resolve patch symbols: InvalidModule(\"ASLR reference is less than the main module's address
( log scale, time is in milliseconds, generated the functions with this macro )
seq_macro::seq!(N in 0..100_000 {
pub fn my_func~N() {
println!("This is my_fn_{}", N);
}
});
@celest magnet
added a 50,000 function datapoint, felt like it was needed
Get a big crate. Change let x = "foo"; for let x = "bar;", or add a comment. Watch as your life slips between your fingers after you type cargo check, or even worse with cargo build. One would think that this should be instant, especially with incremental compilation, but it's not. This is even worse when changing a crate that other crates dep...
enabling dynamic linking on bevy actually increases my reload times from 700ms to 1,700ms
It was negligble for me, but in release mode we cp the dylib into the bundle, while in debug mode we just symlink it. Are you running in debug or release?
dynamic_linking takes me from 2.5s down to 0.7s
I am using cranelift to compile the tip crate in my project
An interesting cursed idea
Editor>edit bsn of the editor+hot-reload>making the editor in the editor.
God mode dog fooding
that was always the plan, and the reason to push things to bsn π₯·
also that's hot reloading, not hotpatching π
I said hot reload?
yup!
I mean, it already works, that doesn't have anything to do with what we're talking about here with subsecond
except some naming discutions π
Subsecond is the code/rust side no?
Hotpatching is using subsecond and the dioxus tool to reload Rust code at runtime
Hotreloading is using the asset system in Bevy to use the new version of an asdet when it's changed in the filesystem.
Hotreloading is much simpler, as it's just changing data, not the code itself
I think Rin was referring to hotpatching the BSN macro's, not BSN files
No no I mean combination of hot-reload and hot-patch to edit the editor
@mellow flint iirc there was a thing where you had to use the same version of the dioxus cli + specified as a dependency in Cargo.toml as bevy_simple_subsecond_systems, is that still a thing? or maybe i'm misremembering the details
i want to test the version that supposedly lets me do linker = "clang"
although i probably want to wait for the alpha.1
Ah, I see now you we're referring to both π
Yeah the UI building workflow feels like it's going to be so much nicer with hot-reloading BSN scenes + hot-patching rust code/BSN macros
It'd also just improve the editor user workflow since cutdown on recompile needs
That's the newest main on dioxus' side π
Could you report your time hotpatching https://github.com/janhohenheim/foxtrot ?
so i can install the newest dioxus-cli and it should work with the current bevy_simple_subsecond_system?
With the current main of the plugin
Should be simpler again once the next dioxus alpha is release π
ah ok, and do i have to patch dioxus-devtools in my Cargo.toml accordingly too? i have it set to a rev rn
well it looks like the rev hasn't changed on main of bsss anyways, still b2bd1f
Ah, I think that should come for free, since the Editor is going to be a plugin iiuc, so running it with hotpatching enabled will just work β’οΈ
could you try setting $env:DX_LINKER="rust-lld.exe" instead, maybe even with a absolute path to the executable?
Will take a look later tonight. I pulled subsecond out last night because of the longer build times and no hot patching π
Just messing around with build time optimisation at the moment
i dualboot, so i can say this with confidence: the biggest improvement was switching to linux. not because it has mold or anything, but stock settings it was already a lot faster
Doesn't surprise me
There's some really esoteric dyn linking bugs on windows.
Yeah I've considered it but it's usually more trouble than it's worth for what I spend most of my time doing haha. I have a MacBook if I get really desperate.
Actually I'm wondering at the moment if it's the "tip level crate only" bug now as I had the main and lib setup going. I've added it to the list for this afternoon
I can specify the linker using the env var and it seems to work. At the moment I have this issue https://github.com/DioxusLabs/dioxus/issues/4191


