Reputation: 618
I have an app which I am trying to migrate to a new project. There is a heavy operation which I am handling in main thread asynchronously. In my older project, it takes just a second to complete this task but in my new project, it takes 6-7 seconds for the same task.
I observed the CPU usage and it looks like the new app is using less CPU and getting very few threads while the old one gets lots of threads for the same task. PS: I am using the same device.
What could cause this? Any ideas or suggestions to find out?
Thanks.
Upvotes: 3
Views: 291
Reputation: 618
Finally, I found the problem. It was caused by Optimization Level
setting in Xcode Build Settings
. When a new project created, default Debug
optimization level is none
, and Release
optimization level is Fastest, Smallest [-Os]
So when I changed Debug to Fastest, Smallest [-Os]
my task completion time dropped to 1 sec.
From Apple:
The Xcode compiler supports optimization options that let you choose whether you prefer a smaller binary size, faster code, or faster build times. For new projects, Xcode automatically disables optimizations for the debug build configuration and selects the Fastest, Smallest option for the release build configuration. Code optimizations of any kind result in slower build times because of the extra work involved in the optimization process. If your code is changing, as it does during the development cycle, you do not want optimizations enabled. As you near the end of your development cycle, though, the release build configuration can give you an indication of the size of your finished product, so the Fastest, Smallest option is appropriate.
If you want to read more about optimization levels and performance: Tuning for Performance and Responsiveness
Side note: Changing the optimization level to fastest, Smallest [-0s] in debug mode might affect the debugger breakpoints and it will behave abruptly.
Cheers.
Upvotes: 3
Reputation: 1142
This probably isn't really a response to your question, you answered it yourself quite nicely, but nonetheless I feel like it's needed.
I'd like to stress out how you should NOT make long running operation on the main thread. For no reason. Actually, if you want the screen to refresh 60 times per second (which should always be your goal) it means that every block of code you submit to the main thread must last less than 0.016 seconds (1/60) to avoid losing some frames. If, in the meantime, you also need to make the main thread do some complex animation and other stuff, well probably you need to go far behind the 0.016 seconds point.
If you block the main thread for much more than that (like 1 second in this case) than the users will experience a stuck interface, they can't scroll a scrollView or navigate the app. They may as well close your app entirely since they may feel like it's stuck.
In your case, for example, you may want to add some nice loading animation, like the ActivityIndicator or some nicer animation, to express you're actually working at that moment and you didn't freeze. That's really expected by users nowadays. You may (or may not, it's up to you) also wanna add a cancel button, if the user wants to cancel the long running operation and do something else with your app.
To avoid what you say that causes the loss of performances (the task is slowed up to 7-8 seconds) you may want to use a serialQueue with a high quality of service. Probably userInitiated is what you want.
This way you still have those task be prioritized by the OS, but you won't block the main thread in meantime, allowing you to add that loading animation for example.
If that's still too low of a performance, you could think of splitting the task in subtasks and having them performed in parallel by using DispatchQueue.concurrentPerform(iterations:execute:) (but I don't know if that's doable in your case).
I hope this helps you. Cheers
Upvotes: 1