Советы по настройке бэкенда LLVM
Компилятор Kotlin/Native использует LLVM для оптимизации и генерации исполняемых двоичных файлов для разных целевых платформ. Значительная часть времени компиляции также уходит на работу LLVM, и для больших приложений этот процесс может занимать неприемлемо много времени.
Вы можете настроить использование LLVM в Kotlin/Native и изменить список проходов оптимизации.
Изучите журнал сборки
Давайте посмотрим на журнал сборки, чтобы понять, сколько времени компиляции уходит на проходы оптимизации LLVM:
-
Запустите задачу Gradle
linkRelease*с параметром-Pkotlin.internal.compiler.arguments.log.level=warning, чтобы Gradle вывел сведения профилирования LLVM, например:./gradlew linkReleaseExecutableMacosArm64 -Pkotlin.internal.compiler.arguments.log.level=warning
Во время выполнения задача выводит необходимые аргументы компилятора, например:
> Task :linkReleaseExecutableMacosArm64 Run in-process tool "konanc" Entry point method = org.jetbrains.kotlin.cli.utilities.MainKt.daemonMain Classpath = [ /Users/user/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.0/konan/lib/kotlin-native-compiler-embeddable.jar /Users/user/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.0/konan/lib/trove4j.jar ] Arguments = [ -Xinclude=... -library /Users/user/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.0/klib/common/stdlib -no-endorsed-libs -nostdlib ... ] -
Запустите компилятор командной строки с указанными аргументами и аргументом
-Xprofile-phases, например:/Users/user/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.0/bin/kotlinc-native \ -Xinclude=... \ -library /Users/user/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.0/klib/common/stdlib \ ... \ -Xprofile-phases
Изучите сгенерированные данные в журнале сборки. Журнал может содержать десятки тысяч строк; разделы с профилированием LLVM находятся в конце.
Вот фрагмент журнала выполнения простой программы Kotlin/Native:
Frontend: 275 msec
PsiToIr: 1186 msec
...
... 30k lines
...
LinkBitcodeDependencies: 476 msec
StackProtectorPhase: 0 msec
MandatoryBitcodeLLVMPostprocessingPhase: 2 msec
===-------------------------------------------------------------------------===
Pass execution timing report
===-------------------------------------------------------------------------===
Total Execution Time: 6.7726 seconds (6.7192 wall clock)
---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
0.9778 ( 22.4%) 0.5043 ( 21.0%) 1.4821 ( 21.9%) 1.4628 ( 21.8%) InstCombinePass
0.3827 ( 8.8%) 0.2497 ( 10.4%) 0.6323 ( 9.3%) 0.6283 ( 9.4%) InlinerPass
0.2815 ( 6.4%) 0.1792 ( 7.5%) 0.4608 ( 6.8%) 0.4555 ( 6.8%) SimplifyCFGPass
...
0.6444 (100.0%) 0.5474 (100.0%) 1.1917 (100.0%) 1.1870 (100.0%) Total
ModuleBitcodeOptimization: 8118 msec
...
LTOBitcodeOptimization: 1399 msec
...
Компилятор Kotlin/Native запускает две отдельные последовательности оптимизации LLVM: проходы модуля и проходы на этапе компоновки. При обычной компиляции оба конвейера запускаются один за другим; единственное существенное различие заключается в том, какие проходы оптимизации LLVM они выполняют.
В журнале выше показаны две оптимизации LLVM: ModuleBitcodeOptimization и LTOBitcodeOptimization. Форматированные таблицы содержат результаты оптимизации и время выполнения каждого прохода.
Настройте проходы оптимизации LLVM
Если один из перечисленных выше проходов выполняется неоправданно долго, его можно пропустить. Однако это может снизить производительность во время выполнения, поэтому после этого следует проверить производительность по результатам тестов.
В настоящее время нет прямого способа отключить определенный проход. Однако можно задать новый список проходов, используя следующие параметры компилятора:
Параметр |
Значение по умолчанию для релизного двоичного файла |
|---|---|
|
|
|
|
Значения по умолчанию разворачиваются в длинный список фактических проходов, из которого нужно исключить ненужные.
Чтобы получить список фактических проходов, запустите инструмент opt, который автоматически загружается вместе с дистрибутивом LLVM в каталог ~/.konan/dependencies/llvm-{VERSION}-{ARCH}-{OS}-dev-{BUILD}/bin.
Например, чтобы получить список проходов на этапе компоновки, выполните команду:
opt -print-pipeline-passes -passes="internalize,globaldce,lto<O3>" < /dev/null
В результате выводится предупреждение и длинный список проходов, который зависит от версии LLVM.
Список проходов инструмента opt и проходы, которые фактически выполняет компилятор Kotlin/Native, различаются в двух аспектах:
Поскольку
opt— это инструмент отладки, он включает один или несколько проходовverify, которые обычно не выполняются.Kotlin/Native отключает проходы
devirt, поскольку компилятор Kotlin уже выполняет их самостоятельно.
После отключения любых проходов всегда повторно запускайте тесты производительности, чтобы проверить, приемлемо ли снижение производительности во время выполнения.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/native-llvm-passes.html