First sorry for my English which is not my native language.
I would like to submit a very strange performance problem I get with Unity 5 (tested with beta 19 & beta 20) on Windows 7 64 bits (editor + player). I don’t have Unity 4 to test this.
I’m evaluating Unity 5 for my company not for building a game but for building a sort of visualization application for “vehicles” (think cars but not only) on a map in 3D (well at least “2.5D”). We are trying to see if Unity could replace our current implementation which works with Silverlight and is 2D only.
The map is based on a tiling system I’ve written in C# that work exactly the same way as deep zoom, or google earth or cesium JS.
The map is 2D, so we add static 3D buildings on it (meshes) just like google earth. This is not done yet.
We can colourize some roads using transparent textures displayed just above (done).
The vehicles can be hundreds at a time and move in realtime (or faster that realtime), and each one is a 3d mesh with a sticker (billboard with various content) floating above. My current testing prototype have 2000 objects with plenty that move in 3D world.
Currently we don’t use any lighting (not tested yet).
We have very strict performance constraints for this application, since :
- it should work on windows laptops or tablets without draining too much batteries
- some instances of it could be deployed in vehicles on embedded PC which are not very powerful (Core i3 + HD 4000) and must not heat too much (passive cooling).
I’m a performance nut, so I’ve optimized every bit of C# script we use for tiling system, mobiles and billboarding using the built-in Unity pro profiler. Nearly everything is procedural in my prototype. I know that my scripts run fast and don’t do anything when not needed. Really.
Currently we have no problem at all getting very good framerate on this prototype (150 to 300 FPS depending on hardware with 2000 objects if we unlock vsync) and are very pleased with that.
But at the same time, we also get very high CPU usage (15% to 30%, which means one core out of for) for no apparent reason, and NOT ALWAYS. Because I’ve found (by accident) a way to get less than 1% CPU with same object count and high framerate by doing a very simple thing I will explain but this does only work in the editor, not on a standalone Windows player …
I could reproduce this behaviour on 2 completely different PCs with very different hardware :
- Intel XEON E5540 (4 cores) + AMD ATI FIREPRO 4800 (my dev pc, don’t laugh …)
- Core i7 notebook (4 cores) + NVIDIA K3000M
Here we go. If I run the application with vsync on (QualitySettings.vSyncCount=1) in editor, I get a solid 60 fps (520 draw calls with a lot of dynamic batching, 3.0ms render thread, <1ms scripts), but also 20% CPU (nearly one core).
Now here come the real strangeness … If I simply insert one System.Threading.Thread.Sleep(1) (1ms sleep) in a gameobject’s LateUpdate, then (tada), CPU drops to less than 1% (0.7% to be precise) … I’m not crazy my cpu measurements are correct (process explorer + task explorer + in app measure using Mono all agree).
Let’s continue with QualitySettings.vSyncCount=0 and Application.targetFrameRate=0 (no sync, full speed) still in editor :
- I get 150 fps on my slow dev pc (520 draw calls with a lot of dynamic batching, 3.0ms render thread, <1ms scripts), and 40-50% CPU. We are running full speed so this is understandable.
- Now if I rerun with 1ms sleep, I get 100 fps and 0.7% CPU with exactly the same scene !!! The app is plenty smooth objects animate at 100 fps, everything flies…
Now even more strange. I CAN’T reproduce this in standalone player. And badly, the player always consumes at least 20% cpu getting the same framerate as the editor. If I insert sleeps in code, it will lower the framerate (depending on vsync activation), the longer the wait the lower the framerate, but in NO WAY I can get 1% cpu. Never.
My understanding on all of this, is that there must be some sort of “spinwait” between main thread and render thread inside Unity or between Unity and DX layer that cause this high CPU consumption.
So I tried to understand with the profiler what was the difference between application executed in editor, and in standalone player. Here is what I saw:
When running in editor (in timeline mode) on my crappy dev pc:
- on the main thread, the only measurable script is my “sleep”, and camera render last 3.4ms
- on the render thread, I see only two Gfx.ProcessCommands for a total time of 2.4ms, and some Gfx.DrawDynamicBatch inside
- the render thread always finish its work before the start of next frame in the main thread
When running in standalone app (in timeline mode):
- on the main thread, the only measurable script is my “sleep”, and camera render last 3.3ms
- on the render thread, I see two Gfx.ProcessCommands, the first is a short one of 1.2ms as in editor but the second cost 7.5ms because it calls Gfx.PresentFrame which lasts 5.3ms. What does Gfx.PresentFrame do ? Could the spinwait be here ?
- the render thread does finish its work after the start of next frame in the main thread. This is strange and another difference with editor
I also tried a Windows native profiler named “Very Spleepy” but didn’t find anything conclusive. I see mostly two threads working.
To add a little bit of strangeness, I also have to explain that when I start the editor, I can’t simply get at first <1% CPU by running my app with 1ms sleep. I first must try many sleep values during the run until suddently the cpu will drop to 1% (I added a keyboard control to make a variable sleep in app for this). As soon as the cpu is <1%, I can run the app as many times as I want for all my session with 1ms wait and it will always “work” …
What I have also tested and discovered :
- Quality settings play no role (fantastic, good, simple, etc…) same behaviour
- DX9 instead of DX11. Same behaviour
- Same behaviour without dynamic batching, except that as soon as drawed object count on viewport exceed some limit (let’s say 1000), the CPU rise sharply
- The ability to get <1% cpu seems to depends on drivers settings related to vsync in windows control panel at least with nvidia hardware. On nvidia k3000m I could not get less than 1% without forcing vsync off in nvidia control panel.
I would be very grateful if someone from Unity could shed some light on this, and will be happy to provide any input needed for that.
Beta 21 just appeared, I will try it.