Just wanted to emphasize that well-established fact :
Coroutines are awesome for performance optimization
I turned to a coroutine an old Update() function that just checked if a fixed float was superior to Time.time, in which case it would turn a boolean to true. And it made me gain 5 fps.
Yeah, that much. The coroutine removed that checkout by randomly changing the boolean every 1 to 4 seconds.
Now I can imagine how my actual fps would benefit from turning every looped methods into coroutines ^^
If you're doing anything where you check for time differences, then coroutines are great. Much better than anything you could do with Update().
You can't use them for everything you'd do in Update(), though, because you only get a performance benefit if the processing happens less than it would, if it happened every frame. So the greater the number you input to WaitForSeconds, the less responsive the game is going to be. It's a nice way to optimize, though. See if everything can run at a smooth framerate in Update(), and if not, start putting what's less important in coroutines, and keep kicking the values you use for WaitForSeconds up until the game is playable.
That's cool advices Jessy, thanks.
I'll see what would benefit and what would not, but except the input detection & movements methods, I guess nothing else has to be checked on every single frame (for basic behaviours I mean).
In fact I'm already running at 40 fps on 3GS, but I feel a lot could be improved via coroutines
On the other hand, one thing that annoyed me at first with checkup coroutines was that while(true) statement.
Apple clearly stated that every dev should avoid loops and Polling in general.
Originally Posted by AppleUse Event-Based Handlers
All modern Mac OS X applications should be using the Cocoa event system or Carbon Event Manager. (Similarly, iPhone applications must use the touch-based event system provided by the UIKit framework.) Your application should never retrieve events by polling the system. Doing so is highly inefficient. In fact, when there are no events to process, polling code is a 100 percent waste of CPU time. The modern event-based APIs are designed to provide the following benefits:
They make your program more responsive to the user.
They reduce your application’s CPU usage.
They minimize your application’s working set—the number of code pages loaded in memory at any given time.
They allow the system to manage power aggressively.
Besides user events, you should avoid polling in other situations as well. Threads in Mac OS X and iPhone OS use run loops to provide on-demand responses to timers, network events, and other incoming data. Many frameworks also use an asynchronous programming model for certain tasks, notifying a designated handler function or method when the task completes.
And more there.
40 on the 3GS isn't all that great ... thats at very best 15 - 20 on the 1st generation devices and potentially the iphone 3G
As for the event handlers: you aren't working with UIKit, so they are of no importance.
Though what I would recommend you to do is not using any time difference measures. use yield and wait till the time has passed point
Well, I guess 40 fps is still pretty good for a start before any deep optimizing process, considering the high number of bones and keyframes of my chars (82 bones total, 2000 x 2 keyframes, 1024 textures), plus all the visual effects, custom HUD, physics and higly detailed background
Still optimizable though, but for what I see on my handheld, it's already appearing very smooth and responsive
And I will abuse of yield, for sure
Thats no wonder, your device is up to 4 times faster than the 3G and older ...
So yes you are still looking forward to a lot of optimization or cut down of your userbase to more or less the 3GS owners
sounds especially like you will have to work on the memory consumption of your app to make it run at all
That's actually the tweaking I found to be efficient, yes, cutting textures by an half to make it run on 3G ^^
For which Unity is awesome, because you can just change Import Settings instead of actually importing resized graphics.Originally Posted by n0madThat's actually the tweaking I found to be efficient, yes, cutting textures by an half to make it run on 3G ^^
Yup I like that feature, but it's even more awesome with Texture2D.PackTextures() where you can just tell what target size you wantOriginally Posted by JessyFor which Unity is awesome, because you can just change Import Settings instead of actually importing resized graphics.Originally Posted by n0madThat's actually the tweaking I found to be efficient, yes, cutting textures by an half to make it run on 3G ^^
By the way, what is the unit reference of "frametime" in the profiler ?
is it the fps ?
here is one from an actual build :
- iPhone Unity internal profiler stats:
- cpu-player> min: 17.4 max: 29.3 avg: 24.4
- cpu-ogles-drv> min: 3.0 max: 5.7 avg: 3.7
- cpu-present> min: 0.5 max: 1.8 avg: 0.6
- frametime> min: 25.2 max: 43.0 avg: 33.3
- draw-call #> min: 5 max: 5 avg: 5
- tris #> min: 4220 max: 4220 avg: 4220
- verts #> min: 6196 max: 6196 avg: 6196
- player-detail> physx: 0.4 animation: 11.3 skinning: 8.3 render: 1.7 fixed-update-count: 1 .. 2
- mono-scripts> update: 2.1 fixedUpdate: 0.4 coroutines: 0.0
- mono-memory> used heap: 2064384 allocated heap: 3960832
Your "used heap" there is pretty large. Does it go up every frame by chance? You may be performing memory allocations in your scripts every frame, which can lead to hiccups down the line due to frequent mono GC. In particular, coroutines can cause such allocations in some situations.
I found it to be that high on every frame, even if I don't have any clue of how much we should aim for in a reasonable way. It was that high even before the coroutine translation.
I guess it's because of the huge animations, each char has a 8 MB animation (40 - 50 moves per character), and 4 x 1024 texture atlases (2 chars + 1 background + 1 HUD).
When I will reach the deep optimization process, I'll cut characters texture size by an half for sure.
But I feel like I can't help but have a huge Animation allocation for this type of game :/
edit @ Tagged : Don't worry dude, you're not stealing anything, I would be happy to launch (yet another) general performance thread
Just in regards to this, I've notice the used heap in my game going up until the end of the background mp3 music, once that loops over and starts again the used heap drops right back down. This happens in sync with the music every time, is this normal? Or should I be looking through the code for culprits?Originally Posted by PirateNinjaAllianceYour "used heap" there is pretty large. Does it go up every frame by chance? You may be performing memory allocations in your scripts every frame, which can lead to hiccups down the line due to frequent mono GC. In particular, coroutines can cause such allocations in some situations.
Apologies for the thread stealing
Compressed audio doesn't add to your mono heap, so if its going up in sync with your music that's just a coincidence. The only thing that should contribute to that particular chunk of memory is allocations from script - assets like textures, sounds and animations are not represented there. The actual size of the heap isn't really that big of a concern by itself as long as its size is relatively steady, but if its rising every frame you've got some kind of allocation happening in your update(s). This will eventually cause mono garbage collection to trigger, which can make your framerate stutter unpleasantly for a second or two. The severity and frequency of mono GC's effect on your framerate can vary wildly - its usually not a showstopper even if GC is running pretty frequently, but its best to avoid it for ideal performance. There's generally no reason why you'd ever have to perform allocations every frame, so its quite avoidable if you keep an eye on it.
Can you tell me what might cause that to happen? For instance, would this code be improved by declaring the variables outside of Update?Originally Posted by PirateNinjaAllianceif its rising every frame you've got some kind of allocation happening in your update(s)...
There's generally no reason why you'd ever have to perform allocations every frame, so its quite avoidable if you keep an eye on it.
I have been declaring variables inside of functions when they won't need to be used outside of the functions, but if that's allocating memory for a new variable each time, I will stop doing that immediately.
Can anyone tell me if InvokeRepeating has the same optimization benefit as using a coroutine with yield discussed here? I find it to be a cleaner approach than using a coroutine with a while() loop.
Well benefit is that invokerepeating gets a new clean memory each time again, no remainder from the last run.
drawback is that it also has to reserve that again on each call.
I know for sure that checking an animation state's values, like in the following script...Originally Posted by JessyCan you tell me what might cause that to happen?
... will allocate every frame, whereas...
... does not. I've also noticed that this use of co-routines causes allocations every frame, whether it someCondition is true or not...
Meanwhile, this does not, even though it is identical in function.
I've learned these "rules" by trial and error, and watching my mono memory closely whenever I'm running the profiler. I'm sure there are other things to avoid as well - as a general rule, I always cache any reference to any component in a variable, and never really never declare temp variables inside a function at all out of paranoia.