GithubHelp home page GithubHelp logo

Comments (10)

leudz avatar leudz commented on June 3, 2024
  1. Deletion (and removal) tracking is kept until you call clear_all_deleted or clear_all_deleted_older_than_timestamp to only remove some of the tracking info.
  2. Workloads don't really exist after they are added to the World, they are just a list of systems but they don't do anything and their start and end isn't recorded. So the fact that systemD is the last one isn't important.
  3. The tracking cycle is kind of in 2 places, there is the running cycle, each system has only one and it increases each time the system runs. Then you have stored cycles, like if you delete a component, the current cycle is stored with the deleted component. That's all per component and per tracking, like you can insert at cycle 3 and modify at cycle 5 to then delete at cycle 10 it's all stored at different places.

Here's a few important code pieces:

In the last one timestamp is when the component was deleted, last_removal_or_deletion is the last time the system ran (the counter is split further outside workloads, that's why the variable has this name) and current is the curent cycle.

I don't say it enough but thanks for opening this kind of issue.

from shipyard.

PudgeKim avatar PudgeKim commented on June 3, 2024

Thanks for a detailed explanation!
After reading your answer and looking some code, I have some more questions.

In View struct, there's a current field which means current cycle as you said.
Let's suppose I have 10 systems and 3 systems have a View<ComponentA>.

(
  system1,
  system2, // contains `View<ComponentA>`
  system3,
  system4, // contains `View<ComponentA>`
  ...
  system10 // contains `View<ComponentA>`
).into_workload()
  1. In this case, View<ComponentA>'s current field is set to 3 after one loop?
    What if system2, 4, 10 run in parallel?

  2. If I understand correctly about deletion, to enhance performance, should I minimize using delete?
    If I delete continuously without clear_all_deleted, deletion's vector keeps increasing and it'll increase time to filter.
    (there's a filter_map with is_track_within_bounds function.)
    Even if I use clear_all_deleted, it's not that cheap I think. (Is it right?)

  3. What's the meaning of u32::Max / 2 in is_track_within_bounds function?

Thank you in advance.

from shipyard.

leudz avatar leudz commented on June 3, 2024
  1. My previous comment was wrong, the third link wasn't the running counter. It was the last_run counter. This is the running counter which is global for all systems. And there is one last_run counter per system.
    So when system10 runs it has a current counter of 9 (it starts at 0) and a last_run counter of 3. Then the loop ends and when system2 gets a View<ComponentA> again it has a current counter of 11 and a last_counter last_run counter of 9 1. See below for accurate counters.
    If other systems run in parallel then the counter will be kind of random between them. But since they run in parallel it shouldn't matter, they can't borrow conflicting views (you couldn't have a ViewMut<ComponentA> and a View<ComponentA> run in parallel).
  2. I would say yes you should avoid deleting, or more exactly you shouldn't go out of your way to delete if you can remove.
    To delete an entity I wouldn't use remove on all components and then delete the entity but I wouldn't use delete over remove when possible.
    Yes if you never clear then the Vec it'll keep growing, that's why it can't be enabled by default. And yes the filter will take more and more time. But if you clear regularly then it shouldn't take a big amount of time, the filter is iterating a single Vec which is fast.
  3. u32::Max / 2 was supposed to be the window where tracking is valid but as I'm writing this and try to come up with an example I'm not sure this window is useful.
    The tracking counter wraps on overflow so I was using half the full u32 range to be safe when getting close to the max value.
    Let's say you have your current at 1 and you have last_run at u32::MAX - 1.
    But since the counter is global, you can't get ViewMut in parallel and the counter only increases then I don't think there can be any problem using the full range.
    You can see the same kind of logic here: https://github.com/bevyengine/bevy/blob/c3a46822e14003970e2de0ea20ca09839a64d913/crates/bevy_ecs/src/change_detection.rs.
    If I can't find a good example of this I'll change the implementation to something like that:
fn is_track_within_bounds(timestamp: u32, last: u32, current: u32) -> bool {
    let bounds = current.wrapping_sub(last);
    let track = current.wrapping_sub(timestamp);

    track < bounds
}

from shipyard.

PudgeKim avatar PudgeKim commented on June 3, 2024

Then the loop ends and when system2 gets a View<ComponentA> again it has a current counter of 11 and a last_counter of 9.

In this part, why last_counter is 9?? I think it would be 4.
Don't you mean second loop?

-----edited--------

ah, I understand. last_run will be 4 ?
So last_counter means last_insert or last_modification or last_removal_or_deletion in View struct?

from shipyard.

leudz avatar leudz commented on June 3, 2024

Yes 4 not 9 It's 1 right? 🤦‍♂️ (Only the run counter is global not the last_run one)
And yes "last_run counter" not "last_counter".

So last_counter means last_insert or last_modification or last_removal_or_deletion in View struct?

It's all of them in workloads, outside each one has a different last_run counter and the View will use them.
You can see it here:

shipyard/src/borrow/mod.rs

Lines 223 to 226 in 54009de

last_insert: last_run.unwrap_or(sparse_set.last_insert),
last_modification: last_run.unwrap_or(sparse_set.last_modification),
last_removal_or_deletion: last_run
.unwrap_or_else(|| current.wrapping_sub(u32::MAX / 2)),
.
last_run is Some in workloads so that's the value used, and if it's None then we'll look inside SparseSet to get the last time a clear_* call was used.

from shipyard.

PudgeKim avatar PudgeKim commented on June 3, 2024

ah..? 1?

So when system10 runs it has a current counter of 9 (it starts at 0) and a last_run counter of 3.

So In this part, 3 also should be 1??

why is it 1..? Some global struct has last_run field. It'll count whenever View<ComponentA> is called. There are 3 systems which contain View<ComponentA>. So last_run is 3.
Doesn't this what you mean?

I'm confused now lol

from shipyard.

leudz avatar leudz commented on June 3, 2024

It should be... 0 (it doesn't have a last_run yet so it starts at 0).
Sorry I messed up all numbers >_<

The run counter is global, it increases each time a system runs and starts at 1 (not 0 like I said before). That will be 1 for system1, then 2 for system2,... and system10 is 10. Then second loop, system1 is 11 then system2 is 12,... and system10 will be 20.

At the same time each of these system has a last_run counter. They all start at 0 and during the first loop, they are all at 0. Then second loop, system1 will be 1, system2 will be 2,... and system10 will be 10.

from shipyard.

PudgeKim avatar PudgeKim commented on June 3, 2024

Ok run counter is increased whenever any system is called. If system1 is called twice in one loop, is it increased twice?

and I don't still understand last_run counter. why system2 will be 2, .. and system10 will be 10 in second loop?
You said each system has a last_run counter. so I think all system's last_run will be 1 in second loop if last_run was 0 in the first loop.

from shipyard.

leudz avatar leudz commented on June 3, 2024

Ok run counter is increased whenever any system is called. If system1 is called twice in one loop, is it increased twice?

Yes

last_run counter is storing what the run counter value was the last time this system ran. Maybe it's not really the right name to call it a counter, it doesn't really count anything, it's more a timestamp.

let current = world.get_current();
let last_run = last_run.swap(current, Ordering::Acquire);

Here you can see that last_run store the value of current.

from shipyard.

PudgeKim avatar PudgeKim commented on June 3, 2024

ah it gets world's current so each system's last_run is increased even different systems ran before.
I understand now.

from shipyard.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.