Заказать файлы

Файл заказов — это новейший метод оптимизации компоновщика. Эти файлы заказов представляют собой текстовые файлы, содержащие символы, обозначающие функции. Линкеры, такие как lld, используют файлы порядка для размещения функций в определенном порядке. Эти двоичные файлы или библиотеки с упорядоченными символами уменьшают количество ошибок страниц и сокращают время запуска программы за счет эффективной загрузки символов во время холодного запуска программы.

Функции файла заказа можно добавить в ваше приложение, выполнив три шага:

  1. Создание профилей и файла сопоставления
  2. Создайте файл заказа из профилей и файла сопоставления.
  3. Используйте файл заказа во время сборки Release для размещения символов.

Создать файл заказа

Для создания файла заказа необходимо выполнить три шага:

  1. Создайте инструментированную версию приложения, записывающую файл заказа.
  2. Запустите приложение для создания профилей
  3. Постобработка профилей и файла сопоставления.

Создайте инструментированную сборку

Профили генерируются путем запуска инструментированной сборки приложения. Инструментированная сборка требует добавления -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 соответственно.