Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are swift function being compiled 25 times?

I've realised that my iOS project (quite large, only swift code) is taking a very long time to build, so I started analysing the code build time using -debug-time-function-bodies and checking the transcript logs.

I noticed that a lot of my functions are getting compiled 25 or 26 times.

What can be causing this kind of issue?

To make this question easier to understand here's a screenshot from BuildTimeAnalyzer for Xcode

enter image description here

As you can see under occurrences some functions are built 25 or 26 times.

like image 251
MrHaze Avatar asked Dec 10 '19 15:12

MrHaze


People also ask

Is Swift interpreted or compiled?

Swift is a compiled language means before producing the actual output Swift perform various activities. These activities are generally performed by the Swift compiler.

How many types of functions are there in Swift?

Swift has two compound Types: functions and tuples. Now I know what you might be thinking: “Functions have names!” Indeed many do.

Can we make an instance of never in Swift?

Never is an uninhabited type, which means that it has no values. Or to put it another way, uninhabited types can't be constructed. Enumerations with no cases are the most common example of an uninhabited type in Swift. Unlike structures or classes, enumerations don't receive an initializer.


1 Answers

The data you provided is not enough to tell what is the actual cause but I'm going to summarize some possibilities.

What is the meaning of occurrence?

It means the compiler is type checking a method or property or expression multiple times.


How should I know what and where is that method and how much time exactly it takes?

By enabling these two flags you can see them directly in code:

-Xfrontend -warn-long-expression-type-checking=100
-Xfrontend -warn-long-function-bodies=100

What is that 100 in the flags?

That is the minimum time you aware. You can start with higher number and lowering it step by step after fixing more expensive issues.


How can I fix that?

By telling the compiler what you already know instead of letting it infer itself. for example:

let singleString = myStrings.joined(separator: ";") /* takes around 200ms to compile */
let singleTypedString: String = myStrings.joined(separator: ";") /* Takes just 1ms to compile */

As you can see, writing String type will eliminate 199 ms (on this moment)

you can find a more complicated example here in this answer where simple changes in code save about 2700ms !


Why the compiler doing it over and over?

Seems like some changes in newer Xcode versions, (I think one of them is the parallel building or etc.) caused this. LLDB and Swift language developers are working hard to boost the performance but we can help us ourselves.

Is there any workaround for preventing multiple type checking?

Depending on the source of the issue (variable, function, closure, lazy, etc.) there are some ways to enhance it. For example:

Making everything final and better than that, make them private where possible. This is how the compiler knows you are not going to override it, so it can type check just once.

This is how you can reduce your build time and prevent the compiler from type checking multiple times.

Hope it helps.



One more thing!:

According to this link in Swift.org:

-Xfrontend, which prompted this post. Every front-end argument is considered unstable. All of them. Even the ones that are the same as driver options. I'd really like to rename this but I don't know what to rename it too. (And to make matters worse, Xcode currently uses it for something. You don't want to know.)

So 1st, make sure you are using these flags only in DEBUG mode, And 2nd, turn them off after fixing the issues you were looking for and try them from time to time.

like image 155
Mojtaba Hosseini Avatar answered Sep 17 '22 08:09

Mojtaba Hosseini