Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question ISystem vs SystemBase?

Discussion in 'Entity Component System' started by CodeMonkeyYT, Nov 5, 2022.

  1. CodeMonkeyYT

    CodeMonkeyYT

    Joined:
    Dec 22, 2014
    Posts:
    121
    Hey everyone
    I'm trying to understand the difference between ISystem and SystemBase.
    According to the docs the only difference is SystemBase is meant for Managed systems and ISystem is meant for Unmanaged systems but I'm not entirely sure what that difference entails.

    Does it just mean, if working with Game Objects or any objects, use SystemBase; if working entirely with Entities, use ISystem?

    However the docs also show SystemBase being used in an example with no objects at all https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/systems-systembase.html
    And ISystem doesn't have any example in the docs and also doesn't seem to have the easy to use Entities.ForEach();

    Perhaps the difference is an ISystem can use Burst and SystemBase cannot?

    So can anyone help me understand the differences, when to use one versus the other?
    Thanks!
     
    Eristen, Kaivaan, gcapeletti and 4 others like this.
  2. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    You’ve got it - the main benefit of ISystem is that its OnCreate(), OnDestroy(), and OnUpdate() methods can be Burst compiled.

    Especially the OnUpdate() method is a large benefit, since it lets you run Bursted code on the main-thread, without scheduling a job.
     
  3. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    Also, Entities.ForEach is not supported at all in ISystem (or it won’t be in the final 1.0 release). It looks like Unity it moving away from it completely, in favor of idiomatic foreach, and IJobEntity.
     
  4. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    791
    Entities.ForEach() is going to be deprecated in SystemBase.

    ISystem
    has other differences SystemState and SystemAPI.

    You will find that you use IJobEntity alot now.
     
  5. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    939
    Last I heard from unite there is no plan to deprecate Entities.ForEach :
    upload_2022-11-5_22-36-20.png
    But it will not be suported by ISystem.

    ISystem and Idiomatic foareach are covered by episode 6 of my tutorial series.
    I also go over some differences between SystemBase and ISystem

     
    Last edited: Nov 5, 2022
    Daxode and Sky_Higher like this.
  6. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    791
    Entities.ForEach() is planned to be deprecated post 1.0


    The biggest takeaway is that there are fewer edge-cases where APIs that work outside of a loop don't work inside, and there’s some behind-the-scenes improvements as well. Entities.ForEach remains in 1.0, but we’re strongly encouraging folks to use idiomatic foreach and jobs instead. To that end, we’re not supporting Entities.ForEach in ISystem (it will remain in SystemBase) and plan to phase out support post 1.0.


    https://forum.unity.com/threads/exciting-developments-in-upcoming-entities-1-0-releases.1341071/
     
    toomasio likes this.
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    ISystem has more boilerplate, but offers more performance if you Burst-compile its methods. It is especially useful either for lots of tiny systems, or for main-thread heavy systems (such as lots of synchronous structural changes with EntityManager).

    For prototyping or game jams, SystemBase is much easier to use.

    For larger games, most systems should be ISystem.
     
    elliotc-unity, xVergilx, RaL and 2 others like this.
  8. CodeMonkeyYT

    CodeMonkeyYT

    Joined:
    Dec 22, 2014
    Posts:
    121
    Alright so the main difference is being Burstable so ideally use ISystem with a IJobForEntity, alternatively for less intensive work use SystemBase with idiomatic foreach.

    Some feedback for the DOTS team: This should have more clarification on the docs and it should have examples, I only know about idiomatic foreach because I read it in the new tutorial docs https://github.com/Unity-Technologi...blob/master/DOTS_Guide/ecs_tutorial/README.md
    Apparently the reason Entities.ForEach still exists is because IFE is not yet at feature parity.

    Thanks everyone!
     
    KANIYO, OUTTAHERE and MrRedpearl like this.
  9. Sunstrace

    Sunstrace

    Joined:
    Dec 15, 2019
    Posts:
    40
    if need to do something with other managerd types,for example,use textures,or unity other classes,systembase is the only way.
     
    lclemens likes this.
  10. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    Worth noting that the Unity team seems to be promoting ISystem as the default way to work, always. Going forward, they recommend using SystemBase only in cases where ISystem can't work or is too cumbersome - like if you need to work with managed components.

    Having worked exclusively with ISystem for a while now - it's actually very possible. I have yet to run into a case where the system I was writing couldn't be an ISystem, and that has come with large performance benefits.
     
  11. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    943
    We are heavily using SystemBase as a kind of reducing boilerplate through template pattern. This cannot be done with ISystem structs.
     
    deus0 likes this.
  12. CarryBrick

    CarryBrick

    Joined:
    Nov 24, 2020
    Posts:
    1
    Nice post share,every say's are useful.:)
    I suppose DOTS Team will do more work on ISystem instead SystemBase.
     
  13. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    262
    I am still fully on SystemBase (with ECS 0.51), but this is mainly because it used to be the recommended way. And the update path from 0.17-> 0.50 -> 0.51, was most convenient just to keep it. With 1.0 and the removal of the Entities.ForEach, it will take more time to upgrade, but ISystem seems the best default option.

    So when reading stuff in the docs or on the forum it might just be out of date when SystemBase is recommended for a situation, since ISystem was not available yet.
     
  14. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    ISystemBase ISystem is more optimise for scheduling jobs, as well as whole system can be bursted. However, you want use idiomatic approach only in ISysteBase ISystem.
    I don't know if it can be properly bursted in SystemBase.

    If you want to use Entities.ForEach, which also gives you multithreading and can take .WithName, which is very handy when it comes to profiling. In such case use SystemBase. I don't get it, why idiomatic foreach don't get naming capability.

    Besides, very well done tutorial, with step by step showcase.

    One bit is missing for me, when you looked into profiler, I would love to see, if there are any idiomatic foreach for comparison with jobs, or Entities.ForEach. That would give the idea, how they are handled differently by profiler.
     
    Last edited: Nov 10, 2022
  15. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    262
    From what I read in other threads this is not true anymore for > ECS 1.0.

     
  16. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    You can use Entities.Foreach in SystemBase, as usual. Here nothing changes in that matter in 1.0.
    Means, you can multithread it.
    Entities.Foreach will most likely not work with ISystemBase ISystem. Hence Unity recommends using idiomatic foreach and jobs instead.
     
    Last edited: Nov 10, 2022
  17. Spy-Master

    Spy-Master

    Joined:
    Aug 4, 2022
    Posts:
    283
  18. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    Not entailer true.
    While in
    [0.50.0] - 2021-09-17
    https://docs.unity3d.com/Packages/com.unity.entities@1.0/changelog/CHANGELOG.html#changed-7
    doc states that it changed "ISystemBase to ISystem"

    0.51.0 has both ISystemBase and ISystem. Only that ISystemBase is marked as depreciated, until 2022.08.30. hats only recently.
    Hence it is technically still valid. However only for 0.50.x and 0.51.x.

    Per say, 1.0 is using indeed ISystem. Which I have corrected as per above note.
     
  19. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,875
  20. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,626
    Can't get the boilerplate to nothing but you can certainly reduce boilerplate to very minimal and share logic between ISystems by moving logic to a standalone struct.
    For example

    Code (CSharp):
    1. [BurstCompile]
    2. [UpdateInGroup(typeof(EffectUpdateSystemGroup))]
    3. [UpdateBefore(typeof(EffectActiveSystem))]
    4. public partial struct EffectDurationSystem : ISystem
    5. {
    6.     private Timer<EffectActiveOnDuration, EffectActiveDurationRemaining, EffectActive, EffectActiveDuration> impl;
    7.  
    8.     [BurstCompile]
    9.     public void OnCreate(ref SystemState state)
    10.     {
    11.         this.impl.OnCreate(ref state);
    12.     }
    13.  
    14.     [BurstCompile]
    15.     public void OnUpdate(ref SystemState state)
    16.     {
    17.         this.impl.OnUpdate(ref state);
    18.     }
    19.  
    20.     public void OnDestroy(ref SystemState state) { }
    21. }
    ISystem is definitely worth it. You will save milliseconds of frame time in a large project which is ridiculous.
     
    Last edited: Nov 20, 2022
    MadeFromPolygons and davenirline like this.
  21. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,594
    can ISystem systems be disabled like it used to happen with SystemBase?
     
  22. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    SystemState has a Disabled property if that's what you are asking.
     
    bb8_1 and Anthiese like this.
  23. Jonas_DM_

    Jonas_DM_

    Joined:
    Feb 28, 2019
    Posts:
    22
    Like Tertle said, the key to reducing boilerplate is to move your logic to a standalone struct.

    But you can also re-use it in SystemBase classes while having it BurstCompiled still!
    SystemBase is still useful in a lot of cases. And in some cases it can be nice to BurstCompile a part of your SystemBase Update.

    The pattern I recently used for making reusable system code was:

    Code (CSharp):
    1. public struct MyReusableSystemState
    2. {
    3.     // Burstable fields like:
    4.     // int, bool,
    5.     // EntityQueries, NativeContainers, ComponentLookups, etc.
    6.  
    7.     public void OnCreate(ref SystemState state)
    8.         {// Reusable Initialization}
    9.  
    10.     public void OnUpdate(ref SystemState state)
    11.         {// Reusable Update}
    12.  
    13.     public void OnDestroy(ref SystemState state)
    14.         {// Reusable Cleanup}
    15. }
    16.  
    17. [BurstCompile]
    18. public abstract unsafe partial class MyReusableSystemBase : SystemBase
    19. {
    20.     private MyReusableSystemState _reusableSystemState;
    21.  
    22.     protected override void OnCreate()
    23.     {
    24.         _reusableSystemState.OnCreate(ref CheckedStateRef);
    25.     }
    26.  
    27.     protected override void OnUpdate()
    28.     {
    29.         BurstUpdate((MyReusableSystemState*)UnsafeUtility.AddressOf(ref _reusableSystemState), ref CheckedStateRef);
    30.     }
    31.  
    32.     protected override void OnDestroy()
    33.     {
    34.        _quickSaveSystemState.OnDestroy(ref CheckedStateRef);
    35.     }
    36.  
    37.     [BurstCompile]
    38.     private static void BurstUpdate(MyReusableSystemState* reusableSystemState, ref SystemState systemState)
    39.     {
    40.         reusableSystemState->OnUpdate(ref systemState);
    41.     }
    42. }
    43.  
    This way your API gives the user the decision to use ISystem or SystemBase without sacrificing performance if he chooses to go with SystemBase.
    Most of the time you don't need to be this flexible, but if you're writing code for multiple projects (AssetStore, etc.) this feels like a good approach.
     
    apkdev and PolarTron like this.
  24. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,594
    if I got it right, ISystem implementatione cannot be added manually in a world yet. Can anyone confirm? Documentation should really put more attention on not automatic bootstrap paths.
     
    Last edited: Jan 22, 2023
  25. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    You can totally add an unmanaged system to a world. When working with unmanaged systems, you often work with them indirectly via SystemHandle.
     
  26. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,594
    can you tell me more about SystemHandle please
     
  27. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    It is returned by API's like World.GetOrCreateSystem() and can be used to access system entity components, get a ref to an unmanaged system, resolve a system's SystemState, update unmanaged systems, and a few other things.
     
    elliotc-unity likes this.
  28. TP-Fab

    TP-Fab

    Joined:
    Jul 10, 2019
    Posts:
    37
  29. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Antypodish likes this.
  30. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    Indeed. Here's one example of such a system. This system used to be really slow before ISystem and unmanaged shared components came along. https://github.com/Dreaming381/lsss...ubSystems/Gameplay/SpawnShipsEnqueueSystem.cs
     
  31. TP-Fab

    TP-Fab

    Joined:
    Jul 10, 2019
    Posts:
    37
    Right, thanks! @DreamingImLatios in your example, is there a specific reason you went with an entity query as native arrays rather than using an ECB (or any custom form of deferred change list)?

    Also, you mention your system was slow before. Do you attribute the gain to the unmanaged shared components only? (allowing you to Burst something that you couldn't before)
    -> If so, was it not possible to have avoided shared components altogether?
    -> If not, is there something else that makes this system better with ISystem / unlocks Burst?
     
  32. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    That mostly has to do with the specifics of this project. there are very few factions, but lots of ships that need to be spawned, and I need their Entity handles resolved immediately so that I can put them in the spawn queues. ECB isn't faster than EntityManager. It just defers commands. that's great in parallel if your commands are behind some conditional, but just extra overhead in this case.

    The AddSharedcomponentToLinkedGroup was pretty slow. It still scaled well, because I only called it a couple times per faction rather than for every spawned ship, but it was still impactful on the main thread.
    The shared components accelerate a lot of other parts of the game that have even bigger impacts on performance. Making this an ISystem was a nice little performance boost, but it was by no means the biggest bottleneck in the game.
    Yes as well, because all the looping through factions and figuring out what to do with spawn queues and such got a good performance boost as well. I rarely write managed systems these days. ISystem has gotten a lot better since 1.0.
     
    TP-Fab likes this.
  33. TP-Fab

    TP-Fab

    Joined:
    Jul 10, 2019
    Posts:
    37
    Thanks for the heads up :) Sounds reasonable indeed, I've not been using much of the shared components as we have much less but more complex entities in our project, so we're actively trying to harmonize them rather than "fragmenting" as the shared components do :)

    Regarding the ECB overhead (beside your need for immediate effect that discards using ECBs), you do trade it with the cost of ToEntityArray, as well as all the GetComponent<>(entity) calls (which I guess don't use ComponentLookup, since each AddComponent would invalidate it), without knowing much yet about Entities 1.0 that doesn't sound like a win overall?
     
    Last edited: Mar 3, 2023
  34. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    Lots of ships. Few factions.

    If you dig through that entire project, you'll find I use ECBs and other stuff of that sort quite often as well. It is really just a matter of knowing your data, profiling, and optimizing where the problems lie. At this point, that system isn't really much of a problem anymore compared to other systems, so I don't touch it.
     
    TP-Fab likes this.
  35. TP-Fab

    TP-Fab

    Joined:
    Jul 10, 2019
    Posts:
    37
    Very sensible approach :)

    Thanks for all the details, 1.0 is both fascinating and frustrating so far
     
    MatanYamin likes this.
  36. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    714
    Can you expand on this statement? I'm probably missing something, but it seems like if someone is using SystemBase with IJobEntity , all the important stuff is bursted and runs in jobs except for the function call to create and schedule IJobEntity which is run in the main thread. Since it usually just a line or two of code (MyJob job = new MyJob {...}; job.ScheduleParallel();), it seems to me that it would result in a miniscule amount of time spent calling Update() in the main thread, even for a few hundred systems. Like on the order of a few microseconds. It's true that some OnCreate() and OnDestroy() functions get bursted with ISystem as well, but those are one-time events and typically are just a few lines of initialization. So what makes ISystem so much faster than SystemBase + IJobEntity?
     
  37. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,626
    You can profile this yourself very easily. It takes ~0.05ms for a SystemBase to update and ~0.01ms for a ISystem.

    There are 3 slow parts to systems

    GetDependency - OnBeforeUpdate which gets the dependencies for the system
    AddDependency - OnAfterUpdate which writes the dependencies back from the system
    ScheduleBatchedJobs - OnAfterUpdate which actually sends the jobs off to be scheduled

    I profiled this on my work project like a year ago (note this is 0.51 and job scheduling has likely improved in 2022)

    m_DependencyManager->GetDependency
    179/frame - Median 1.23ms, Mean 1.24ms, Min 1.02ms, Max 1.41ms

    m_DependencyManager->AddDependency
    171/frame - Median 0.20ms, Mean 0.24ms, Min 0.17ms, Max 0.48ms

    JobHandle.ScheduleBatchedJobs
    171/frame - Median 0.62ms, Mean 0.61ms, Min 0.47ms, Max 0.69ms

    Which is over 2ms/frame just on dependency/scheduling without you writing any logic on top or using entity queries to get data etc.
     
    Last edited: Mar 12, 2023
  38. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    714
    Wow - I had no idea!! Thanks so much for sharing that research!