Оптимизация на основе профиля (PGO) — это хорошо известный метод оптимизации компилятора. В PGO профили времени выполнения программы используются компилятором для принятия оптимальных решений относительно встраивания и компоновки кода. Это приводит к повышению производительности и уменьшению размера кода.
PGO можно развернуть в вашем приложении или библиотеке, выполнив следующие действия: 1. Определите репрезентативную рабочую нагрузку. 2. Соберите анкеты. 3. Используйте профили в сборке Release.
Шаг 1. Определите репрезентативную рабочую нагрузку
Сначала определите репрезентативный тест или рабочую нагрузку для вашего приложения. Это критический шаг, поскольку профили, собранные из рабочей нагрузки, определяют «горячие» и «холодные» области кода. При использовании профилей компилятор будет выполнять агрессивную оптимизацию и встраивание в горячие регионы. Компилятор также может уменьшить размер кода холодных регионов, пожертвовав при этом производительностью.
Определение хорошей рабочей нагрузки также полезно для отслеживания производительности в целом.
Шаг 2. Соберите профили
Сбор профилей включает в себя три этапа: — создание собственного кода с инструментами, — запуск инструментированного приложения на устройстве и создание профилей, а также — объединение/постобработка профилей на хосте.
Создать инструментированную сборку
Профили собираются путем выполнения рабочей нагрузки, начиная с шага 1, в инструментированной сборке приложения. Чтобы создать инструментированную сборку, добавьте -fprofile-generate
к флагам компилятора и компоновщика. Этот флаг должен управляться отдельной переменной сборки, поскольку во время сборки по умолчанию этот флаг не требуется.
Создание профилей
Затем запустите инструментированное приложение на устройстве и создайте профили. Профили собираются в памяти при запуске инструментированного двоичного файла и записываются в файл при выходе. Однако функции, зарегистрированные с помощью atexit
не вызываются в приложении Android — приложение просто убивается.
Приложению/рабочей нагрузке приходится выполнять дополнительную работу, чтобы установить путь к файлу профиля, а затем явно инициировать запись профиля.
- Чтобы установить путь к файлу профиля, вызовите
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw
.%m
полезен при наличии нескольких общих библиотек.%m
расширяется до уникальной подписи модуля для этой библиотеки, в результате чего для каждой библиотеки создается отдельный профиль Другие полезные спецификаторы шаблонов см. здесь .PROFILE_DIR
— это каталог, доступный для записи из приложения. См. демонстрацию для обнаружения этого каталога во время выполнения. - Чтобы явно вызвать запись профиля, вызовите функцию
__llvm_profile_write_file
.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_write_file(void);
}
#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
// ...
// run workload
// ...
// set path and write profiles after workload execution
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
__llvm_profile_write_file();
return;
}
Примечание. Создать файл профиля проще, если рабочая нагрузка представляет собой отдельный двоичный файл — просто установите для переменной среды LLVM_PROFILE_FILE
значение %t/default-%m.profraw
перед запуском двоичного файла.
Профили постобработки
Файлы профиля имеют формат .profraw. Сначала их необходимо получить с устройства с помощью adb pull
. После выборки используйте утилиту llvm-profdata
в NDK для преобразования .profraw
в .profdata
, который затем можно будет передать компилятору.
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
merge --output=pgo_profile.profdata \
<list-of-profraw-files>
Используйте llvm-profdata
и clang
из одной и той же версии NDK, чтобы избежать несоответствия версий форматов файлов профилей.
Шаг 3. Использование профилей для создания приложения
Используйте профиль из предыдущего шага во время сборки выпуска вашего приложения, передав -fprofile-use=<>.profdata
компилятору и компоновщику. Профили можно использовать даже по мере развития кода — компилятор Clang может допускать небольшое несоответствие между исходным кодом и профилями.
NB: В целом, для большинства библиотек профили являются общими для разных архитектур. Например, профили, созданные из сборки библиотеки Arm64, можно использовать для всех архитектур. Предостережение заключается в том, что если в библиотеке есть пути кода для конкретной архитектуры (arm или x86 или 32-бит или 64-бит), для каждой такой конфигурации следует использовать отдельные профили.
Собираем все это вместе
https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo показывает комплексную демонстрацию использования PGO из приложения. Он предоставляет дополнительную информацию, которая была рассмотрена в этом документе.
- Правила сборки CMake показывают, как настроить переменную CMake, которая создает собственный код с помощью инструментов. Если переменная сборки не установлена, собственный код оптимизируется с использованием ранее созданных профилей PGO.
- В инструментированной сборке pgodemo.cpp записывает профили выполнения рабочей нагрузки.
- Доступное для записи местоположение для профилей получается во время выполнения в MainActivity.kt с помощью
applicationContext.cacheDir.toString()
. - Чтобы извлечь профили с устройства без необходимости использования
adb root
, используйте рецептadb
здесь .
Оптимизация на основе профиля (PGO) — это хорошо известный метод оптимизации компилятора. В PGO профили времени выполнения программы используются компилятором для принятия оптимальных решений относительно встраивания и компоновки кода. Это приводит к повышению производительности и уменьшению размера кода.
PGO можно развернуть в вашем приложении или библиотеке, выполнив следующие действия: 1. Определите репрезентативную рабочую нагрузку. 2. Соберите анкеты. 3. Используйте профили в сборке Release.
Шаг 1. Определите репрезентативную рабочую нагрузку
Сначала определите репрезентативный тест или рабочую нагрузку для вашего приложения. Это критический шаг, поскольку профили, собранные из рабочей нагрузки, определяют «горячие» и «холодные» области кода. При использовании профилей компилятор будет выполнять агрессивную оптимизацию и встраивание в горячие регионы. Компилятор также может уменьшить размер кода холодных регионов, пожертвовав при этом производительностью.
Определение хорошей рабочей нагрузки также полезно для отслеживания производительности в целом.
Шаг 2. Соберите профили
Сбор профилей включает в себя три этапа: — создание собственного кода с инструментами, — запуск инструментированного приложения на устройстве и создание профилей, а также — объединение/постобработка профилей на хосте.
Создать инструментированную сборку
Профили собираются путем выполнения рабочей нагрузки, начиная с шага 1, в инструментированной сборке приложения. Чтобы создать инструментированную сборку, добавьте -fprofile-generate
к флагам компилятора и компоновщика. Этот флаг должен управляться отдельной переменной сборки, поскольку во время сборки по умолчанию этот флаг не требуется.
Создание профилей
Затем запустите инструментированное приложение на устройстве и создайте профили. Профили собираются в памяти при запуске инструментированного двоичного файла и записываются в файл при выходе. Однако функции, зарегистрированные с помощью atexit
не вызываются в приложении Android — приложение просто убивается.
Приложению/рабочей нагрузке приходится выполнять дополнительную работу, чтобы установить путь к файлу профиля, а затем явно инициировать запись профиля.
- Чтобы установить путь к файлу профиля, вызовите
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw
.%m
полезен при наличии нескольких общих библиотек.%m
расширяется до уникальной подписи модуля для этой библиотеки, в результате чего для каждой библиотеки создается отдельный профиль Другие полезные спецификаторы шаблонов см. здесь .PROFILE_DIR
— это каталог, доступный для записи из приложения. См. демонстрацию для обнаружения этого каталога во время выполнения. - Чтобы явно вызвать запись профиля, вызовите функцию
__llvm_profile_write_file
.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_write_file(void);
}
#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
// ...
// run workload
// ...
// set path and write profiles after workload execution
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
__llvm_profile_write_file();
return;
}
Примечание. Создать файл профиля проще, если рабочая нагрузка представляет собой отдельный двоичный файл — просто установите для переменной среды LLVM_PROFILE_FILE
значение %t/default-%m.profraw
перед запуском двоичного файла.
Профили постобработки
Файлы профиля имеют формат .profraw. Сначала их необходимо получить с устройства с помощью adb pull
. После выборки используйте утилиту llvm-profdata
в NDK для преобразования .profraw
в .profdata
, который затем можно будет передать компилятору.
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
merge --output=pgo_profile.profdata \
<list-of-profraw-files>
Используйте llvm-profdata
и clang
из одной и той же версии NDK, чтобы избежать несоответствия версий форматов файлов профилей.
Шаг 3. Использование профилей для создания приложения
Используйте профиль из предыдущего шага во время сборки выпуска вашего приложения, передав -fprofile-use=<>.profdata
компилятору и компоновщику. Профили можно использовать даже по мере развития кода — компилятор Clang может допускать небольшое несоответствие между исходным кодом и профилями.
NB: В целом, для большинства библиотек профили являются общими для разных архитектур. Например, профили, созданные из сборки библиотеки Arm64, можно использовать для всех архитектур. Предостережение заключается в том, что если в библиотеке есть пути кода для конкретной архитектуры (arm или x86 или 32-бит или 64-бит), для каждой такой конфигурации следует использовать отдельные профили.
Собираем все это вместе
https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo показывает комплексную демонстрацию использования PGO из приложения. Он предоставляет дополнительную информацию, которая была рассмотрена в этом документе.
- Правила сборки CMake показывают, как настроить переменную CMake, которая создает собственный код с помощью инструментов. Если переменная сборки не установлена, собственный код оптимизируется с использованием ранее созданных профилей PGO.
- В инструментированной сборке pgodemo.cpp записывает профили выполнения рабочей нагрузки.
- Доступное для записи местоположение для профилей получается во время выполнения в MainActivity.kt с помощью
applicationContext.cacheDir.toString()
. - Чтобы извлечь профили с устройства без необходимости использования
adb root
, используйте рецептadb
здесь .
Оптимизация на основе профиля (PGO) — это хорошо известный метод оптимизации компилятора. В PGO профили времени выполнения программы используются компилятором для принятия оптимальных решений по встраиванию и компоновке кода. Это приводит к повышению производительности и уменьшению размера кода.
PGO можно развернуть в вашем приложении или библиотеке, выполнив следующие действия: 1. Определите типичную рабочую нагрузку. 2. Соберите анкеты. 3. Используйте профили в сборке Release.
Шаг 1. Определите репрезентативную рабочую нагрузку
Сначала определите репрезентативный тест или рабочую нагрузку для вашего приложения. Это критический шаг, поскольку профили, собранные из рабочей нагрузки, определяют «горячие» и «холодные» области кода. При использовании профилей компилятор будет выполнять агрессивную оптимизацию и встраивание в горячие регионы. Компилятор также может уменьшить размер кода холодных регионов, пожертвовав при этом производительностью.
Определение хорошей рабочей нагрузки также полезно для отслеживания производительности в целом.
Шаг 2. Соберите профили
Сбор профилей включает в себя три этапа: — создание собственного кода с инструментами, — запуск инструментированного приложения на устройстве и создание профилей, а также — объединение/постобработка профилей на хосте.
Создать инструментированную сборку
Профили собираются путем выполнения рабочей нагрузки, начиная с шага 1, в инструментированной сборке приложения. Чтобы создать инструментированную сборку, добавьте -fprofile-generate
к флагам компилятора и компоновщика. Этот флаг должен управляться отдельной переменной сборки, поскольку во время сборки по умолчанию этот флаг не требуется.
Создание профилей
Затем запустите инструментированное приложение на устройстве и создайте профили. Профили собираются в памяти при запуске инструментированного двоичного файла и записываются в файл при выходе. Однако функции, зарегистрированные с помощью atexit
не вызываются в приложении Android — приложение просто убивается.
Приложению/рабочей нагрузке приходится выполнять дополнительную работу, чтобы установить путь к файлу профиля, а затем явно инициировать запись профиля.
- Чтобы установить путь к файлу профиля, вызовите
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw
.%m
полезен при наличии нескольких общих библиотек.%m
расширяется до уникальной подписи модуля для этой библиотеки, в результате чего для каждой библиотеки создается отдельный профиль Другие полезные спецификаторы шаблонов см. здесь .PROFILE_DIR
— это каталог, доступный для записи из приложения. См. демонстрацию для обнаружения этого каталога во время выполнения. - Чтобы явно вызвать запись профиля, вызовите функцию
__llvm_profile_write_file
.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_write_file(void);
}
#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
// ...
// run workload
// ...
// set path and write profiles after workload execution
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
__llvm_profile_write_file();
return;
}
Примечание. Создать файл профиля проще, если рабочая нагрузка представляет собой отдельный двоичный файл — просто установите для переменной среды LLVM_PROFILE_FILE
значение %t/default-%m.profraw
перед запуском двоичного файла.
Профили постобработки
Файлы профиля имеют формат .profraw. Сначала их необходимо получить с устройства с помощью adb pull
. После выборки используйте утилиту llvm-profdata
в NDK для преобразования .profraw
в .profdata
, который затем можно будет передать компилятору.
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
merge --output=pgo_profile.profdata \
<list-of-profraw-files>
Используйте llvm-profdata
и clang
из одной и той же версии NDK, чтобы избежать несоответствия версий форматов файлов профилей.
Шаг 3. Использование профилей для создания приложения
Используйте профиль из предыдущего шага во время сборки выпуска вашего приложения, передав -fprofile-use=<>.profdata
компилятору и компоновщику. Профили можно использовать даже по мере развития кода — компилятор Clang допускает небольшое несоответствие между исходным кодом и профилями.
NB: В целом, для большинства библиотек профили являются общими для разных архитектур. Например, профили, созданные из сборки библиотеки Arm64, можно использовать для всех архитектур. Предостережение заключается в том, что если в библиотеке есть пути кода для конкретной архитектуры (arm или x86 или 32-бит или 64-бит), для каждой такой конфигурации следует использовать отдельные профили.
Собираем все это вместе
https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo показывает комплексную демонстрацию использования PGO из приложения. Он предоставляет дополнительную информацию, которая была рассмотрена в этом документе.
- Правила сборки CMake показывают, как настроить переменную CMake, которая создает собственный код с помощью инструментов. Если переменная сборки не установлена, собственный код оптимизируется с использованием ранее созданных профилей PGO.
- В инструментированной сборке pgodemo.cpp записывает профили выполнения рабочей нагрузки.
- Доступное для записи местоположение для профилей получается во время выполнения в MainActivity.kt с помощью
applicationContext.cacheDir.toString()
. - Чтобы извлечь профили с устройства без необходимости использования
adb root
, используйте рецептadb
здесь .
Оптимизация на основе профиля (PGO) — это хорошо известный метод оптимизации компилятора. В PGO профили времени выполнения программы используются компилятором для принятия оптимальных решений относительно встраивания и компоновки кода. Это приводит к повышению производительности и уменьшению размера кода.
PGO можно развернуть в вашем приложении или библиотеке, выполнив следующие действия: 1. Определите типичную рабочую нагрузку. 2. Соберите анкеты. 3. Используйте профили в сборке Release.
Шаг 1. Определите репрезентативную рабочую нагрузку
Сначала определите репрезентативный тест или рабочую нагрузку для вашего приложения. Это критический шаг, поскольку профили, собранные из рабочей нагрузки, определяют «горячие» и «холодные» области кода. При использовании профилей компилятор будет выполнять агрессивную оптимизацию и встраивание в горячие регионы. Компилятор также может уменьшить размер кода холодных регионов, пожертвовав при этом производительностью.
Определение хорошей рабочей нагрузки также полезно для отслеживания производительности в целом.
Шаг 2. Соберите профили
Сбор профилей включает в себя три этапа: — создание собственного кода с инструментами, — запуск инструментированного приложения на устройстве и создание профилей, а также — объединение/постобработка профилей на хосте.
Создать инструментированную сборку
Профили собираются путем выполнения рабочей нагрузки, начиная с шага 1, в инструментированной сборке приложения. Чтобы создать инструментированную сборку, добавьте -fprofile-generate
к флагам компилятора и компоновщика. Этот флаг должен управляться отдельной переменной сборки, поскольку во время сборки по умолчанию этот флаг не требуется.
Создание профилей
Затем запустите инструментированное приложение на устройстве и создайте профили. Профили собираются в памяти при запуске инструментированного двоичного файла и записываются в файл при выходе. Однако функции, зарегистрированные с помощью atexit
не вызываются в приложении Android — приложение просто убивается.
Приложению/рабочей нагрузке приходится выполнять дополнительную работу, чтобы установить путь к файлу профиля, а затем явно инициировать запись профиля.
- Чтобы установить путь к файлу профиля, вызовите
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw
.%m
полезен при наличии нескольких общих библиотек.%m
расширяется до уникальной подписи модуля для этой библиотеки, в результате чего для каждой библиотеки создается отдельный профиль Другие полезные спецификаторы шаблонов см. здесь .PROFILE_DIR
— это каталог, доступный для записи из приложения. См. демонстрацию для обнаружения этого каталога во время выполнения. - Чтобы явно вызвать запись профиля, вызовите функцию
__llvm_profile_write_file
.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_write_file(void);
}
#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
// ...
// run workload
// ...
// set path and write profiles after workload execution
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
__llvm_profile_write_file();
return;
}
Примечание. Создать файл профиля проще, если рабочая нагрузка представляет собой отдельный двоичный файл — просто установите для переменной среды LLVM_PROFILE_FILE
значение %t/default-%m.profraw
перед запуском двоичного файла.
Профили постобработки
Файлы профиля имеют формат .profraw. Сначала их необходимо получить с устройства с помощью adb pull
. После выборки используйте утилиту llvm-profdata
в NDK для преобразования .profraw
в .profdata
, который затем можно будет передать компилятору.
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
merge --output=pgo_profile.profdata \
<list-of-profraw-files>
Используйте llvm-profdata
и clang
из одной и той же версии NDK, чтобы избежать несоответствия версий форматов файлов профилей.
Шаг 3. Использование профилей для создания приложения
Используйте профиль из предыдущего шага во время сборки выпуска вашего приложения, передав -fprofile-use=<>.profdata
компилятору и компоновщику. Профили можно использовать даже по мере развития кода — компилятор Clang допускает небольшое несоответствие между исходным кодом и профилями.
NB: В целом, для большинства библиотек профили являются общими для разных архитектур. Например, профили, созданные из сборки библиотеки Arm64, можно использовать для всех архитектур. Предостережение заключается в том, что если в библиотеке есть пути кода для конкретной архитектуры (arm или x86 или 32-бит или 64-бит), для каждой такой конфигурации следует использовать отдельные профили.
Собираем все это вместе
https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo показывает комплексную демонстрацию использования PGO из приложения. Он предоставляет дополнительную информацию, которая была рассмотрена в этом документе.
- Правила сборки CMake показывают, как настроить переменную CMake, которая создает собственный код с помощью инструментов. Если переменная сборки не установлена, собственный код оптимизируется с использованием ранее созданных профилей PGO.
- В инструментированной сборке pgodemo.cpp записывает профили выполнения рабочей нагрузки.
- Доступное для записи местоположение для профилей получается во время выполнения в MainActivity.kt с помощью
applicationContext.cacheDir.toString()
. - Чтобы извлечь профили с устройства без необходимости использования
adb root
, используйте рецептadb
здесь .