-driver-time-compilation flag in Xcode 13.3.1

If I add the -driver-time-compilation to the "Other Swift Flags" section in Xcode, should I expect to see that flag passed down to the CompileSwift step in Xcode? I tried setting it in hopes of trying to debug why we're getting an insane crazy compilation time for one of our targets but 1. I don't see being emitted in that step and 2. I can't find any actual diagnostics emitted in Xcode anywhere.

Is this still a valid flag? Does it interact with some other Swift setting in a way where it will only work in certain conditions?

Try with the Swift build system integration turned off (delete the defaults key/value). I found that it can interfere with the various notes that diagnostic flags can add to the compiler's output.

This was what we were seeing as well, the flag is defined in the Swift Driver but it doesn't seem to do anything. Add support for -driver-time-compilation by owenv · Pull Request #262 · apple/swift-driver · GitHub was closed.

Thanks @Jon_Shier. Was this specifically referring to the EnableSwiftBuildSystemIntegration default setting? If so, does updating that require a restart of the machine, as I've definitely removed that value as I've been investigating our slow compilation times for this one module.

I had noticed after posting that most of the CompileSwift steps were executing:

<path_to_toolchain>/usr/bin/swift-frontend -frontend .....

as opposed to swiftc, which seems to indicate that this might be the new build system. Do you know if that's the case?

Again, thanks for your help!

Yes, I’ve seen reports the new build system is still slower than the old, so that’s certainly something to investigate.

As this point, I'm just at my wits end. We have a very large code base, with around 70 different "feature" modules implemented as Xcode Projects / Framework targets along with a handful of other libraries plus the main app. In terms of total build time, most of them are on the order of just a handful of seconds. But for whatever reason, when compiling in DEBUG for device, this one module takes on the order of 28 minutes to compile on M1 Max MBP and around 45 minutes on an Intel Mac i9. Compiling in DEBUG for simulator on either brings this one framework back to the normal time. Note when compiling for simulator, we're compiling for x86_64 on both Intel and Apple Silicon because we have a few dependencies that aren't ready for arm64 simulator on the M1s.

In the case of building for device, the Compiling step for a handful of the Swift files take 20+ minutes while the rest of the Swift files take just a couple of seconds. I've tried the debugging around function build (-Xfrontend -debug-time-function-bodies) and type checking (-Xfrontend -debug-time-expression-type-checking) and I see nothing out of the ordinary. For those files that take 20+ minutes to "compile", I see a total of around 1 second total for both function body and type checking. I have no idea what it might be doing that is taking so much time.

I try passing -driver-time-compilation and I can now see it appearing on the compile step but nothing ever gets printed out. I've tried in both Xcode and on the command line.

All of our feature frameworks are built pretty much from the same template using Tuist, so I have yet to find any settings differences between this one framework and everything else.

I've spent a full day and a half on this and don't feel any closer to figuring out why this is happening. Open to any other suggestions.

You should be able to build just that module with a timing summary in Xcode to narrow down the file or step that’s taking the time.

Sorry, I have performed that. It is several of the Compile Swift steps on some files that take 20+ minutes while other files in that same module finish in seconds. There are 70 Swift files total and it is probably 15-20 or so that regularly are the ones that take the ridiculous amounts of time.

Ah right, I forgot the file timings are only granular down to the time taken by the batch the file's in, so if you have 20 cores, you'll see 20 files with the same time. Can you divide and conquer those files? By that I mean comment out the content of half the files (while still being able to build) and keep iterating until you no longer have the build issue?

1 Like

@monocularvision I was also facing this issue last month and just gave up. The driver time compilation output never shows for me although it is being passed as an option in the logs. I tried with a development snapshot to make sure its not Xcode being wonky, but that also did not help. If anyone has any pointers on what to check, do share.

1 Like

Working on this today, but if it helps anyone else (or myself in the future), I happened to give -disable-batch-mode a try after Googling only returned results about opting-in to the feature back in the day, which was -enable-batch-mode. It appears to have worked and is allowing me to get a more narrowed list of files that is taking hundreds of seconds to compile.

Could you double-check the version of the Swift toolchain in Xcode? Is it 5.5.3 or 5.6? If 5.5.3, you may have hit an extremely unlucky edge case in GenericSignatureBuilder. Could you narrow down the files to a “Reproducer”, or a snippet of code that can run independently of your other dependencies? Then you could run that same snippet on the newest development snapshot, where GenericSignatureBuilder was fully replaced by RequirementMachine.

We're on Xcode 13.3.1, using Swift version 5.6. I have zero alternative toolchains installed.

I'm still working on a smaller reproduction, but what I've found so far in this single Swift file of around 300 lines of code, compilation is:

• 26m18s without any changes
• 8m 50s if I remove all of the function bodies and return a hard-coded value if the function returns something.
• 18m 4s if I add a manual equatable conformance to the four types present (just return true)
• .619s (yes, under one second) if I perform both of the above (remove function bodies and implement the manual equatable conformance)

Again, this is only when building for "Any iOS Device (arm64)" in Debug mode. Building for x86 simulator or building for device in Release mode doesn't have this problem.

You can also try toggling parts of the new generics infrastructure, as there may still be bugs on one side or the other. There are three different flags at different levels, and one part of the generics system was moved to the new Requirements Machine in Swift 5.6, so toggling the various parts off and on may change some things. I would try turning more bits on first, then turning stuff off. The "Requirement Machine", a new generics implementation based on term rewriting

Edit: Now that I notice the arch issue I wonder if there's an underlying LLVM issue since it seems arch specific. You might want to try a 5.7 toolchain and see if the issue still exists.

There's a known bug in the arm64 backend where some enum operations take a long time to compile. I believe it's fixed in 5.7.

You can set OTHER_SWIFT_FLAGS to -stats-output-dir /tmp/stats after creating a /tmp/stats directory, and grep for LLVM pipeline.wall in /tmp/stats/*.json to conform if this is the case.

1 Like

Are there no compiler flags / notes that could expose that timing information?

That's what -stats-output-dir <foo> does, try it with your own project if you're curious. Just remember that you do need to manually create the directory first.

Does the LLVM pipeline.wall value not exist if you don't hit this bug? I don't see it in any of my output.

Looks like this timer was accidentally removed at some point. I'll put it back. But you can look at the rest of the file to get an idea of what is tracked.

Are these values documented anywhere? Some of them seem self explanatory but others are not.