Post by Admin on Jul 16, 2016 4:14:41 GMT
movrajr @movrajr Sep 14 2015 05:28
I've compared the performance of Unity's original Roguelike project to JamesMcMahon's Entitas version (https://github.com/JamesMcMahon/entitas-2d-roguelike). The result is in this image album: imgur.com/a/QUU9G
Seems like AddComponent() incurs a relatively large performance hit. It could quickly spiral out of control with a large pool of complex entities.
I wonder if it's possible to somehow merge the components into one master component.
movrajr @movrajr Sep 14 2015 05:37
The smaller spikes following the 2 largest spikes are from moving the player character. The Entitas version also has a larger footprint in those smaller spikes, even in the standalone build where the debug monitor is disabled.
So while you could spread out the initialization of the entities over a number of frames through coroutines and masking the resulting delay behind a splash screen, run-time performance is perhaps also a concern. I'd have to take a closer look.
astro75 @astro75 Sep 14 2015 05:47
Did you disable Entitas.Unity.VisualDebugging ?
movrajr @movrajr Sep 14 2015 05:49
That should have no influence on the standalone build, should it?
astro75 @astro75 Sep 14 2015 05:49
I did tests on Match-One. VisualDebugging slowed down everything by at least an order of magnitude.
movrajr @movrajr Sep 14 2015 05:50
My problem is with Unity's AttributeHelperEngine and Entitas heavily depends on it.
In the bottom screenshot I've drilled down to the creation of the components.
astro75 @astro75 Sep 14 2015 05:53
This is in Unity's GameObject.AddComponent. I thought Entitas does not rely on unity game objects.
movrajr @movrajr Sep 14 2015 05:56
Hm, I've removed the visual debugging now. There's still a lot of GC Allocations: 186.5 KB, but now the source is elsewhere.
astro75 @astro75 Sep 14 2015 05:58
will you post a screenshot?
movrajr @movrajr Sep 14 2015 06:00
Working on it.
astro75 @astro75 Sep 14 2015 06:00
The only place I found in entitas where constant GC allocation could happen is group.getAllEntities
movrajr @movrajr Sep 14 2015 06:01
i.imgur.com/SZUz5YS.png
Now I can't pinpoint a single source of alloc anymore, it's all over the place. But it's definitely a lot more than the original version. 175 KB vs 1.5 KB.
At least the AddComponent doesn't seem to be a problem anymore after removing Visual Debugging.
astro75 @astro75 Sep 14 2015 06:09
It seems like most of it is not caused by Entitas directly.
movrajr @movrajr Sep 14 2015 06:11
Indeed, the smaller spike can be attributed to the implementation of the AudioComponent. Converting an Array to an IEnumerable and back to an Array through LINQ.
There are some smaller sources of allocations such as Group.addEntity() @ 24.3 KB/1 ms.
Maybe it's more efficient for me to create a new Entitas project and measure performance properly.
astro75 @astro75 Sep 14 2015 06:17
What are you trying to accomplish exactly?
movrajr @movrajr Sep 14 2015 06:19
The Entitas version of this Roguelike example has a 100 times larger GC alloc value than the original. I'm concerned about how that scales in a larger project. But first I have to make sure the problem is not with JamesMcMahon's implementation.
astro75 @astro75 Sep 14 2015 06:19
Did you watch entitas presentation video?
movrajr @movrajr Sep 14 2015 06:20
No, I watched it on location.
How so?
astro75 @astro75 Sep 14 2015 06:20
They made code generator just to deal with GC
And the whole codebase is not large so you can find where garbage is created just by analyzing the code
movrajr @movrajr Sep 14 2015 06:22
Let's see, it's somewhere around 22:00 in the video.
Before optimization: 164 KB/11 ms. After optimization: 46 KB/13 ms
Granted, the later versions have more improvements since the presentation.
movrajr @movrajr Sep 14 2015 06:28
OK, majority of GC alloc currently appears to be coming from HashSet.Resize ().
astro75 @astro75 Sep 14 2015 06:30
In the second image yellow spikes are gone, but we should see about 2 of them according to the numbers. It is unclear at which frame the snapshot is taken.
movrajr @movrajr Sep 14 2015 06:34
I see. So before optimization there were runtime allocations causing the GC to be triggered every few frames. After optimization the alloc value is 46 KB but maybe it's the first and only frame where gameobjects are created. The GC isn't triggered during runtime anymore.
astro75 @astro75 Sep 14 2015 06:35
Probably.
Or maybe it is triggered, but at much bigger intervals
The only garbage concern I have is in this line: github.com/sschmid/Entitas-CSharp/blob/develop/Entitas/Entitas/Group.cs#L106
movrajr @movrajr Sep 14 2015 06:43
That is causing constant run-time allocations?
astro75 @astro75 Sep 14 2015 06:44
It will cause if you use that method
movrajr @movrajr Sep 14 2015 06:45
Aha, I guess every frame the _entitiesCache array is set to null.
astro75 @astro75 Sep 14 2015 06:46
It may be more frequent
movrajr @movrajr Sep 14 2015 06:46
Indeed, whenever the other methods in the class are called
Better to clear the array and resize if needed?
astro75 @astro75 Sep 14 2015 06:47
not really
this would cause bugs
and resizing array is the same as creating a new one
movrajr @movrajr Sep 14 2015 06:48
But at least it only happens when the number of elements changes.
But that would make performance less predictable too.
astro75 @astro75 Sep 14 2015 06:51
You can't modify the same array because it might be used somewhere else in a call stack
my solution would be to have a List instead of array, and use a system similar to Entity.retain/release on the whole lists
But this allocation might not even be a problem
It depends on concrete project
Simon Schmid @sschmid Sep 14 2015 17:26
I just quickly deep profiled roguelike, too. My results:
There are a few implementation specific things that cause the gc allocations. When I move it’s mostly AudioComponent.cs
When starting the game, I see hits from ResourceComponent.cs, CreateGameBoardSystem.cs and others.
The only hits I see from Entitas is the initial pool.CreateEntity() and the HashSetResize in group when adding the views
When idle, there’s 0.0 gc alloc.
When profiling, make sure to comment out these lines in Pools.cs and to use Systems instead of DebugSystem, since they will have some overhead which won’t be in a release build
astro75 @astro75 Sep 14 2015 18:13
I've started using my new roslyn generator in our prototype game. Found some bugs and fixed them. If anyone wants to try github.com/astro75/Entitas-CSharp/tree/roslyn-syntaxanalyzer-generator
Simon Schmid @sschmid Sep 14 2015 18:21
Awesome!
I've compared the performance of Unity's original Roguelike project to JamesMcMahon's Entitas version (https://github.com/JamesMcMahon/entitas-2d-roguelike). The result is in this image album: imgur.com/a/QUU9G
Seems like AddComponent() incurs a relatively large performance hit. It could quickly spiral out of control with a large pool of complex entities.
I wonder if it's possible to somehow merge the components into one master component.
movrajr @movrajr Sep 14 2015 05:37
The smaller spikes following the 2 largest spikes are from moving the player character. The Entitas version also has a larger footprint in those smaller spikes, even in the standalone build where the debug monitor is disabled.
So while you could spread out the initialization of the entities over a number of frames through coroutines and masking the resulting delay behind a splash screen, run-time performance is perhaps also a concern. I'd have to take a closer look.
astro75 @astro75 Sep 14 2015 05:47
Did you disable Entitas.Unity.VisualDebugging ?
movrajr @movrajr Sep 14 2015 05:49
That should have no influence on the standalone build, should it?
astro75 @astro75 Sep 14 2015 05:49
I did tests on Match-One. VisualDebugging slowed down everything by at least an order of magnitude.
movrajr @movrajr Sep 14 2015 05:50
My problem is with Unity's AttributeHelperEngine and Entitas heavily depends on it.
In the bottom screenshot I've drilled down to the creation of the components.
astro75 @astro75 Sep 14 2015 05:53
This is in Unity's GameObject.AddComponent. I thought Entitas does not rely on unity game objects.
movrajr @movrajr Sep 14 2015 05:56
Hm, I've removed the visual debugging now. There's still a lot of GC Allocations: 186.5 KB, but now the source is elsewhere.
astro75 @astro75 Sep 14 2015 05:58
will you post a screenshot?
movrajr @movrajr Sep 14 2015 06:00
Working on it.
astro75 @astro75 Sep 14 2015 06:00
The only place I found in entitas where constant GC allocation could happen is group.getAllEntities
movrajr @movrajr Sep 14 2015 06:01
i.imgur.com/SZUz5YS.png
Now I can't pinpoint a single source of alloc anymore, it's all over the place. But it's definitely a lot more than the original version. 175 KB vs 1.5 KB.
At least the AddComponent doesn't seem to be a problem anymore after removing Visual Debugging.
astro75 @astro75 Sep 14 2015 06:09
It seems like most of it is not caused by Entitas directly.
movrajr @movrajr Sep 14 2015 06:11
Indeed, the smaller spike can be attributed to the implementation of the AudioComponent. Converting an Array to an IEnumerable and back to an Array through LINQ.
There are some smaller sources of allocations such as Group.addEntity() @ 24.3 KB/1 ms.
Maybe it's more efficient for me to create a new Entitas project and measure performance properly.
astro75 @astro75 Sep 14 2015 06:17
What are you trying to accomplish exactly?
movrajr @movrajr Sep 14 2015 06:19
The Entitas version of this Roguelike example has a 100 times larger GC alloc value than the original. I'm concerned about how that scales in a larger project. But first I have to make sure the problem is not with JamesMcMahon's implementation.
astro75 @astro75 Sep 14 2015 06:19
Did you watch entitas presentation video?
movrajr @movrajr Sep 14 2015 06:20
No, I watched it on location.
How so?
astro75 @astro75 Sep 14 2015 06:20
They made code generator just to deal with GC
And the whole codebase is not large so you can find where garbage is created just by analyzing the code
movrajr @movrajr Sep 14 2015 06:22
Let's see, it's somewhere around 22:00 in the video.
Before optimization: 164 KB/11 ms. After optimization: 46 KB/13 ms
Granted, the later versions have more improvements since the presentation.
movrajr @movrajr Sep 14 2015 06:28
OK, majority of GC alloc currently appears to be coming from HashSet.Resize ().
astro75 @astro75 Sep 14 2015 06:30
In the second image yellow spikes are gone, but we should see about 2 of them according to the numbers. It is unclear at which frame the snapshot is taken.
movrajr @movrajr Sep 14 2015 06:34
I see. So before optimization there were runtime allocations causing the GC to be triggered every few frames. After optimization the alloc value is 46 KB but maybe it's the first and only frame where gameobjects are created. The GC isn't triggered during runtime anymore.
astro75 @astro75 Sep 14 2015 06:35
Probably.
Or maybe it is triggered, but at much bigger intervals
The only garbage concern I have is in this line: github.com/sschmid/Entitas-CSharp/blob/develop/Entitas/Entitas/Group.cs#L106
movrajr @movrajr Sep 14 2015 06:43
That is causing constant run-time allocations?
astro75 @astro75 Sep 14 2015 06:44
It will cause if you use that method
movrajr @movrajr Sep 14 2015 06:45
Aha, I guess every frame the _entitiesCache array is set to null.
astro75 @astro75 Sep 14 2015 06:46
It may be more frequent
movrajr @movrajr Sep 14 2015 06:46
Indeed, whenever the other methods in the class are called
Better to clear the array and resize if needed?
astro75 @astro75 Sep 14 2015 06:47
not really
this would cause bugs
and resizing array is the same as creating a new one
movrajr @movrajr Sep 14 2015 06:48
But at least it only happens when the number of elements changes.
But that would make performance less predictable too.
astro75 @astro75 Sep 14 2015 06:51
You can't modify the same array because it might be used somewhere else in a call stack
my solution would be to have a List instead of array, and use a system similar to Entity.retain/release on the whole lists
But this allocation might not even be a problem
It depends on concrete project
Simon Schmid @sschmid Sep 14 2015 17:26
I just quickly deep profiled roguelike, too. My results:
There are a few implementation specific things that cause the gc allocations. When I move it’s mostly AudioComponent.cs
When starting the game, I see hits from ResourceComponent.cs, CreateGameBoardSystem.cs and others.
The only hits I see from Entitas is the initial pool.CreateEntity() and the HashSetResize in group when adding the views
When idle, there’s 0.0 gc alloc.
When profiling, make sure to comment out these lines in Pools.cs and to use Systems instead of DebugSystem, since they will have some overhead which won’t be in a release build
astro75 @astro75 Sep 14 2015 18:13
I've started using my new roslyn generator in our prototype game. Found some bugs and fixed them. If anyone wants to try github.com/astro75/Entitas-CSharp/tree/roslyn-syntaxanalyzer-generator
Simon Schmid @sschmid Sep 14 2015 18:21
Awesome!