Файл заказов — это новейший метод оптимизации компоновщика. Эти файлы заказов представляют собой текстовые файлы, содержащие символы, обозначающие функции. Линкеры, такие как lld, используют файлы порядка для размещения функций в определенном порядке. Эти двоичные файлы или библиотеки с упорядоченными символами уменьшают количество ошибок страниц и сокращают время запуска программы за счет эффективной загрузки символов во время холодного запуска программы.
Функции файла заказа можно добавить в ваше приложение, выполнив три шага:
- Создание профилей и файла сопоставления
- Создайте файл заказа из профилей и файла сопоставления.
- Используйте файл заказа во время сборки Release для размещения символов.
Создать файл заказа
Для создания файла заказа необходимо выполнить три шага:
- Создайте инструментированную версию приложения, записывающую файл заказа.
- Запустите приложение для создания профилей
- Постобработка профилей и файла сопоставления.
Создайте инструментированную сборку
Профили генерируются путем запуска инструментированной сборки приложения. Инструментированная сборка требует добавления -forder-file-instrumentation
как к флагам компилятора, так и к флагам компоновщика, причем -mllvm -orderfile-write-mapping=<filename>-mapping.txt
строго добавляется к флагам компилятора. Флаг инструментирования включает инструментарий файла заказа для профилирования и загружает специальную библиотеку, необходимую для профилирования. С другой стороны, флаг сопоставления просто выводит файл сопоставления, который показывает хэш MD5 для каждой функции в двоичном файле или библиотеке.
Кроме того, обязательно передайте любой флаг оптимизации, кроме -O0
поскольку он требуется как для флага инструментирования, так и для флага сопоставления. Если флаг оптимизации не передан, файл сопоставления не создается, и инструментированная сборка может выводить неправильные хэши в файл профиля.
ndk-сборка
Обязательно выполняйте сборку с использованием APP_OPTIM=release
, чтобы ndk-build использовал режим оптимизации, отличный от -O0
. При сборке с использованием AGP это происходит автоматически для выпускных сборок.
LOCAL_CFLAGS += \
-forder-file-instrumentation \
-mllvm -orderfile-write-mapping=mapping.txt \
LOCAL_LDFLAGS += -forder-file-instrumentation
CMake
Обязательно используйте CMAKE_BUILD_TYPE
отличный от Debug
, чтобы CMake использовал режим оптимизации, отличный от -O0
. При сборке с использованием AGP это происходит автоматически для выпускных сборок.
target_compile_options(orderfiledemo PRIVATE
-forder-file-instrumentation
-mllvm -orderfile-write-mapping=mapping.txt
)
target_link_options(orderfiledemo PRIVATE -forder-file-instrumentation)
Другие системы сборки
Скомпилируйте свой код, используя -forder-file-instrumentation -O1 -mllvm -orderfile-write-mapping=mapping.txt
.
-O1
конкретно не требуется, но не используйте -O0
.
Опустите -mllvm -orderfile-write-mapping=mapping.txt
при связывании.
Все эти флаги не нужны для сборки Release, поэтому ими следует управлять с помощью переменной сборки. Для простоты вы можете настроить все это в CMakeLists.txt, как в нашем примере .
Создайте библиотеку файлов заказов
В дополнение к флагам необходимо настроить файл профиля, а инструментированный двоичный файл должен явно инициировать запись профиля во время его выполнения.
- Вызовите
__llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw")
для настройки пути к профилю. Несмотря на то, что переданный аргумент —<filename>-%m.profraw
, файл профиля сохраняется как<filename>-%m.profraw.order
. Убедитесь, что приложение доступно для записиPROFILE_DIR
и у вас есть доступ к каталогу.- Поскольку профилируется множество общих библиотек,
%m
полезен, поскольку он расширяется до уникальной подписи модуля для библиотеки, в результате чего для каждой библиотеки создается отдельный профиль. Дополнительные спецификаторы шаблонов можно найти по этой ссылке .
- Поскольку профилируется множество общих библиотек,
- Вызовите
__llvm_profile_initialize_file()
, чтобы настроить файл профиля. - Вызовите
__llvm_orderfile_dump()
для явной записи в файл профиля.
Профили собираются в памяти, а функция дампа записывает их в файл. Вам необходимо убедиться, что функция дампа вызывается в конце запуска, чтобы в вашем файле профиля были все символы до конца запуска.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_initialize_file(void);
extern int __llvm_orderfile_dump(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_initialize_file();
__llvm_orderfile_dump();
return;
}
Запустите сборку профилей
Запустите инструментированное приложение на физическом или виртуальном устройстве, чтобы создать профили. Вы можете извлечь файлы профиля с помощью adb pull
.
adb shell "run-as <package-name> sh -c 'cat /data/user/0/<package-name>/cache/default-%m.profraw.order' | cat > /data/local/tmp/default-%m.profraw.order"
adb pull /data/local/tmp/default-%m.profraw.order .
Как упоминалось ранее, убедитесь, что у вас есть доступ к папке, содержащей записанный файл профиля. Если это виртуальное устройство, возможно, вам стоит избегать эмуляторов с Play Store из-за отсутствия доступа ко многим папкам.
Постобработка файла профиля и сопоставления
Когда вы получите профили, вам нужно найти файл сопоставления и преобразовать каждый профиль в шестнадцатеричный формат. Обычно файл сопоставления можно найти в папке сборки приложения. Если у вас есть и то, и другое, вы можете использовать наш скрипт для получения файла профиля и правильного файла сопоставления для создания файла заказа.
Linux/Mac/ChromeOS
hexdump -C default-%m.profraw.order > default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
Окна
certutil -f -encodeHex default-%m.profraw.order default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
Если вы хотите узнать больше о скрипте, вы можете просмотреть этот README .
Используйте файл заказа для создания приложения
После создания файла заказа вам следует удалить предыдущие флаги и функции файла заказа, поскольку они предназначены только для этапов создания. Вам просто нужно передать -Wl,--symbol-ordering-file=<filename>.orderfile
в флаги компиляции и компоновщика. Иногда символы не могут быть найдены или не могут перемещаться и выдавать предупреждения, поэтому вы можете передать -Wl,--no-warn-symbol-ordering
чтобы подавить эти предупреждения.
ndk-сборка
LOCAL_CFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
LOCAL_LDFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
CMake
target_compile_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
target_link_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
Другие системы сборки
Скомпилируйте код, используя -Wl,--symbol-ordering-file=<filename>.orderfile -Wl,--no-warn-symbol-ordering
.
Для получения дополнительной информации ознакомьтесь с примером файла заказа .
Детали реализации файла заказа
Существует множество способов создания файлов заказов и использования их для построения. NDK использует метод LLVM, поэтому он наиболее полезен для ваших общих библиотек C или C++ по сравнению с реальным приложением Java или Kotlin. Clang берет каждое имя функции (символ), создает его хеш MD5 и выводит это отношение в файл сопоставления. Хэш MD5 функции записывается в файл профиля (формат profraw) при первом выполнении функции. Любые последующие выполнения функции не записывают ее MD5-хеш в файл профиля, поскольку она хочет избежать дублирования. В результате в заказе фиксируется только первое выполнение функции. Просматривая файл профиля и файл сопоставления, вы можете взять каждый хэш MD5, заменить его соответствующей функцией и получить файл заказа.
Примеры файла профиля в шестнадцатеричном формате и файла сопоставления можно найти как example.prof и example-mapping.txt соответственно.