Static linking


(David Beck) #1

In session 406: optimizing app startup time at WWDC, most of the recommendations were very pro Swift. Things like using structs and the fact that it can automatically inline calls. One recommendation that was very anti swift, was the section on limiting dylibs. The presenter recommended keeping it to under 6. I’m not sure if the 15 libswift dylibs that get included by default in a Swift application count towards that (he did mention that Apple frameworks are optimized, but I’m not sure if that is limited to the ones preinstalled on the device).

His recommendation was to use static libraries, which makes sense, except that Swift on iOS doesn’t seem to support static linking. But for whatever reason, Swift PM ONLY supports static linking. Is there any plans to add static linking to Mac and iOS apps? The only alternative I see at this point is to simply include the source files from libraries in the app’s target, but Swift has from the beginning encouraged naming things generically and relying on modules for name spacing.

David Beck
http://davidbeck.co
http://twitter.com/davbeck
http://facebook.com/davbeck


(Rod Brown) #2

In regards to Mac and iOS apps, the dylibs are included because of the lack of ABI stability, which was a goal for Swift 3 that was pushed back due to the really significant changes that occurred in the language.

From what I understand, these dylibs are very light and simply act as binding between the actual frameworks and your code, rather than being their own code. Thus, I expect they’re as heavily optimised as they can be, and are relatively light impact. They were more discussing true frameworks and libraries.

I don’t have any official evidence of this and it’d be something I’d love to get an official comment on too, but this would be my understanding. Also, if they were a significant hit I would have expected them to mention it while they were throwing around their pro-Swift recommendations, as a caveat.

···

On 18 Jun 2016, at 8:41 AM, David Beck via swift-users <swift-users@swift.org> wrote:

In session 406: optimizing app startup time at WWDC, most of the recommendations were very pro Swift. Things like using structs and the fact that it can automatically inline calls. One recommendation that was very anti swift, was the section on limiting dylibs. The presenter recommended keeping it to under 6. I’m not sure if the 15 libswift dylibs that get included by default in a Swift application count towards that (he did mention that Apple frameworks are optimized, but I’m not sure if that is limited to the ones preinstalled on the device).

His recommendation was to use static libraries, which makes sense, except that Swift on iOS doesn’t seem to support static linking. But for whatever reason, Swift PM ONLY supports static linking. Is there any plans to add static linking to Mac and iOS apps? The only alternative I see at this point is to simply include the source files from libraries in the app’s target, but Swift has from the beginning encouraged naming things generically and relying on modules for name spacing.

David Beck
http://davidbeck.co <http://davidbeck.co/>
http://twitter.com/davbeck
http://facebook.com/davbeck
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(David Beck) #3

This morning I used the DYLD_PRINT_STATISTICS environment variable that was recommended in the session (I couldn’t get it to work on an iOS device, so these are numbers from the simulator). “Cold” refers to launching the app after a restart to make sure that the libraries aren’t already in memory and “hot” is when the app has been run recently. I created 2 basic iOS projects, one Swift and the other ObjC, using the empty view template, and changing nothing except the environment variable. I ran this experiment a few times over for all 4 scenarios, and these are typical results.

Swift:
Cold:
Total pre-main time: 140.49 milliseconds (100.0%)
         dylib loading time: 49.29 milliseconds (35.0%)
        rebase/binding time: 15.57 milliseconds (11.0%)
            ObjC setup time: 50.73 milliseconds (36.1%)
           initializer time: 24.72 milliseconds (17.5%)
           slowest intializers :
               libSystem.dylib : 7.22 milliseconds (5.1%)
   libBacktraceRecording.dylib : 8.49 milliseconds (6.0%)
                CoreFoundation : 3.41 milliseconds (2.4%)
                    Foundation : 4.42 milliseconds (3.1%)
Hot:
Total pre-main time: 63.33 milliseconds (100.0%)
         dylib loading time: 27.78 milliseconds (43.8%)
        rebase/binding time: 11.38 milliseconds (17.9%)
            ObjC setup time: 13.25 milliseconds (20.9%)
           initializer time: 10.83 milliseconds (17.1%)
           slowest intializers :
               libSystem.dylib : 2.46 milliseconds (3.8%)
   libBacktraceRecording.dylib : 4.84 milliseconds (7.6%)
                    Foundation : 1.52 milliseconds (2.4%)

ObjC:
Cold:
Total pre-main time: 133.77 milliseconds (100.0%)
         dylib loading time: 43.62 milliseconds (32.6%)
        rebase/binding time: 14.08 milliseconds (10.5%)
            ObjC setup time: 51.98 milliseconds (38.8%)
           initializer time: 23.88 milliseconds (17.8%)
           slowest intializers :
               libSystem.dylib : 6.52 milliseconds (4.8%)
   libBacktraceRecording.dylib : 7.93 milliseconds (5.9%)
                CoreFoundation : 3.89 milliseconds (2.9%)
                    Foundation : 4.32 milliseconds (3.2%)
Hot:
Total pre-main time: 55.55 milliseconds (100.0%)
         dylib loading time: 21.90 milliseconds (39.4%)
        rebase/binding time: 11.30 milliseconds (20.3%)
            ObjC setup time: 12.92 milliseconds (23.2%)
           initializer time: 9.34 milliseconds (16.8%)
           slowest intializers :
               libSystem.dylib : 2.98 milliseconds (5.3%)
   libBacktraceRecording.dylib : 3.52 milliseconds (6.3%)
                CoreFoundation : 1.23 milliseconds (2.2%)
                    Foundation : 1.15 milliseconds (2.0%)

Keep in mind that the recommended startup time is 400ms. The Swift standard libraries never show up in slowest initializers, but something does seem to be slowing the Swift startup time down at least a little, but not by a significant amount. My conclusion would be that the Swift libs are indeed optimized and shouldn’t be a major concern.

However, my bigger concern was in an app that has 3rd party dependencies (like my own). I’m looking at a 700ms pre-main time, with all my Carthage dependencies showing up in the slowest initializers list. While some of them could be refactored out, others are either non-simple, or for a service we use such as analytics. I’m curious how we can optimize the launch time of a Swift app that uses 3rd party frameworks, since iOS doesn’t support static linking of Swift code.

Interestingly, Crashlytics uses a framework, with a module map, that can be used by Swift code directly, but the binary is a static lib that doesn’t need to be embedded. I wonder how they created that...

David Beck
http://davidbeck.co
http://twitter.com/davbeck
http://facebook.com/davbeck

···

On Jun 18, 2016, at 8:41 AM, David Beck <swift@tnku.co> wrote:

In session 406: optimizing app startup time at WWDC, most of the recommendations were very pro Swift. Things like using structs and the fact that it can automatically inline calls. One recommendation that was very anti swift, was the section on limiting dylibs. The presenter recommended keeping it to under 6. I’m not sure if the 15 libswift dylibs that get included by default in a Swift application count towards that (he did mention that Apple frameworks are optimized, but I’m not sure if that is limited to the ones preinstalled on the device).

His recommendation was to use static libraries, which makes sense, except that Swift on iOS doesn’t seem to support static linking. But for whatever reason, Swift PM ONLY supports static linking. Is there any plans to add static linking to Mac and iOS apps? The only alternative I see at this point is to simply include the source files from libraries in the app’s target, but Swift has from the beginning encouraged naming things generically and relying on modules for name spacing.

David Beck
http://davidbeck.co <http://davidbeck.co/>
http://twitter.com/davbeck
http://facebook.com/davbeck


(Marco S Hyman) #4

Not always so light as earlier discussed on this list. An Xcode 8 Swift 3 compile shows swift Frameworks taking 9.2 MB of the 11.5 MB total app size for an OS X app I’m working with.

The code portion of this small app is less than .5 MB. Resources are about 1.5 MB.

···

On Jun 18, 2016, at 2:55 PM, Rod Brown via swift-users <swift-users@swift.org> wrote:

From what I understand, these dylibs are very light


(Rod Brown) #5

Sorry, by light I was referring to the work required to process these dylibs. Not the actual size of them. From what I know they’re not directionally proportional.

···

On 18 Jun 2016, at 3:14 PM, Marco S Hyman <marc@snafu.org> wrote:

On Jun 18, 2016, at 2:55 PM, Rod Brown via swift-users <swift-users@swift.org> wrote:

From what I understand, these dylibs are very light

Not always so light as earlier discussed on this list. An Xcode 8 Swift 3 compile shows swift Frameworks taking 9.2 MB of the 11.5 MB total app size for an OS X app I’m working with.

The code portion of this small app is less than .5 MB. Resources are about 1.5 MB.