Otimização do tempo de construção - Parte 1

Quase todo desenvolvedor, pelo menos uma vez, encontrou um tempo de compilação bastante longo para seu projeto. Isso leva à redução da produtividade e diminui o processo de desenvolvimento de toda a equipe. Como você pode ver, aumentar o tempo de construção de um projeto é crucial, pois tem um impacto direto no momento em que o aplicativo é publicado na AppStore e na liberação mais rápida de novos recursos em seu aplicativo.

Neste artigo, aprenderemos como criar um perfil para uma montagem no Xcode e obter métricas. No próximo artigo, falarei sobre métodos para eliminar gargalos e acelerar a montagem do projeto. Também deve ser mencionado que usaremos o projeto iOS do Kickstarter, que pode ser encontrado no Github . Então vamos começar!

O que estamos medindo?


A primeira coisa que devemos fazer é determinar o que estamos tentando medir e otimizar. Duas opções podem ser consideradas:

  • Construção limpa - limpe e construa o projeto. Geralmente, as compilações limpas são feitas no IC para verificar uma nova solicitação de recebimento e executar testes de unidade.
  • Construção incremental - construa o projeto após alterações significativas no código-fonte. Este assembly é criado pelo desenvolvedor enquanto trabalha com novas funcionalidades.

Na maioria dos casos, reduzir o tempo durante a compilação Limpa também deve acelerar a compilação Incremental . A melhor opção seria criar métricas para os dois tipos de montagens e rastreá-las. Mediremos o tempo de construção usando a configuração Debug apenas porque é usada na maioria das vezes e tem um impacto maior no desenvolvimento.

Nós calculamos o tempo de montagem


A maneira mais eficaz de melhorar o tempo de construção deve ser uma abordagem baseada na implementação e verificação de alterações com base em métricas específicas. Considere-os, bem como as ferramentas que podemos usar para obter informações sobre o tempo de construção do projeto.

Relatório de tempo de construção do Xcode


Podemos facilmente obter dados de tempo de construção usando o Xcode. Ele rastreia todas as construções por padrão e permite visualizar o tempo de construção do projeto no navegador de relatórios.

imagem

Você também tem a opção de exibir informações semelhantes no Xcode no painel do visualizador de atividades . Ele pode ser ativado para exibição usando a linha de comando, executando o comando: O tempo de construção do projeto é exibido após a montagem, junto com a mensagem “Succeeded”. Essas são apenas duas opções básicas que devem fornecer uma idéia aproximada do tempo de criação Limpo e Incremental .

defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES



imagem



Resumo do tempo de construção do projeto no Xcode


Resumo do tempo de construção do Xcode - Seu primeiro amigo para obter estatísticas e gargalos do tempo de construção. Você pode executá-lo através de Produto-> Executar Ação-> Resumo do Compilação com Tempo . Agora você verá um grande detalhamento do tempo gasto em várias tarefas:

imagem

Esse método deve ser um bom ponto de partida para encontrar as tarefas que consomem mais tempo no processo de montagem. A captura de tela acima mostra que as fases CompileStoryboard , CompileXIB , CompileSwiftSources e PhaseScriptExecution levaram a maior parte do tempo de compilação. O Xcode conseguiu concluir parte das tarefas em paralelo, para que a montagem seja concluída muito mais rapidamente do que o tempo necessário para concluir a tarefa de cada um dos comandos.

Podemos obter um resumo do tempo de compilação para a compilação limpa usando o xcodebuild com a opção - buildWithTimingSummary : Agora vamos obter métricas semelhantes para a compilação incremental. Deve-se observar que o tempo de criação incremental depende completamente dos arquivos que estão sendo modificados no projeto. Para obter resultados consistentes, você pode modificar um arquivo e compilar o projeto. Diferentemente dos sistemas Buck ou Bazel, o Xcode usa registros de data e hora para determinar o que mudou e o que precisa ser reconstruído. Podemos atualizar o carimbo de data / hora usando o toque:

xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
-showBuildTimingSummary \
clean build | sed -n -e '/Build Timing Summary/,$p'

Build Timing Summary
CompileStoryboard (29 tasks) | 87.128 seconds
CompileSwiftSources (4 tasks) | 54.144 seconds
PhaseScriptExecution (14 tasks) | 18.167 seconds
CompileAssetCatalog (2 tasks) | 6.532 seconds
CompileXIB (21 tasks) | 6.293 seconds
CodeSign (7 tasks) | 3.069 seconds
Ld (4 tasks) | 2.342 seconds
LinkStoryboards (2 tasks) | 0.172 seconds
CompileC (3 tasks) | 0.122 seconds
Ditto (20 tasks) | 0.076 seconds
Touch (4 tasks) | 0.007 seconds
** BUILD SUCCEEDED ** [92.620 sec]



touch KsApi/mutations/CancelBackingMutation.swift && \
xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
-showBuildTimingSummary \
build | sed -n -e '/Build Timing Summary/,$p'

Build Timing Summary
PhaseScriptExecution (14 tasks) | 18.089 seconds
CodeSign (7 tasks) | 2.990 seconds
CompileSwiftSources (1 task) | 1.245 seconds
Ld (1 task) | 0.361 seconds
** BUILD SUCCEEDED ** [23.927 sec]

Avisos de verificação de tipo


Quando o tempo de compilação é um gargalo, podemos obter mais informações definindo Outros Swift Flags nas opções de criação do projeto no Xcode. Quando o sinalizador está ativado, o Xcode gera um aviso para qualquer função ou expressão que leva mais de 100 ms para determinar o tipo de variáveis:

  • -Xfrontend -warn-long-function-corpos = 100
  • -Xfrontend -warn-long-expression-type-verificação = 100

imagem

Agora você sabe o código com o qual o compilador Swift tem problemas e agora pode tentar aprimorá-lo.

Opções de diagnóstico do compilador


O compilador Swift possui muitas opções de diagnóstico internas que você pode usar para criar um perfil da montagem.

  • -driver-time-compilation - um alto nível de sincronização de tarefas executadas pelo driver.
  • -Xfrontend -debug-time-compilation — .
  • -Xfrontend -debug-time-function-bodies – .
  • -Xfrontend -debug-time-expression-type-checking – .

Vamos usar o sinalizador -debug-time-compilation para obter informações sobre os arquivos mais lentos ao compilar: Como você pode ver, foram necessários 25 segundos para compilar SettingsNewslettersCellViewModel.swift . No log de montagem, é possível obter informações adicionais sobre o tempo de compilação do arquivo: Agora é óbvio que a verificação de tipo e a análise semântica são o trabalho que consome mais tempo. Vamos seguir em frente e listar as funções e expressões mais lentas na etapa Verificação de tipo :

xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
clean build \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-compilation" |
awk '/CompileSwift normal/,/Swift compilation/{print; getline; print; getline; print}' |
grep -Eo "^CompileSwift.+\.swift|\d+\.\d+ seconds" |
sed -e 'N;s/\(.*\)\n\(.*\)/\2 \1/' |
sed -e "s|CompileSwift normal x86_64 $(pwd)/||" |
sort -rn |
head -3

25.6026 seconds Library/ViewModels/SettingsNewslettersCellViewModel.swift
24.4429 seconds Library/ViewModels/PledgeSummaryViewModel.swift
24.4312 seconds Library/ViewModels/PaymentMethodsViewModel.swift



===-------------------------------------------------------------------------===
Swift compilation
===-------------------------------------------------------------------------===
Total Execution Time: 25.6026 seconds (26.6593 wall clock)

---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
24.4632 ( 98.3%) 0.5406 ( 76.5%) 25.0037 ( 97.7%) 26.0001 ( 97.5%) Type checking and Semantic analysis
0.0981 ( 0.4%) 0.1383 ( 19.6%) 0.2364 ( 0.9%) 0.2872 ( 1.1%) Name binding
0.1788 ( 0.7%) 0.0043 ( 0.6%) 0.1831 ( 0.7%) 0.1839 ( 0.7%) IRGen
0.0508 ( 0.2%) 0.0049 ( 0.7%) 0.0557 ( 0.2%) 0.0641 ( 0.2%) Parsing
0.0599 ( 0.2%) 0.0020 ( 0.3%) 0.0619 ( 0.2%) 0.0620 ( 0.2%) SILGen
0.0285 ( 0.1%) 0.0148 ( 2.1%) 0.0433 ( 0.2%) 0.0435 ( 0.2%) SIL optimization
0.0146 ( 0.1%) 0.0015 ( 0.2%) 0.0161 ( 0.1%) 0.0162 ( 0.1%) Serialization, swiftmodule
0.0016 ( 0.0%) 0.0006 ( 0.1%) 0.0022 ( 0.0%) 0.0022 ( 0.0%) Serialization, swiftdoc
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0001 ( 0.0%) SIL verification, pre-optimization
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) AST verification
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) SIL verification, post-optimization
24.8956 (100.0%) 0.7069 (100.0%) 25.6026 (100.0%) 26.6593 (100.0%) Total



xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
clean build \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-expression-type-checking \
-Xfrontend -debug-time-function-bodies" |
grep -o "^\d*.\d*ms\t[^$]*$" |
awk '!visited[$0]++' |
sed -e "s|$(pwd)/||" |
sort -rn |
head -5

16226.04ms Library/Styles/UpdateDraftStyles.swift:31:3
10551.24ms Kickstarter-iOS/Views/RewardCardContainerView.swift:171:16 instance method configureBaseGradientView()
10547.41ms Kickstarter-iOS/Views/RewardCardContainerView.swift:172:7
8639.30ms Kickstarter-iOS/Views/Controllers/AddNewCardViewController.swift:396:67
8233.27ms KsApi/models/templates/ProjectTemplates.swift:94:5

Da mesma forma, criamos perfil de nossa montagem e descobrimos que, na fase de verificação de tipo, existem gargalos. Como próximo passo, você pode dar uma olhada nas funções e expressões listadas acima e tentar otimizar a inferência de tipo .

Tempo de construção desejado


É aconselhável medir o tempo de montagem do alvo separadamente e exibi-los no gráfico. Você pode ajudar a entender quais destinos estão sendo coletados ou podem ser coletados em paralelo. Para fazer isso, você pode usar a ferramenta xcode-build-time-rendering. Vamos defini-lo como RubyGem: Após a conclusão da instalação, execute o seguinte comando para inserir o registro de data e hora na Fase de Criação de Script de Execução de seus destinos: Em seguida, compile o projeto e o relatório usando: Como resultado, você deve obter um bom gráfico de Gantt por tempo de compilação que mostre o tempo montagens de todos os seus alvos:

gem install xcode-build-times



xcode-build-times install



xcode-build-times generate



imagem

Métricas agregadas


Seria ótimo agregar os vários indicadores mencionados acima. XCLogParser é uma ótima ferramenta que pode ajudá-lo com isso. É um analisador de log para o xcactivitylog gerado pelo Xcode, e fornece muitas informações sobre o tempo de compilação para cada módulo e arquivo no projeto, avisos, erros e resultados de teste de unidade. Você pode instalá-lo clonando o repositório e iniciando pela linha de comando: Este é um relatório criado para o projeto iOS do Kickstarter:

git clone https://github.com/spotify/XCLogParser
rake build
xclogparser parse --project Kickstarter --reporter html



imagem

Automação


Note-se que as métricas de tempo de montagem dependem do hardware e de seu uso. Você pode usar seu equipamento para experimentos. A melhor opção seria automatizar o processo o máximo possível e usar equipamentos de CI dedicados para métricas diárias. Por fim, eles podem ser monitorados no painel e notificados sobre o agravamento dos tempos de construção usando o Slack.

Conclusão


Reduzir o tempo de construção de um projeto é fundamental para melhorar a produtividade do desenvolvedor. Hoje aprendemos como medir o tempo de construção de um projeto e obter algumas métricas para análise ...

Na próxima publicação, consideraremos métodos que podem ser usados ​​para reduzir o tempo de construção.

Obrigado pela leitura!

All Articles