Performance Swift shell-scripts

I tried to compare the performance of swift-versions and hardware.

Short story:
Mac Pro (2008) | Apple Swift version 3.0.1
0m0.391s

Mac mini (2018) | Apple Swift version 5.6.1
0m3.769s

Question: Why is the newer version about 10 times slower???

My bash-script:

... 
swift -version > $RESULT_FILE
( time $SWIFT_SCRIPT ) 2>&1 | tee -a $RESULT_FILE

My swift-script:

#!/usr/bin/swift

let LargeIndex      = 1 ... 1000 * 1000 * 10

print ("LargeIndex is \(LargeIndex)");

for Number in LargeIndex {
    if ((Number % (1000 * 1000)) == 0) {
            print ("Number is \(Number)");
    }   
}   

// vim: ts=4 sw=4

Result-1:

    Mac mini (2018)
    macOS Monterey
    Version 12.6
    
    Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)
    Target: x86_64-apple-macosx12.0
    LargeIndex is 1...10000000
    Number is 1000000
    Number is 2000000
    Number is 3000000
    Number is 4000000
    Number is 5000000
    Number is 6000000
    Number is 7000000
    Number is 8000000
    Number is 9000000
    Number is 10000000
    
    real        0m3.769s
    user        0m3.710s
    sys 0m0.049s

Result-2

    Mac Pro (Anfang 2008)
    OS X El Captain
    Version 10.11.6

    Apple Swift version 3.0.1 (swiftlang-800.0.58.6 clang-800.0.42.1)
    Target: x86_64-apple-macosx10.9
    LargeIndex is 1...10000000
    Number is 1000000
    Number is 2000000
    Number is 3000000
    Number is 4000000
    Number is 5000000
    Number is 6000000
    Number is 7000000
    Number is 8000000
    Number is 9000000
    Number is 10000000

    real        0m0.391s
    user        0m0.131s
    sys 0m0.043s
1 Like

You're also comparing across very different hardware and OS versions, which clouds the results.

In my experience on macOS, it sometimes can take multiple seconds (easily 5 s, maybe more) for the Swift toolchain to "warm up" on first launch after a while. Subsequent launches are then much faster.

This happens even with calls like swift --version, so I don't think it's related to compiler or runtime performance. I'm seeing this both with nightly toolchains and with the official Swift toolchains that ship with Xcode.

Sadly, this makes Swift a bad choice for scripting in many cases.

This is also measuring a debug build.

Try

#!/usr/bin/swift -O

// ...

A big part of this is often macOS's built-in anti-malware junk, which sometimes runs on first launch in a given boot session. For compiler toolchains that can slow things down a lot. It's also something which tends to get worse in newer macOS versions, as Apple adds more and more such things.

Which, again, is why it's critical to comparison test on the same macOS version.

2 Likes

Latest Swift 5.10 that comes with Xcode 15.3 and Swift 6 build from 13th of March has indeed interesting results:

But with optimisations turned on there is almost no difference:

Yeah, it’s not the runtime of your code, it’s the overhead of the Swift driver.

Interesting what’s causing such difference between 5.10 and 6.0 versions — is that improvement to the driver itself or being free from overhead that comes with official releases and maybe Xcode? Probably on Linux it might be more clear…

i am doubtful that macOS is (mostly) to blame here, i have also anecdotally noticed a similar slowdown on linux ever since upgrading from 5.8 → 5.9.

:man_shrugging: It can be multiple things.

But Gatekeeper is definitely part of it. e.g. upon launching swift repl just now, it took over ten seconds (which is actually better than average for first launch). The swift process only used about one second of CPU time, and the rest of the time was syspolicyd chewing up a whole core. On subsequent launches swift repl takes only a second or two (and syspolicyd remains idle).

It's a bit infuriating that Apple's own antivirus system interferes so severely with Apple's own apps. You'd think at least Apple's apps would be suitable signed and deployed such that they wouldn't need frequent reprocessing (of whatever nature syspolicyd is doing).

Xcode is the worst - first launch, when Gatekeeper interferes, I can watch syspolicyd sit there chewing on a core for about a minute before Xcode's first window finally appears (and even then it can take another thirty seconds or so for Xcode to become truly responsive - although that part might be Xcode's fault).

1 Like