I’m currently using Unity3D to build an iOS app and the other day I decided to do some profiling, just to make sure nothing is taking up crazy amounts of time. What I saw was pretty strange:
Now, if you Google the title of this post, you’ll find quite a few people who are seeing spikes in the Unity3D profiler for something called Overhead and if you follow those links you’ll find that for the most part people aren’t incredibly certain how to make them go away. The Unity3D docs don’t really explain what Overhead represents, but you can see it in the very first image on the page. Some people on the internet seem to think that Overhead includes garbage collection, but I’m pretty good about not creating tons of new objects every frame and others point out GC.Collect is what will show up for that. Also, if you look closely at the legend in the image you’ll see GarbageCollector has its own color.
No, it turned out that the culprit was using UnitySendMessage in a native plugin code! My app has a music system and in order to keep good metronomic time, I run the metronome with native code. This is important because if the metronome is only updated every frame, then you can wind up with wonky rhythm when there are framerate spikes. Lots of things are tied to the metronome in this app, so I needed a way to tell script about “ticks”, which simply means calling script on every sixteenth note. I used a line of code that looked like this:
UnitySendMessage( "Metronome", "Broadcast", m_tickString );
This function tells the Unity runtime to find the object named “Metronome” in the scene and then call a function named “Broadcast” that takes a string. In my Metronome.cs script I then converted the string to a float and told all of the objects listening to the metronome that a tick just happened. I wrote it this way because the very first tip given for iOS plugins is “Managed-to-unmanaged calls are quite processor intensive on iOS. Try to avoid calling multiple native methods per frame.” So I figured having Metronome.cs call a native function every frame to retrieve ticks would probably be a bad idea, but it turns out it’s better than using UnitySendMessage.
I changed the way the metronome works so that when the native code gets to each tick it pushes it onto the back of a list, then in the Update function for my C# Metronome, I pass a float array to a native Metronome_GetTicks function, which then fills the array with all of the ticks in the tick list and returns how many ticks it put into the array. Then, for each tick in the array, I call the same Broadcast(float) method that I called from Broadcast(string). Now profiling the exact same level that gave me spikes looks like this: