SlideShare a Scribd company logo
Speed up build time of
big project on
Objective-C + Swift
Ivan Bondar
Lead iOS developer in Avito
Build time: 194.803s
75% of build time - Compile Swift files phase
Swift:
- *.swift files: 626
- LOC: 27264
Project structure
Objective-C:
- *.m files: 729
- LOC: 45947
- 217 imports in bridging-header
What to do
• Tune build settings
• Reduce .swift files count
• Reduce extensions count
• Optimize slow compiling functions
• Fix warnings
• Apply ccache compiler cache utility
Tune build settings
Build Active Architecture Only
Enable Objective-C Modules
Debug data format - DWARF (no dsym file)
Enable Whole module optimization
Tune build settings
Debug data format - DWARF (no dsym file)
Build time: 191.623s (194.803s before)
Tune build settings
Whole module optimization
Main target build time: 76.614 s
Not suitable for debugging
Can’t compile unit test target - segfault or weird errors with
Swift-ObjC bridging
Reduce .swift files count
Pre-build action - merge all Swift code to one FAT
Swift file
Not suitable for big projects:
- can’t compile with segmentation fault 11
- eliminates «private» modifier
- can’t use breakpoints in the original source
Reduce .swift files count
Merge different classes/protocols in big .swift files
Not suitable for VIPER in general
Decided to apply only in certain cases, e.g.
put Input and Output protocol declarations in one file
Reduce extensions count
0
10
20
30
40
100 1000 2000 3000 5000 10000
methods extensions
* by Dmitry Bespalov
https://tech.zalando.com/blog/speeding-up-xcode-builds/
Reduce extensions count
class FilterViewController: UIViewController {
}
// MARK: UITableViewDelegate
extension FilterViewController: UITableViewDelegate {
}
// MARK: UITableViewDataSource
extension FilterViewController: UITableViewDataSource {
}
class FilterViewController: UIViewController,
UITableViewDelegate,
UITableViewDataSource {
// MARK: UITableViewDelegate
// MARK: UITableViewDataSource
}
Changes in code style applied
Before: After:
Extensions count reduced by 400
Build time: 94.3s (191.623s before)
Optimize slow compiling functions
Profile compile time per function, filter by time > 1 ms.
xcodebuild ARCHS=arm64 ONLY_ACTIVE_ARCH=NO -workspace App.xcworkspace -scheme App
clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep [1-9].
[0-9]ms | sort -nr > culprits.txt
Optimize slow compiling functions
What to fix:
• Functions with longest compile time
• Functions with big number of occurrences
2871.3ms /Users/iyubondar/Projects/avito-ios/Models/Domain/Advertisement/Advertisement/Base/AdvertisementImage.swift:2:5 init(url100x75:
String?, url140x105: String?, url240x180: String?, url432x324: String?, url640x480: String?, url1280x960: String?)
932.7ms /Users/iyubondar/Projects/avito-ios/Core/Extensions/UIKitExtensions/UICollectionView/UICollectionView+ChangeAnimations.swift:57:17
final class func changeSet<T : Hashable>(oldArray oldArray: [T], newArray: [T]) -> CollectionViewChangeSet
253.0ms /Users/iyubondar/Projects/avito-ios/Core/Extensions/UIKitExtensions/UICollectionView/UICollectionView+ChangeAnimations.swift:90:17
final class func changeSet<T>(oldArray oldArray: [T], newArray: [T], identityHashFunction: (T) -> Int, identityCheckFunction: (T, T) -> Bool,
equalityCheckFunction: (T, T) -> Bool = default) -> CollectionViewChangeSet
136.0ms /Users/iyubondar/Projects/avito-ios/Presentation/Views/Advertisement/AdvertisementView/AdvertisementPresenter.swift:9:26 @objc
public override func setModel(model: AnyObject!)
91.4ms/Users/iyubondar/Projects/avito-ios/Presentation/Views/Controls/PullToRefresh/ScrollViewRefresher.swift:251:18 private func
handleRefreshingProgressChanged(progress: RefreshingProgress)
84.0ms/Users/iyubondar/Projects/avito-ios/VIPER/SelectCategoryParameters/Validation/SelectFromToValidator.swift:52:25 private final class func
findValidRowIndex(valuesToSelect: [SelectCategoryParameterViewModel.Data], inCompareToValues compareValues:
[SelectCategoryParameterViewModel.Data]?, selectedRowIndex: Int, iterationOrder: IterationOrder) -> Int
82.5ms/Users/iyubondar/Projects/avito-ios/Presentation/Views/Profile/ProfileViewPresenter.swift:30:10 @objc func notificationsSubtitle() -> String
81.8ms<invalid loc> init?(rawValue: String)
currentDate: NSDate, calendar: NSCalendar, todayDateFormatter: NSDateFormatter, yesterdayDateFormatter: NSDateFormatter, weekdayDateFormatter:
NSDateFormatter, dayDateFormatter: NSDateFormatter, yearDayDateFormatter: NSDateFormatter, fullDateFormatter: NSDateFormatter) -> String
8659 occurrences found.
Use lazy only when it's necessary
1204 occurrences found
Compile time: 1.0 … 11.8 ms
Optimize slow compiling functions
private lazy var footerLabel: UILabel = {
let footerLabel = UILabel()
footerLabel.textColor = SpecColors.mainText
footerLabel.font = SpecFonts.regular(14)
footerLabel.autoresizingMask = .FlexibleWidth
footerLabel.lineBreakMode = .ByWordWrapping
footerLabel.numberOfLines = 0
footerLabel.textAlignment = .Center
footerLabel.shadowColor = UIColor.whiteColor()
footerLabel.shadowOffset = CGSize(width: 0, height: -1)
return footerLabel
}()
Avoid long expressions
Compile time: 2871.3ms
Optimize slow compiling functions
self.thumbnailUrl = url240x180 ?? url140x105 ?? url100x75 ?? nil
self.fullImageUrl = url640x480 ?? url432x324 ?? url1280x960 ?? url240x180 ??
url140x105 ?? url100x75 ?? nil
self.thumbnailUrl = url240x180 ?? url140x105 ?? url100x75
self.fullImageUrl = url640x480 ?? url432x324 ?? url1280x960 ?? url240x180 ??
url140x105 ?? url100x75
Compile time: 916 ms
Avoid long expressions
Optimize slow compiling functions
var fullImageUrl: String? {
if let url640x480 = url640x480 {
return url640x480
}
if let url432x324 = url432x324 {
return url432x324
}
…
if let url100x75 = url100x75 {
return url100x75
}
return nil
}
Compile time: <1 ms
Use map() and flatMap() with care
1177 occurrences found
Compile time: 2.5 … 21.8 ms
Optimize slow compiling functions
private lazy var tabControllers: [UIViewController] = {
var controllers = [UIViewController?](count: Tab.tabsCount, repeatedValue: nil)
controllers[Tab.Search.rawValue] = self.categoriesNavigationController()
controllers[Tab.Favorites.rawValue] = self.favoritesNavigationController()
controllers[Tab.Publish.rawValue] = self.publishNavigationController()
controllers[Tab.Messenger.rawValue] = self.channelsRootViewController()
controllers[Tab.Profile.rawValue] = self.profileNavigationController()
return controllers.flatMap { $0 }
}()
Use map() and flatMap() with care
Optimize slow compiling functions
Original example: http://irace.me/swift-profiling
return [CustomType()] + array.map(CustomType.init) + [CustomType()]
Compile time: 3158.2 ms and many occurrences
Give «type hints» to the compiler when necessary
* example by IMPATHIC
http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times
Optimize slow compiling functions
func hangCompiler() { ["A": [ ["B": [ 1, 2, 3, 4, 5 ]], ["C": [ ]], ["D": [ ["A":
[ 1 ]] ]] ]] }
Build time: 54.249 s
func hangCompiler() { ["A": [ ["B": [ 1, 2, 3, 4, 5 ]] as [String: [Int]], ["C": [ ]]
as [String: [Int]], ["D": [ ["A": [ 1 ]] as [String: [Int]] ]] ]] }
Build time: 1.293 s
Optimize slow compiling functions
Build time: 92.5s (94.3s before)
No great effect in our case
Before:
• 8659 functions > 1ms
• max time 2871.3мс
• median time 1.8ms
After:
• 2227 functions > 1ms
• max time 124.3мс
• median time 3.4ms
Fix warnings
Swift Compiler Warnings: 64 total
Warning type Count
Build time
after fix
Parameters of ... have different optionality 3 92.5s
User-defined 2 92.5s
Cannot find protocol definition 3 90.481s
Overriding instance method parameter with implicitly unwraped optional
type 27 warnings
27 90.195s
Deprecation 18 93.487s
<Some code> will never been executed 1 93.654s
Immutable value ... was never used 1 93.152s
Pointer is missing nullability specifier 9 80.667s
Build time: 80.667s (92.5s before)
Fix warnings
But, with 1 warning <Some code> will never been executed, build
time is 84.919s
Fix all Swift Compiler Warnings to speed up build time!
Apply ccache compiler cache utility
Build time: 68.403s (80.667s before)
ccache limitations:
- no support for Clang modules
- no support for precompiled headers
- no Swift support
ccache applied to project
What was done
Before: 194.803 s After: 68.403 s
There is no silver bullet :(
• Tune build settings - 3s
• Reduce .swift files count - 0s
• Reduce extensions count - 97s
• Optimize slow compiling functions - 2s
• Fix warnings - 12s
• Apply ccache compiler cache utility -12s
Injection for Xcode plugin:
+ dynamically inserts new Swift / Objective-C code into a
running app
+ support «tunable parameters»
Source: https://github.com/johnno1962/injectionforxcode
Injection for Xcode plugin:
Source: https://github.com/johnno1962/injectionforxcode
Swift limitations. It’s not possible to:
- Make changes to Structs.
- Change functions or classes that are marked as final.
- Change global functions or variables that are not
constrained into a class.
Split app into frameworks with no cyclic dependencies between
classes of different frameworks *
Plans
* idea and image: http://bits.citrusbyte.com/improving-swift-compile-time/
Further legacy code refactoring, remove Swift -
Objective C dependencies.
Plans
Links
• http://bits.citrusbyte.com/improving-swift-compile-time/
• http://stackoverflow.com/questions/25537614/why-is-swift-compile-time-so-slow
General:
• http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times
• http://irace.me/swift-profiling
Debug slow compile time:
• https://tech.zalando.com/blog/speeding-up-xcode-builds/
• https://gist.github.com/lucholaf/e37f4d26e406250a156a
Speed up builds:
• https://developer.apple.com/videos/play/wwdc2015/409/
• http://useyourloaf.com/blog/swift-whole-module-optimization/
• http://useyourloaf.com/blog/modules-and-precompiled-headers/
• https://labs.spotify.com/2013/11/04/shaving-off-time-from-the-ios-edit-build-test-cycle/
• http://tomj.io/2015/08/29/speed-up-your-swift-test-builds-by-70-percent.html
• https://pewpewthespells.com/blog/managing_xcode.html#dep-imp
Build settings:
• https://pspdfkit.com/blog/2015/ccache-for-fun-and-profit/
• https://ccache.samba.org/manual.html#_configuration
ccache utility:
Questions?
Ad

Recommended

Advanced Swift Generics
Advanced Swift Generics
Max Sokolov
 
Adopting Swift Generics
Adopting Swift Generics
Max Sokolov
 
Python in the database
Python in the database
pybcn
 
Rxjs ppt
Rxjs ppt
Christoffer Noring
 
Group111
Group111
Shahriar Robbani
 
Swift after one week of coding
Swift after one week of coding
SwiftWro
 
Mobile TechTalk - Interesting talks from NSConference 6
Mobile TechTalk - Interesting talks from NSConference 6
GlobalLogic Ukraine
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
Viliam Elischer
 
Oop assignment 02
Oop assignment 02
MamoonKhan39
 
Joblib for cloud computing
Joblib for cloud computing
Alexandre Abadie
 
PyParis2017 / Function-as-a-service - a pythonic perspective on severless com...
PyParis2017 / Function-as-a-service - a pythonic perspective on severless com...
Pôle Systematic Paris-Region
 
Swift Ready for Production?
Swift Ready for Production?
Crispy Mountain
 
Database connectivity in python
Database connectivity in python
baabtra.com - No. 1 supplier of quality freshers
 
Forgive me for i have allocated
Forgive me for i have allocated
Tomasz Kowalczewski
 
Angular2 inter3
Angular2 inter3
Oswald Campesato
 
RxJS 5 in Depth
RxJS 5 in Depth
C4Media
 
AWS Java SDK @ scale
AWS Java SDK @ scale
Tomasz Kowalczewski
 
Understanding reactive programming with microsoft reactive extensions
Understanding reactive programming with microsoft reactive extensions
Oleksandr Zhevzhyk
 
Mejores Practicas en SQL Server - Seguridad, Conectividad y CLR
Mejores Practicas en SQL Server - Seguridad, Conectividad y CLR
Juan Fabian
 
HTML5 video filters
HTML5 video filters
Artigiani del Web
 
Mongo db
Mongo db
Athira Mukundan
 
Talk KVO with rac by Philippe Converset
Talk KVO with rac by Philippe Converset
CocoaHeads France
 
Introduction to rx java for android
Introduction to rx java for android
Esa Firman
 
Using akka streams to access s3 objects
Using akka streams to access s3 objects
Mikhail Girkin
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
FDConf
 
Java Performance Tweaks
Java Performance Tweaks
Jim Bethancourt
 
はじめてのUnitTest XCTestに触れて
はじめてのUnitTest XCTestに触れて
Kenji Tanaka
 
Swift Sequences & Collections
Swift Sequences & Collections
CocoaHeads France
 
Swift
Swift
Quentin de Quelen
 
"Опыт миграции между дата-центрами" Сергей Бурладян и Михаил Тюрин (Avito)
"Опыт миграции между дата-центрами" Сергей Бурладян и Михаил Тюрин (Avito)
AvitoTech
 

More Related Content

What's hot (20)

Oop assignment 02
Oop assignment 02
MamoonKhan39
 
Joblib for cloud computing
Joblib for cloud computing
Alexandre Abadie
 
PyParis2017 / Function-as-a-service - a pythonic perspective on severless com...
PyParis2017 / Function-as-a-service - a pythonic perspective on severless com...
Pôle Systematic Paris-Region
 
Swift Ready for Production?
Swift Ready for Production?
Crispy Mountain
 
Database connectivity in python
Database connectivity in python
baabtra.com - No. 1 supplier of quality freshers
 
Forgive me for i have allocated
Forgive me for i have allocated
Tomasz Kowalczewski
 
Angular2 inter3
Angular2 inter3
Oswald Campesato
 
RxJS 5 in Depth
RxJS 5 in Depth
C4Media
 
AWS Java SDK @ scale
AWS Java SDK @ scale
Tomasz Kowalczewski
 
Understanding reactive programming with microsoft reactive extensions
Understanding reactive programming with microsoft reactive extensions
Oleksandr Zhevzhyk
 
Mejores Practicas en SQL Server - Seguridad, Conectividad y CLR
Mejores Practicas en SQL Server - Seguridad, Conectividad y CLR
Juan Fabian
 
HTML5 video filters
HTML5 video filters
Artigiani del Web
 
Mongo db
Mongo db
Athira Mukundan
 
Talk KVO with rac by Philippe Converset
Talk KVO with rac by Philippe Converset
CocoaHeads France
 
Introduction to rx java for android
Introduction to rx java for android
Esa Firman
 
Using akka streams to access s3 objects
Using akka streams to access s3 objects
Mikhail Girkin
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
FDConf
 
Java Performance Tweaks
Java Performance Tweaks
Jim Bethancourt
 
はじめてのUnitTest XCTestに触れて
はじめてのUnitTest XCTestに触れて
Kenji Tanaka
 
Swift Sequences & Collections
Swift Sequences & Collections
CocoaHeads France
 
Joblib for cloud computing
Joblib for cloud computing
Alexandre Abadie
 
PyParis2017 / Function-as-a-service - a pythonic perspective on severless com...
PyParis2017 / Function-as-a-service - a pythonic perspective on severless com...
Pôle Systematic Paris-Region
 
Swift Ready for Production?
Swift Ready for Production?
Crispy Mountain
 
RxJS 5 in Depth
RxJS 5 in Depth
C4Media
 
Understanding reactive programming with microsoft reactive extensions
Understanding reactive programming with microsoft reactive extensions
Oleksandr Zhevzhyk
 
Mejores Practicas en SQL Server - Seguridad, Conectividad y CLR
Mejores Practicas en SQL Server - Seguridad, Conectividad y CLR
Juan Fabian
 
Talk KVO with rac by Philippe Converset
Talk KVO with rac by Philippe Converset
CocoaHeads France
 
Introduction to rx java for android
Introduction to rx java for android
Esa Firman
 
Using akka streams to access s3 objects
Using akka streams to access s3 objects
Mikhail Girkin
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
FDConf
 
はじめてのUnitTest XCTestに触れて
はじめてのUnitTest XCTestに触れて
Kenji Tanaka
 
Swift Sequences & Collections
Swift Sequences & Collections
CocoaHeads France
 

Viewers also liked (20)

Swift
Swift
Quentin de Quelen
 
"Опыт миграции между дата-центрами" Сергей Бурладян и Михаил Тюрин (Avito)
"Опыт миграции между дата-центрами" Сергей Бурладян и Михаил Тюрин (Avito)
AvitoTech
 
"Marshroute: удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Av...
"Marshroute: удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Av...
AvitoTech
 
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
AvitoTech
 
"Favicon на стероидах" Александр Амосов (Avito)
"Favicon на стероидах" Александр Амосов (Avito)
AvitoTech
 
"Икскод, джейсон, два скетча" Олег Фролов (Avito)
"Икскод, джейсон, два скетча" Олег Фролов (Avito)
AvitoTech
 
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
AvitoTech
 
"Деплой кода процедур" Мурат Кабилов (Avito)
"Деплой кода процедур" Мурат Кабилов (Avito)
AvitoTech
 
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
AvitoTech
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
AvitoTech
 
"Удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Avito)
"Удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Avito)
AvitoTech
 
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...
AvitoTech
 
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
AvitoTech
 
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Ontico
 
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
AvitoTech
 
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
AvitoTech
 
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
AvitoTech
 
"Секционирование без границ" Ильдар Мусин (Postgres Professional)
"Секционирование без границ" Ильдар Мусин (Postgres Professional)
AvitoTech
 
"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)
AvitoTech
 
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
AvitoTech
 
"Опыт миграции между дата-центрами" Сергей Бурладян и Михаил Тюрин (Avito)
"Опыт миграции между дата-центрами" Сергей Бурладян и Михаил Тюрин (Avito)
AvitoTech
 
"Marshroute: удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Av...
"Marshroute: удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Av...
AvitoTech
 
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
AvitoTech
 
"Favicon на стероидах" Александр Амосов (Avito)
"Favicon на стероидах" Александр Амосов (Avito)
AvitoTech
 
"Икскод, джейсон, два скетча" Олег Фролов (Avito)
"Икскод, джейсон, два скетча" Олег Фролов (Avito)
AvitoTech
 
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
AvitoTech
 
"Деплой кода процедур" Мурат Кабилов (Avito)
"Деплой кода процедур" Мурат Кабилов (Avito)
AvitoTech
 
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
AvitoTech
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
AvitoTech
 
"Удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Avito)
"Удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Avito)
AvitoTech
 
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...
AvitoTech
 
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
AvitoTech
 
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Ontico
 
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
AvitoTech
 
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
AvitoTech
 
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
AvitoTech
 
"Секционирование без границ" Ильдар Мусин (Postgres Professional)
"Секционирование без границ" Ильдар Мусин (Postgres Professional)
AvitoTech
 
"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)
AvitoTech
 
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
AvitoTech
 
Ad

Similar to "Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito) (20)

DevOps Practices @Pipedrive
DevOps Practices @Pipedrive
Renno Reinurm
 
Building source code level profiler for C++.pdf
Building source code level profiler for C++.pdf
ssuser28de9e
 
Distributed Automation(2018) - London Test Automation in Devops Meetup
Distributed Automation(2018) - London Test Automation in Devops Meetup
aragavan
 
Advanced iOS Build Mechanics, Sebastien Pouliot
Advanced iOS Build Mechanics, Sebastien Pouliot
Xamarin
 
Apache Druid Auto Scale-out/in for Streaming Data Ingestion on Kubernetes
Apache Druid Auto Scale-out/in for Streaming Data Ingestion on Kubernetes
DataWorks Summit
 
Francisco Javier Ramirez Urea - Hopla - OSL19
Francisco Javier Ramirez Urea - Hopla - OSL19
marketingsyone
 
Advanced Cassandra
Advanced Cassandra
DataStax Academy
 
SDAccel Design Contest: Vivado HLS
SDAccel Design Contest: Vivado HLS
NECST Lab @ Politecnico di Milano
 
OSMC 2023 | Replacing NSClient++ for Windows Monitoring by Sven Nielein
OSMC 2023 | Replacing NSClient++ for Windows Monitoring by Sven Nielein
NETWAYS
 
SNClient+ - General purpose monitoring agent
SNClient+ - General purpose monitoring agent
Sven Nierlein
 
Why use Gitlab
Why use Gitlab
abenyeung1
 
Why and How to Run Your Own Gitlab Runners as Your Company Grows
Why and How to Run Your Own Gitlab Runners as Your Company Grows
NGINX, Inc.
 
Scaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container Service
Ben Hall
 
Infrastructure development using Consul
Infrastructure development using Consul
Grid Dynamics
 
Improving app performance with Kotlin Coroutines
Improving app performance with Kotlin Coroutines
Hassan Abid
 
Continuous Deployment with Kubernetes, Docker and GitLab CI
Continuous Deployment with Kubernetes, Docker and GitLab CI
alexanderkiel
 
AWS ECS workshop
AWS ECS workshop
Prashant Kalkar
 
CiklumCPPSat: Alexey Podoba "Automatic assembly. Cmake"
CiklumCPPSat: Alexey Podoba "Automatic assembly. Cmake"
Ciklum Ukraine
 
Azure machine learning service
Azure machine learning service
Ruth Yakubu
 
Feedback on building Production-Ready Microsoft Teams Apps
Feedback on building Production-Ready Microsoft Teams Apps
Guillaume Meyer
 
DevOps Practices @Pipedrive
DevOps Practices @Pipedrive
Renno Reinurm
 
Building source code level profiler for C++.pdf
Building source code level profiler for C++.pdf
ssuser28de9e
 
Distributed Automation(2018) - London Test Automation in Devops Meetup
Distributed Automation(2018) - London Test Automation in Devops Meetup
aragavan
 
Advanced iOS Build Mechanics, Sebastien Pouliot
Advanced iOS Build Mechanics, Sebastien Pouliot
Xamarin
 
Apache Druid Auto Scale-out/in for Streaming Data Ingestion on Kubernetes
Apache Druid Auto Scale-out/in for Streaming Data Ingestion on Kubernetes
DataWorks Summit
 
Francisco Javier Ramirez Urea - Hopla - OSL19
Francisco Javier Ramirez Urea - Hopla - OSL19
marketingsyone
 
OSMC 2023 | Replacing NSClient++ for Windows Monitoring by Sven Nielein
OSMC 2023 | Replacing NSClient++ for Windows Monitoring by Sven Nielein
NETWAYS
 
SNClient+ - General purpose monitoring agent
SNClient+ - General purpose monitoring agent
Sven Nierlein
 
Why use Gitlab
Why use Gitlab
abenyeung1
 
Why and How to Run Your Own Gitlab Runners as Your Company Grows
Why and How to Run Your Own Gitlab Runners as Your Company Grows
NGINX, Inc.
 
Scaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container Service
Ben Hall
 
Infrastructure development using Consul
Infrastructure development using Consul
Grid Dynamics
 
Improving app performance with Kotlin Coroutines
Improving app performance with Kotlin Coroutines
Hassan Abid
 
Continuous Deployment with Kubernetes, Docker and GitLab CI
Continuous Deployment with Kubernetes, Docker and GitLab CI
alexanderkiel
 
CiklumCPPSat: Alexey Podoba "Automatic assembly. Cmake"
CiklumCPPSat: Alexey Podoba "Automatic assembly. Cmake"
Ciklum Ukraine
 
Azure machine learning service
Azure machine learning service
Ruth Yakubu
 
Feedback on building Production-Ready Microsoft Teams Apps
Feedback on building Production-Ready Microsoft Teams Apps
Guillaume Meyer
 
Ad

More from AvitoTech (20)

Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
AvitoTech
 
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
AvitoTech
 
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
AvitoTech
 
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoTech
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений Фомченко
AvitoTech
 
Migro - Юрий Богомолов
Migro - Юрий Богомолов
AvitoTech
 
TableKit - Максим Соколов
TableKit - Максим Соколов
AvitoTech
 
Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)
AvitoTech
 
SimplePEG - Алексей Охрименко
SimplePEG - Алексей Охрименко
AvitoTech
 
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
AvitoTech
 
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
AvitoTech
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
AvitoTech
 
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
AvitoTech
 
ASO for iOS 11
ASO for iOS 11
AvitoTech
 
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
AvitoTech
 
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
AvitoTech
 
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
AvitoTech
 
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
AvitoTech
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
AvitoTech
 
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
AvitoTech
 
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
AvitoTech
 
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
AvitoTech
 
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
AvitoTech
 
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoTech
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений Фомченко
AvitoTech
 
Migro - Юрий Богомолов
Migro - Юрий Богомолов
AvitoTech
 
TableKit - Максим Соколов
TableKit - Максим Соколов
AvitoTech
 
Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)
AvitoTech
 
SimplePEG - Алексей Охрименко
SimplePEG - Алексей Охрименко
AvitoTech
 
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
AvitoTech
 
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
AvitoTech
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
AvitoTech
 
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
AvitoTech
 
ASO for iOS 11
ASO for iOS 11
AvitoTech
 
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
AvitoTech
 
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
AvitoTech
 
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
AvitoTech
 
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
AvitoTech
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
AvitoTech
 
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
AvitoTech
 

"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)

  • 1. Speed up build time of big project on Objective-C + Swift Ivan Bondar Lead iOS developer in Avito
  • 2. Build time: 194.803s 75% of build time - Compile Swift files phase Swift: - *.swift files: 626 - LOC: 27264 Project structure Objective-C: - *.m files: 729 - LOC: 45947 - 217 imports in bridging-header
  • 3. What to do • Tune build settings • Reduce .swift files count • Reduce extensions count • Optimize slow compiling functions • Fix warnings • Apply ccache compiler cache utility
  • 4. Tune build settings Build Active Architecture Only Enable Objective-C Modules Debug data format - DWARF (no dsym file) Enable Whole module optimization
  • 5. Tune build settings Debug data format - DWARF (no dsym file) Build time: 191.623s (194.803s before)
  • 6. Tune build settings Whole module optimization Main target build time: 76.614 s Not suitable for debugging Can’t compile unit test target - segfault or weird errors with Swift-ObjC bridging
  • 7. Reduce .swift files count Pre-build action - merge all Swift code to one FAT Swift file Not suitable for big projects: - can’t compile with segmentation fault 11 - eliminates «private» modifier - can’t use breakpoints in the original source
  • 8. Reduce .swift files count Merge different classes/protocols in big .swift files Not suitable for VIPER in general Decided to apply only in certain cases, e.g. put Input and Output protocol declarations in one file
  • 9. Reduce extensions count 0 10 20 30 40 100 1000 2000 3000 5000 10000 methods extensions * by Dmitry Bespalov https://tech.zalando.com/blog/speeding-up-xcode-builds/
  • 10. Reduce extensions count class FilterViewController: UIViewController { } // MARK: UITableViewDelegate extension FilterViewController: UITableViewDelegate { } // MARK: UITableViewDataSource extension FilterViewController: UITableViewDataSource { } class FilterViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { // MARK: UITableViewDelegate // MARK: UITableViewDataSource } Changes in code style applied Before: After: Extensions count reduced by 400 Build time: 94.3s (191.623s before)
  • 11. Optimize slow compiling functions Profile compile time per function, filter by time > 1 ms. xcodebuild ARCHS=arm64 ONLY_ACTIVE_ARCH=NO -workspace App.xcworkspace -scheme App clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep [1-9]. [0-9]ms | sort -nr > culprits.txt
  • 12. Optimize slow compiling functions What to fix: • Functions with longest compile time • Functions with big number of occurrences 2871.3ms /Users/iyubondar/Projects/avito-ios/Models/Domain/Advertisement/Advertisement/Base/AdvertisementImage.swift:2:5 init(url100x75: String?, url140x105: String?, url240x180: String?, url432x324: String?, url640x480: String?, url1280x960: String?) 932.7ms /Users/iyubondar/Projects/avito-ios/Core/Extensions/UIKitExtensions/UICollectionView/UICollectionView+ChangeAnimations.swift:57:17 final class func changeSet<T : Hashable>(oldArray oldArray: [T], newArray: [T]) -> CollectionViewChangeSet 253.0ms /Users/iyubondar/Projects/avito-ios/Core/Extensions/UIKitExtensions/UICollectionView/UICollectionView+ChangeAnimations.swift:90:17 final class func changeSet<T>(oldArray oldArray: [T], newArray: [T], identityHashFunction: (T) -> Int, identityCheckFunction: (T, T) -> Bool, equalityCheckFunction: (T, T) -> Bool = default) -> CollectionViewChangeSet 136.0ms /Users/iyubondar/Projects/avito-ios/Presentation/Views/Advertisement/AdvertisementView/AdvertisementPresenter.swift:9:26 @objc public override func setModel(model: AnyObject!) 91.4ms/Users/iyubondar/Projects/avito-ios/Presentation/Views/Controls/PullToRefresh/ScrollViewRefresher.swift:251:18 private func handleRefreshingProgressChanged(progress: RefreshingProgress) 84.0ms/Users/iyubondar/Projects/avito-ios/VIPER/SelectCategoryParameters/Validation/SelectFromToValidator.swift:52:25 private final class func findValidRowIndex(valuesToSelect: [SelectCategoryParameterViewModel.Data], inCompareToValues compareValues: [SelectCategoryParameterViewModel.Data]?, selectedRowIndex: Int, iterationOrder: IterationOrder) -> Int 82.5ms/Users/iyubondar/Projects/avito-ios/Presentation/Views/Profile/ProfileViewPresenter.swift:30:10 @objc func notificationsSubtitle() -> String 81.8ms<invalid loc> init?(rawValue: String) currentDate: NSDate, calendar: NSCalendar, todayDateFormatter: NSDateFormatter, yesterdayDateFormatter: NSDateFormatter, weekdayDateFormatter: NSDateFormatter, dayDateFormatter: NSDateFormatter, yearDayDateFormatter: NSDateFormatter, fullDateFormatter: NSDateFormatter) -> String 8659 occurrences found.
  • 13. Use lazy only when it's necessary 1204 occurrences found Compile time: 1.0 … 11.8 ms Optimize slow compiling functions private lazy var footerLabel: UILabel = { let footerLabel = UILabel() footerLabel.textColor = SpecColors.mainText footerLabel.font = SpecFonts.regular(14) footerLabel.autoresizingMask = .FlexibleWidth footerLabel.lineBreakMode = .ByWordWrapping footerLabel.numberOfLines = 0 footerLabel.textAlignment = .Center footerLabel.shadowColor = UIColor.whiteColor() footerLabel.shadowOffset = CGSize(width: 0, height: -1) return footerLabel }()
  • 14. Avoid long expressions Compile time: 2871.3ms Optimize slow compiling functions self.thumbnailUrl = url240x180 ?? url140x105 ?? url100x75 ?? nil self.fullImageUrl = url640x480 ?? url432x324 ?? url1280x960 ?? url240x180 ?? url140x105 ?? url100x75 ?? nil self.thumbnailUrl = url240x180 ?? url140x105 ?? url100x75 self.fullImageUrl = url640x480 ?? url432x324 ?? url1280x960 ?? url240x180 ?? url140x105 ?? url100x75 Compile time: 916 ms
  • 15. Avoid long expressions Optimize slow compiling functions var fullImageUrl: String? { if let url640x480 = url640x480 { return url640x480 } if let url432x324 = url432x324 { return url432x324 } … if let url100x75 = url100x75 { return url100x75 } return nil } Compile time: <1 ms
  • 16. Use map() and flatMap() with care 1177 occurrences found Compile time: 2.5 … 21.8 ms Optimize slow compiling functions private lazy var tabControllers: [UIViewController] = { var controllers = [UIViewController?](count: Tab.tabsCount, repeatedValue: nil) controllers[Tab.Search.rawValue] = self.categoriesNavigationController() controllers[Tab.Favorites.rawValue] = self.favoritesNavigationController() controllers[Tab.Publish.rawValue] = self.publishNavigationController() controllers[Tab.Messenger.rawValue] = self.channelsRootViewController() controllers[Tab.Profile.rawValue] = self.profileNavigationController() return controllers.flatMap { $0 } }()
  • 17. Use map() and flatMap() with care Optimize slow compiling functions Original example: http://irace.me/swift-profiling return [CustomType()] + array.map(CustomType.init) + [CustomType()] Compile time: 3158.2 ms and many occurrences
  • 18. Give «type hints» to the compiler when necessary * example by IMPATHIC http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times Optimize slow compiling functions func hangCompiler() { ["A": [ ["B": [ 1, 2, 3, 4, 5 ]], ["C": [ ]], ["D": [ ["A": [ 1 ]] ]] ]] } Build time: 54.249 s func hangCompiler() { ["A": [ ["B": [ 1, 2, 3, 4, 5 ]] as [String: [Int]], ["C": [ ]] as [String: [Int]], ["D": [ ["A": [ 1 ]] as [String: [Int]] ]] ]] } Build time: 1.293 s
  • 19. Optimize slow compiling functions Build time: 92.5s (94.3s before) No great effect in our case Before: • 8659 functions > 1ms • max time 2871.3мс • median time 1.8ms After: • 2227 functions > 1ms • max time 124.3мс • median time 3.4ms
  • 20. Fix warnings Swift Compiler Warnings: 64 total Warning type Count Build time after fix Parameters of ... have different optionality 3 92.5s User-defined 2 92.5s Cannot find protocol definition 3 90.481s Overriding instance method parameter with implicitly unwraped optional type 27 warnings 27 90.195s Deprecation 18 93.487s <Some code> will never been executed 1 93.654s Immutable value ... was never used 1 93.152s Pointer is missing nullability specifier 9 80.667s Build time: 80.667s (92.5s before)
  • 21. Fix warnings But, with 1 warning <Some code> will never been executed, build time is 84.919s Fix all Swift Compiler Warnings to speed up build time!
  • 22. Apply ccache compiler cache utility Build time: 68.403s (80.667s before) ccache limitations: - no support for Clang modules - no support for precompiled headers - no Swift support ccache applied to project
  • 23. What was done Before: 194.803 s After: 68.403 s There is no silver bullet :( • Tune build settings - 3s • Reduce .swift files count - 0s • Reduce extensions count - 97s • Optimize slow compiling functions - 2s • Fix warnings - 12s • Apply ccache compiler cache utility -12s
  • 24. Injection for Xcode plugin: + dynamically inserts new Swift / Objective-C code into a running app + support «tunable parameters» Source: https://github.com/johnno1962/injectionforxcode
  • 25. Injection for Xcode plugin: Source: https://github.com/johnno1962/injectionforxcode Swift limitations. It’s not possible to: - Make changes to Structs. - Change functions or classes that are marked as final. - Change global functions or variables that are not constrained into a class.
  • 26. Split app into frameworks with no cyclic dependencies between classes of different frameworks * Plans * idea and image: http://bits.citrusbyte.com/improving-swift-compile-time/
  • 27. Further legacy code refactoring, remove Swift - Objective C dependencies. Plans
  • 28. Links • http://bits.citrusbyte.com/improving-swift-compile-time/ • http://stackoverflow.com/questions/25537614/why-is-swift-compile-time-so-slow General: • http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times • http://irace.me/swift-profiling Debug slow compile time: • https://tech.zalando.com/blog/speeding-up-xcode-builds/ • https://gist.github.com/lucholaf/e37f4d26e406250a156a Speed up builds: • https://developer.apple.com/videos/play/wwdc2015/409/ • http://useyourloaf.com/blog/swift-whole-module-optimization/ • http://useyourloaf.com/blog/modules-and-precompiled-headers/ • https://labs.spotify.com/2013/11/04/shaving-off-time-from-the-ios-edit-build-test-cycle/ • http://tomj.io/2015/08/29/speed-up-your-swift-test-builds-by-70-percent.html • https://pewpewthespells.com/blog/managing_xcode.html#dep-imp Build settings: • https://pspdfkit.com/blog/2015/ccache-for-fun-and-profit/ • https://ccache.samba.org/manual.html#_configuration ccache utility: