Swift app only performing reasonably when built for Xcode's Time Profiler? - ios

I'm working on an app that processes large float arrays, and I was extremely disappointed to find that Swift is apparently a good 10x slower than Python when running on my iPhone 5. I guess that can't be true, but I would have thought it true had I not tested the app in the Time Profiler and realized that it's probably not my algorithm or Swift's implementation causing the issues.
When the app is built for the profiler, it performs nicely: It does the processing in an imperceptibly small amount of time, as it should. But normally, if I hit the run button (play symbol) in Xcode to build and run, even with the compiler set to be Fastest, it takes almost 20 seconds to complete. (Code remains unchanged between builds.) It's ridiculously slow.
It's reasonably fast when I build and run in a simulator on my MacBook Pro, but even then it's slower than it is when built and run through the Time Profiler on my little iPhone 5.
The performance difference between builds is also present when I place the following test code in the application() function in AppDelegate, so I don't think it's a GUI/threading issue or anything. And the same test code runs quickly when implemented in Objective-C (in a separate app on my device) and Python on my Mac.
var nums: [Float] = []
for var i = 0; i < 250000; i++ {
nums.append(Float(i) * 0.001)
}
(This takes around 20 seconds unless run through the Time Profiler.)
Have any of you experienced anything like this before? I'd be immensely happy if you could help me figure this out.

You were building the app in Debug mode instead of Release mode. Debug mode is much easier to debug, but release mode generates faster code.
When building for Debug mode, the compiler inserts special debug symbols that help the debugger. I once tried to debug an app in Release mode and the debugger couldn't even find my variables. Release mode not only doesn't include those symbols, but it also optimizes your app, generating a binary that is much smaller and faster.
Here's how to switch between Debug and Release mode:
Click on your scheme in the top-left corner of Xcode.
Select "Edit Scheme..."
Click on the "Build Configuration" dropdown.
Change the build configuration to Release.
Rebuild your project.
(I am not providing an image here because I assume you know how to rebuild your project.)

Related

High CPU Usage when run as Debug vs as Release (Instruments run as Release). How to Debug?

I've been having what I would think as performance issue on my app when running on old hardware (iPad mini 2 which is close to 7 years old). It's unfortunately seems like sporadic whereby 2/10 times it runs OK and the rest, CPU Usage creeps upwards of 90% as time goes by.
The App is doing some intensive(?). drawRect stuffs where I use bezierpath to draw a live HeartRate (among others) chart. Using Instruments does not really show me where the possible bottleneck is occurring. (TBH, I'm not very good at reading the output tho)
(for this image, I used 'invert call tree', 'hide system libraries'
I tried putting in some time profiling of my own
let start = CFAbsoluteTimeGetCurrent()
let end = CFAbsoluteTimeGetCurrent() - start
print("drawRect END:\(Date()) - total Secs:\(end)")
and while it's slower than my iPhone 7, I think it's still acceptable.
drawRect END:2021-01-16 00:39:26 +0000 - total Secs:0.002599000930786133
drawRect END:2021-01-16 00:39:27 +0000 - total Secs:0.001813054084777832
drawRect END:2021-01-16 00:39:28 +0000 - total Secs:0.0019180774688720703
drawRect END:2021-01-16 00:39:29 +0000 - total Secs:0.0016759634017944336
In the end, I found this post --> https://developer.apple.com/forums/thread/19936 and when I started the run as "release" then the high CPU Usage basically went away.
Question:
During normal app development, I agree that running as Debug would be beneficial, but what are the actual benefit? How is the Debug config different? (Some reading material / Links would be good) TQ
If instruments are running as "release" config, then how does one actually be able to figure out what's happening under the hood? Like in my case, I had no idea Instruments is running as "release" and normal run (Cmd-R) is running as "Debug". This is a big mismatch and obviously threw me off.
So.. Do I have an issue or do I not? It's highly likely that I do, but I, for the life of me, can't seems to figure out why.
The iPad Mini2 is definitely old and slow. I downloaded some CPU/System monitor app from the store and just running it I am seeing 40% CPU usage already (!!) Is there a way to collect CPU usage data within the app? like in a Print statement.
Thanks.
The benefit of the Debug configuration is that it lets you debug your app. The Debug configuration lets you see things like the values of variables. If you tried to debug your app with the Release configuration, you would see memory addresses instead of variable names. The Debug build configuration sacrifices speed for the ability to debug. The Release build configuration sacrifices debugging for speed.
If you want to see the problem you're having when running in the Debug configuration, edit your project scheme and tell Xcode to use the Debug configuration for profiling. Then Instruments can help you find where the slow spots are in the code in the Debug configuration.
Focus on time profiling for the Release build configuration, the configuration the people using your app will see.
Take a look at the os and OSLog framework references in Apple's documentation, which you can read in Xcode by choosing Help > Developer Documentation. The os and OSLog frameworks are in the System section. Those frameworks are how you collect profiling data from your code.
For a more detailed explanation of the Time Profiler instrument, read the following article:
Finding the Slow Spots in Your Code with the Time Profiler Instrument

Could Xcode affect app performance while debugging?

I have an application written in Swift on SceneKit + Metal. When I build and run the app from Xcode fps counter shows 40fps. But if I run the app myself by tapping the icon on springboard fps counter shows 60fps. How could it be? Could Xcode somehow affect app performance while debugging? I have no idea how this all works, but I suppose there could be some hooks for debugging to work correctly which affect performance. If so, can I opt-in from this?
I'm aware of different build flags for debug and release builds, but I don't make release build. Performance differs in the same debug build while running from Xcode vs when I run the app manually on the phone.
By default, Xcode enables the Metal validation layer. That does a bunch of additional checking of how you're using it to catch incorrect uses. The additional checking is slow, which is why Metal doesn't do it unless validation is enabled.
This can be changed in Xcode's Scheme editor. This is documented in Apple's Metal Programming Guide.
A nice tutorial on iOS Assembly. This might be insightful on the topic
As stated, this is because the compiler is in debug mode, meaning no optimizations are made. If you turn optimizations on, then you’ll see a much smaller function generated.
And also check out this answer about changing optimization levels.
I've experimented with different options in scheme editor and have find out that Debug executable checkbox affected performance in my case. So my assumption about debugger was right, but I didn't know about that checkbox before.

Fixing low FPS in Swift Playground

My SpriteKit playground book averaged 15 FPS on my MacBook Pro.
Do playgrounds run slower than iOS device simulations? If I run the same playground book on my iPad Pro, will the FPS limitation be similar? Will other apps opened on my computer limit the speed of playgrounds?
EDIT:
Moving code such as subclasses and extensions to auxiliary code in the "Sources" folder of the playground book allow the simulation to run quicker because the code only compiles once.
On the Mac, Xcode's "Playgrounds" are super useful for quick experiments but, due to their nature, terribly slow for "real" tasks.
If your code is more than a few pages long, and/or involves working with the UI, as you do with SpriteKit, the Playground may become really slow, sometimes even unresponsive.
"Playgrounds" are part of Xcode and run on top of the iOS simulator - that's how they display graphics and UI in the "Assitant Editor". The iOS simulator is not really known to be fast either.
On the other hand, "Swift Playgrounds" on iOS is a completely different app, even if it shares a lot with its Mac cousin.
Most importantly, it runs in iOS on the real device, with the real hardware processing, not emulation, which makes it ideal to use for SpriteKit, as Apple themselves often shows in their demos.
I would therefore say that your code should indeed run faster/better/properly on the iPad version.
Even if of course, I can't really know, since I don't know your code - you will probably be the one telling us later if using the iPad version made a difference.

How to debug slow app launch

When launching my app i get the launch screen for about 2-3 seconds and only then my first UIViewController appears.
And some times my ViewDIdAppear is being called before the UIViewController is actually appearing.
I have a pretty big storyboard (15 screens).
I have some flags that i check from UserDefaults (user is logged-in ...), and i initialize crashlytics and GCM.
So the flags and the initializing doesn't seem to be the problem.
I checked system time differences and it seems to be OK.
Any ideas for debugging the slow launch?
In Xcode: Product -> Profile
Choose the "Time Profiler"
Running this tool will give you time spent in every method in your program, and it'll give you that information in a hierarchical structure. This should give you an idea where most of the time is spent. Keep in mind that the instrumentation adds extra overhead, so the absolute time value may not be correct, but the proportion of time spend in each method should what you need to debug this issue.
Here is a decent looking tutorial (albeit on an older version of Xcode) showing how to use this tool.
The time profiler will not help you if the slowness is from the initialization time. During that time none of your code is running yet, so the time profile won't be logging anything.
You can have xcode print out stattics on how long it take to launch by going to 'edit scheme' -> run -> environment variables add add DYLD_PRINT_STATISTICS with a value of 1. Ideally you want your launch time to be less than 400ms which is about the length of the opening animation. I was able to cut my launch time in half by removing use_frameworks! from cocoapods. And I was able to to cut it in half again by removing unused external libraries.
There is a great apple lecture on the topic here:
https://developer.apple.com/videos/play/wwdc2016/406/

Reducucing AIR compile time

I have an AIR app that is quiet big, and compile time is around 40-50 sec.
Good thing is that app is quiet modular, I could easily break it down to modules, and compile them as swc and then recompile only those modules in which I'm working on, like i could do with normal desktop apps. Is it possible to have the same approach on mobile? Is there any way to do that on IOS? As far as I know It would not be possible to load swc on IOS at runtime.
Any other ideas to bring compile time down?
AIR compiler for iOS compiles everything into a normal swf then compiles that swf again into iOS code, and that's where it takes ages!
But you can do a test build which takes some seconds though it runs slower but enough for testing especially if you're using a high end iOS device.

Resources