Slow iOS app start using Xcode 10.2 + iOS 12.2
Asked Answered
T

0

6

I have a very strange issue seemingly caused by compiling with latest Xcode 10.2.

I have noticed my app start time to get significantly worse (3x slower) caused simply by building using Xcode 10.2(.x) and running on iOS 12.2. The same code revision, when running on older iOS (12.0) or compiled with Xcode 10.1 for iOS 12.2, runs fine.

The delay happens even before main() gets called. Basically the delay between console saying Bootstrapping com.myapp.something with intent foreground-interactive and main() is called is where the measured time start increase happens.

App setup (quickly):

  • Mixed target Swift + Obj-C
  • Using internal frameworks for code separation
  • Using CocoaPods (1.5.3) with frameworks
  • ~35 internal frameworks loaded in runtime (internal + mostly CocoaPods)

Here is what happens

Old code revision (Swift 4.2) - one of older releases which worked fine back then compiled using Xcode 10.1

This is the table showing impact of compiling with Xcode 10.2 to app launch times (the moment first frame of status bar fade in starts).

|            | iOS 12.0 | iOS 12.2 |
|------------|----------|----------|
| Xcode 10.1 |       1x |    1.25x |
| Xcode 10.2 |       1x |       3x | <-- πŸ’₯

The startup time of last OK release (iOS 12.0 / Xcode 10.1) is considered 1x, the rest is relative to it. We are talking seconds here (less the 3s -> almost 9s).

This significant delay happens only on fresh install. Every subsequent launch is fast again.

Latest code (Swift 5) - all code migrated to Swift 5, all CocoaPods updated to latest Swift 5 compatible versions, project updated to Xcode 10.2 settings

Very similar situation as before Swift 5. So Swift 5 itself does not seem to be the issue.


Edit 1:

Time Profiler uncovered that Initialization time got drastically slower.

Turns out _dyld_start (loading of dynamic frameworks) is ~35x slower.

|            | _dyld_start time |
|------------|------------------|
| Xcode 10.1 |             0.2s |
| Xcode 10.2 |             7.0s |

This means something related to Xcode 10.2 + iOS 12.2 causes loading of dynamic frameworks to get drastically slower.

With my ~35 dynamic frameworks loaded to runtime (most of it CocoaPods), the perf degradation seems to be massive. No clue why the change though...


Since the issue happens only on iOS 12.2 + Xcode 10.2 (which has support for Swift 5), I was wondering if this issue can somehow be related to ABI stability or something. What does not make sense to me is that it happens even for code before Swift 5 migration when compiled with Xcode 10.2.

What I have tried so far:

  • Updating to latest CocoaPods 1.7.0.rc.2 - no impact
  • Measuring with Time Profiler

Edit 2:

Seems to be caused by dynamic linker. We have made some investigation and linked seems to be using different implementation on iOS 12.2 when loading frameworks.

Since iOS 12.2 there is a lot of mentions of "recursive" in Instruments when loading (in ImageLoader::) and seems like the recursion goes wrong there. The stack trace seems to go very wrong (see screenshots below).

Profiler stacktrace screenshots

I guess the only workaround here would be to remove frameworks and compile directly or using static libraries.

Any help / ideas on how to keep using frameworks appreciated! Thank you!


Edit 3:

The issue does not seem to happen anymore on first iOS 13 Public beta.

Measurements (setup below) showed me that launching same code revision on iOS 12.3.1 takes about 3x longer then on iOS 13.

This really seems to me as bug on iOS 12.x. Given fact iOS 13 is out quite soon, I don't think any fix will appear for iOS 12.x anymore (leaving dropped devices like iPhone 6 to suffer...).

Test setup:

  • Running the very same code (Swift 5, Xcode 11 beta 2)
  • Running on the same iPhone model (iPhone 6S 16GB)
  • Cold app launch after device reboot
  • Devices with iOS 12.3.1 (latest stable) and iOS 13 (first Public Beta)
Theresita answered 22/5, 2019 at 10:48 Comment(10)
Have you tried using the Instruments to Time Profiler to see if there are any differences in resource usage when your code is compiled using Xcode 10.2? – Aviation
Thank you for the idea @DávidPásztor. Did some measurements and it uncovered issues. I have updated the question. – Theresita
Do the release notes ring a bell perhaps? – Dandy
@Dandy What part of release notes do mean? AFAIK there is nothing explaining this issue – Theresita
I wasn't expecting a direct explanation of your issue. I meant that some of the Xcode changes may give you a direction in which to search. In a case like this, I would go through the release notes with an open mind, trying to think of some association with my issue. – Dandy
@LukasKukacka could you clarify your "workaround" please? I'm seeing something very similar and it's causing issues at app launch, especially on lower end iPhones. – Scutter
@Scutter Please see my latest edit. Can you try on Xcode 11 & iOS 13? I guess the only way is to reduce the impact by reducing the number of frameworks or drop iOS 12 support as soon as iOS 13 is out (which is impossible for many apps). – Theresita
Have you tried Xcode 10.2.1? – Enclasp
I didn't experience the same issue, but this could be something Apple does on purpose to be able to say "iOS 13, 3x faster app starts than 12.2". But I hope it's not. – Enclasp
@LukasKukacka I solved it by using static libraries instead, through Cocoapods. It's an incredible situation... Debugging was so difficult on this one. Thanks for your answer Lukas! – Scutter

© 2022 - 2024 β€” McMap. All rights reserved.