BeanCheeseBurrito / Flecs.NET

A C# wrapper for flecs
MIT License
145 stars 18 forks source link

Consistent freeze when using .MultiThreaded (and sometimes crash) on world.Progress() #48

Closed deathbeam closed 1 week ago

deathbeam commented 3 weeks ago

After few cycles the world.Progress() just never returns, probably waiting on some lock. I had crashes before with multithreaded as well, but now its just freeze. Only 2 multithreaded systems are these 2:

    public static void Move(World world)
    {
        world
            .System<Velocity, Position>("Move")
            .MultiThreaded()
            .Each(
                (Iter it, int i, ref Velocity v, ref Position p) =>
                {
                    p.X += it.DeltaTime() * v.X;
                    p.Y += it.DeltaTime() * v.Y;
                }
            );
    }

    public static void RandomDestination(World world, Random random)
    {
        world
            .System<Position, Destination, Velocity>("RandomDestination")
            .Without<GridPath>()
            .MultiThreaded()
            .Each(
                (ref Position p, ref Destination d, ref Velocity v) =>
                {
                    v.X = 0;
                    v.Y = 0;
                    d.X = p.X + random.Next(-100, 100);
                    d.Y = p.Y + random.Next(-100, 100);
                }
            );
    }

When i Remove .MultiThreaded on both the freeze stops. My world has 2 threads set:

        world.SetThreads(2);

The more entities I have the faster the lockup happens.

My loop mostly looks like this:

        using var world = World.Create();
        world.SetThreads(2);

        // Do i need this? Apparently cant register components in multi treaded
        world.Component<Position>();
        world.Component<Map>();
        world.Component<Layer>();
        world.Component<Translate>();
        world.Component<Scale>();
        world.Component<Velocity>();
        world.Component<Source>();
        world.Component<Texture>();
        world.Component<Light>();
        world.Component<Occluder>();
        world.Component<Collider>();
        world.Component<GridPath>();
        world.Component<Destination>();
        world.Component<Camera>();
        world.Component<Tint>();

#if DEBUG
        world.Import<Ecs.Units>();
        world.Import<Ecs.Stats>();
        world.Set(default(flecs.EcsRest));
#endif

        // Some other stuff...

        // Flecs Systems register
        Systems.UpdateCamera(world, renderer);
        Systems.DisableEntities(world, grid);
        Systems.RandomDestination(world, random);
        Systems.FindPaths(world, grid);
        Systems.FollowPaths(world, grid);
        Systems.Move(world);
        Systems.ProcessOccluders(world, renderer);
        Systems.ProcessColliders(world, grid);
        var drawTextures = Systems.DrawTextures(world, renderer);
        var drawLights = Systems.DrawLights(world, renderer);
        var drawPaths = Systems.DrawPaths(world, grid);
        var drawGrids = Systems.DrawGrid(world, grid);

        // Do stuff
        while (!Raylib.WindowShouldClose())
        {
            var delta = Raylib.GetFrameTime();
            Console.WriteLine("Before progress");
            world.Progress(delta);
            Console.WriteLine("After progress");

            // Manually calling textures and light systems later and some other rendering stuff
        }
deathbeam commented 2 weeks ago
* thread #1, name = 'Game', stop reason = signal SIGSEGV: address not mapped to object
  * frame #0: 0x00007c8e6c7d308b libcoreclr.so`___lldb_unnamed_symbol15044 + 27
    frame #1: 0x00007c8e6c7e761f libcoreclr.so`___lldb_unnamed_symbol15373 + 255
    frame #2: 0x00007c8e6c7e6bf5 libcoreclr.so`___lldb_unnamed_symbol15363 + 469
    frame #3: 0x00007c8e6cb5d1d0 libc.so.6`___lldb_unnamed_symbol3369 + 1
    frame #4: 0x00007c8e6c542caf libcoreclr.so`___lldb_unnamed_symbol6240 + 47
    frame #5: 0x00007c8def5d7024
    frame #6: 0x00007c8def5d6fd2
    frame #7: 0x00007c8def5f5b8d
    frame #8: 0x00007c8def5f5b1d
    frame #9: 0x00007c8e6b77cfa9 libflecs.so`flecs_run_intern(world=0x00005871f50fcb20, stage=0x00005871f5503800, system=104725, system_data=0x00005871f661f190, stage_index=3, stage_count=32, delta_time=0.299937189, param=0x0000000000000000) at flecs.c:63450:21
    frame #10: 0x00007c8e6b77cabf libflecs.so`flecs_run_pipeline_ops(world=0x00005871f50fcb20, stage=0x00005871f5503800, stage_index=3, stage_count=32, delta_time=0.299937189) at flecs.c:52930:9
    frame #11: 0x00007c8e6b77ec1a libflecs.so`flecs_worker(arg=0x00005871f5503800) at flecs.c:53360:9
    frame #12: 0x00007c8e6cbb439d libc.so.6`___lldb_unnamed_symbol3666 + 941
    frame #13: 0x00007c8e6cc3949c libc.so.6`___lldb_unnamed_symbol4097 + 7

managed to get some stacktrace i think.

Currently was testing on this:

        world
            .System<Position>("CullEntities")
            .Kind(Ecs.PostLoad)
            .MultiThreaded()
            .Rate(2)
            .TermAt(0)
            .In()
            .With(Ecs.Disabled)
            .Optional()
            .InOut()
            .With<Camera>()
            .Singleton()
            .In()
            .Each(CullEntities);

The body of cullentities is empty:

    private static void CullEntities(ref Position position)
    {
        Logger.Debug("CullEntities");

        // var camera = it.World().Get<Camera>();
        // var (left, top, right, bottom) = camera.GetBounds(CameraOffset);
        //
        // foreach (int i in it)
        // {
        //     var pos = positions[i];
        //     var entity = it.Entity(i);
        //     if (pos.X < left || pos.X > right || pos.Y < top || pos.Y > bottom)
        //     {
        //         entity.Disable();
        //     }
        //     else
        //     {
        //         entity.Enable();
        //     }
        // }
    }
BeanCheeseBurrito commented 2 weeks ago

I feel it could be related to this issue that I'm currently working on https://github.com/BeanCheeseBurrito/Flecs.NET/issues/50.

BeanCheeseBurrito commented 2 weeks ago

I feel it could be related to this issue that I'm currently working on #50.

Small update. I was able to reproduce it on my end and it looks like the changes on the binding-context-fix branch fixed the crashes with multithreaded systems. I believe https://github.com/BeanCheeseBurrito/Flecs.NET/issues/49 and https://github.com/BeanCheeseBurrito/Flecs.NET/issues/45 are also fixed by these changes.

deathbeam commented 2 weeks ago

I feel it could be related to this issue that I'm currently working on #50.

Small update. I was able to reproduce it on my end and it looks like the changes on the binding-context-fix branch fixed the crashes with multithreaded systems. I believe #49 and #45 are also fixed by these changes.

Oh awesome, will try that branch and report back

deathbeam commented 2 weeks ago

Ok tried bunch of stuff and on your branch I cant reproduce #48, #45 or #49 anymore, amazing job.

deathbeam commented 1 week ago

Fixed by #54, closing