Когда сборка занимает слишком много времени, очень полезно знать, что она делает. Bazel имеет встроенный инструментарий, который позволяет вам визуализировать, что каждый поток делает в любой момент сборки, и какие этапы сборки замедляют вашу общую сборку.
Чтобы опробовать инструменты профилирования Bazel, создайте свою любимую (или, скорее, наименее любимую) цель с --profile
опцией:
$ bazel build --profile=myprofile.out //snail:slow-lib
Это запишет профиль в файл myprofile.out в текущем каталоге. Как только ваша сборка завершится, вы сможете взглянуть на этот файл, но он не предназначен для чтения людьми. Вместо этого подключите его к analyze-profile
команде Базеля :
$ bazel analyze-profile --html myprofile.out
Теперь вы ждете, пока Базель проанализирует информацию в профиле и наслаждаетесь изображением улитки, которую я видел на днях, прогуливаясь по Домино (копейки включены в масштаб):
Сделайте ваш проект быстрее, чем этот.
(После того, как я сделал это фото, я переместил улитку на траву, так как я почти уверен, что ей не очень приятно находиться посреди тротуара в Нью-Йорке.)
Дин, анализ, вероятно, сделано. Теперь вы можете открыть myprofile.out.html и увидеть свою сборку, разбитую на сотни или тысячи отдельных шагов. Скриншот вывода:
Я загрузил HTML-страницу, чтобы вы могли увидеть все здесь и поиграть с ней (она откроется в новой вкладке).
Я использовал //android
цель из примера приложения для профиля выше, так как он немного более мясистый, чем игрушечный пример.
Диаграмма показывает, что все 200 потоков сборки делали во время сборки в любой момент времени (один поток на строку). Сборка разделена на несколько «фаз», которые показаны в виде разноцветных столбцов на графике:
- Первые 1,5 секунды (темно-серые) были потрачены на инициализацию команды сборки, а это означает, что она просто разбирает параметры и настраивает кэш.
- Следующая ~ 1 секунда (зеленая) была этапом загрузки, на котором Bazel выясняет, какие пакеты ему понадобятся, загружает внешние зависимости, а также находит и анализирует файлы BUILD.
- Следующими ~ 100 мс (полоска светло-серого цвета) была фаза анализа зависимостей, на которой Базель выяснила, какие зависимости были кешированы и очищены, и поэтому их не нужно перестраивать.
- Наконец, Базель перешел в фазу сборки (розовый фон), фактически собрав все, что нужно было построить.
Есть несколько других фаз, которые вы можете увидеть в легенде, но они, по большей части, слишком короткие, чтобы их можно было увидеть на графике.
Ниже графика есть раздел «Фаза выполнения». «Выполнение» может быть немного запутанным в этом контексте: оно относится к выполнению сборки, а не к запуску вашей программы. Фаза выполнения отображается в розовую фазу на приведенной выше диаграмме. В этом разделе есть подраздел «Критический путь», который разбивает то, что ожидала ваша сборка:
Critical path (13.339 s):
Id Time Percentage Description
6722 48.1 ms 0.36% Zipaligning apk
6721 344 ms 2.58% Generating signed apk
6720 540 ms 4.05% Converting bazel-out/local_darwin-fastbuild/bin/android/android_deploy.jar to dex format
6719 230 ms 1.73% Building deploy jar android/android_deploy.jar
6718 1.051 s 7.88% Building android/libandroid.jar (0 files)
6717 15.7 ms 0.12% Extracting interface //android activities
6716 1.744 s 13.07% Building android/libactivities.jar (1 files)
6715 785 ms 5.89% Processing resources
6712 3.737 s 28.01% Building external/default_android_tools/src/tools/android/java/com/google/devtools/build/android/libandroid_builder_lib.jar (17 files) [for host]
6711 4.843 s 36.30% Writing file external/default_android_tools/src/tools/android/java/com/google/devtools/build/android/libandroid_builder_lib.jar-2.params [for host]
1.73 ms 0.01% [2 middleman actions]
Как видите, сборка была «заблокирована» более чем на 8 секунд при сборке libandroid_builder_lib.jar и его файла параметров. К счастью, эти файлы не должны меняться между сборками (если вы не обновите свой Android SDK, что не должно происходить между каждой сборкой). Если я внесу изменения в libactivities.jar (собственно ядро программы) и пересоберу, я получу:
$ bazel build --profile profile2 //android
INFO: Writing profile data to '/Users/kchodorow/gitroot/examples/tutorial/profile2'
INFO: Found 1 target...
INFO: From Generating unsigned apk:
THIS TOOL IS DEPRECATED. See --help for more information.
INFO: From Generating signed apk:
THIS TOOL IS DEPRECATED. See --help for more information.
Target //android:android up-to-date:
bazel-bin/android/android_deploy.jar
bazel-bin/android/android_unsigned.apk
bazel-bin/android/android.apk
INFO: Elapsed time: 4.545s, Critical Path: 2.72s
Вот новая страница профиля для этой инкрементной сборки.
Обратите внимание, что критический путь составляет всего 2,718 секунды, а не 13,339! Если мы посмотрим на профиль, то увидим, что новый критический путь гораздо более изящен:
Critical path (2.718 s):
Id Time Percentage Description
543 52.3 ms 1.92% Zipaligning apk
542 342 ms 12.59% Generating signed apk
541 577 ms 21.22% Converting bazel-out/local_darwin-fastbuild/bin/android/android_deploy.jar to dex format
540 245 ms 9.00% Building deploy jar android/android_deploy.jar
539 1.502 s 55.26% Building android/libactivities.jar (1 files)
Сейчас сборка libactivities.jar является самой тяжелой операцией на критическом пути, поэтому мы могли бы решить эту проблему, разбив ее на отдельные библиотеки, которые не нужно перекомпилировать каждый раз, когда что-то меняется.
Профили, создаваемые Bazel, могут быть … плотными … поэтому не стесняйтесь спрашивать в списке рассылки, если вам нужна помощь в их интерпретации. Также, если вас интересует больше по теме, ознакомьтесь с документацией по профилированию .