Используйте оптимизацию на основе профиля

Система сборки Android для Android 13 и более ранних версий поддерживает использование оптимизации на основе профиля (PGO) Clang в собственных модулях Android, имеющих правила сборки схемы . На этой странице описывается Clang PGO, как постоянно создавать и обновлять профили, используемые для PGO, и как интегрировать PGO с системой сборки (с указанием вариантов использования).

Примечание. В этом документе описывается использование PGO на платформе Android. Чтобы узнать об использовании PGO из приложения Android, посетите эту страницу .

О Кланг ПГО

Clang может выполнять оптимизацию на основе профилей, используя два типа профилей:

  • Профили на основе инструментов генерируются из инструментированной целевой программы. Эти профили детализированы и требуют больших затрат времени выполнения.
  • Профили на основе выборки обычно создаются аппаратными счетчиками выборки. Они требуют небольших накладных расходов во время выполнения и могут быть собраны без каких-либо инструментов или изменений в двоичном файле. Они менее детальны, чем профили, основанные на приборах.

Все профили должны создаваться на основе репрезентативной рабочей нагрузки, которая демонстрирует типичное поведение приложения. Хотя Clang поддерживает как на основе AST ( -fprofile-instr-generate ), так и на основе LLVM IR ( -fprofile-generate) , Android поддерживает только LLVM IR для PGO на основе инструментов.

Для сборки сбора профилей необходимы следующие флаги:

  • -fprofile-generate для ИК-инструментов. При использовании этого параметра серверная часть использует подход минимального взвешенного связующего дерева, чтобы уменьшить количество точек инструментирования и оптимизировать их размещение для ребер с малым весом (используйте этот параметр также для шага связывания). Драйвер Clang автоматически передает среду выполнения профилирования ( libclang_rt.profile- arch -android.a ) компоновщику. Эта библиотека содержит процедуры для записи профилей на диск после выхода из программы.
  • -gline-tables-only для сбора профилей на основе выборки для создания минимальной отладочной информации.

Профиль можно использовать для PGO, используя -fprofile-use= pathname или -fprofile-sample-use= pathname для профилей на основе инструментов и выборки соответственно.

Примечание. Если в код вносятся изменения, Clang больше не может использовать данные профиля, он генерирует предупреждение -Wprofile-instr-out-of-date .

Используйте ПГО

Использование PGO включает в себя следующие шаги:

  1. Создайте библиотеку/исполняемый файл с инструментами, передав -fprofile-generate компилятору и компоновщику.
  2. Соберите профили, запустив репрезентативную рабочую нагрузку на инструментированном двоичном файле.
  3. Выполните постобработку профилей с помощью утилиты llvm-profdata (подробнее см. в разделе «Обработка файлов профилей LLVM» ).
  4. Используйте профили для применения PGO, передав -fprofile-use=<>.profdata компилятору и компоновщику.

Для PGO в Android профили следует собирать в автономном режиме и возвращать вместе с кодом, чтобы обеспечить воспроизводимость сборок. Профили можно использовать по мере развития кода, но их необходимо периодически перегенерировать (или всякий раз, когда Clang предупреждает, что профили устарели).

Собирайте профили

Clang может использовать профили, собранные при выполнении тестов с использованием инструментированной сборки библиотеки или путем выборки аппаратных счетчиков при запуске теста. В настоящее время Android не поддерживает сбор профилей на основе выборки, поэтому вам необходимо собирать профили с помощью инструментированной сборки:

  1. Определите эталон и набор библиотек, совместно используемых этим тестом.
  2. Добавьте свойства pgo в тест и библиотеки (подробности ниже).
  3. Создайте сборку Android с инструментированной копией этих библиотек, используя:
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark — это заполнитель, который идентифицирует коллекцию библиотек, инструментированных во время сборки. Фактические репрезентативные входные данные (и, возможно, другой исполняемый файл, который связан с тестируемой библиотекой) не относятся к PGO и выходят за рамки этого документа.

  1. Прошивайте или синхронизируйте инструментированную сборку на устройстве.
  2. Запустите тест для сбора профилей.
  3. Используйте инструмент llvm-profdata (описанный ниже) для постобработки профилей и подготовки их к возврату в дерево исходного кода.

Используйте профили во время сборки

Проверьте профили в toolchain/pgo-profiles в дереве Android. Имя должно соответствовать тому, что указано в подсвойстве profile_file свойства pgo библиотеки. Система сборки автоматически передает файл профиля в Clang при сборке библиотеки. Для переменной среды ANDROID_PGO_DISABLE_PROFILE_USE можно установить значение true , чтобы временно отключить PGO и измерить его выигрыш в производительности.

Чтобы указать дополнительные каталоги профилей для конкретного продукта, добавьте их к переменной make PGO_ADDITIONAL_PROFILE_DIRECTORIES в BoardConfig.mk . Если указаны дополнительные пути, профили в этих путях переопределяют профили в toolchain/pgo-profiles .

При создании образа выпуска с использованием цели dist для make система сборки записывает имена отсутствующих файлов профиля в $DIST_DIR/pgo_profile_file_missing.txt . Вы можете проверить этот файл, чтобы увидеть, какие файлы профиля были случайно удалены (что автоматически отключает PGO).

Включить PGO в файлах Android.bp

Чтобы включить PGO в файлах Android.bp для собственных модулей, просто укажите свойство pgo . Это свойство имеет следующие подсвойства:

Свойство Описание
instrumentation Установите значение true для PGO с использованием инструментов. По умолчанию — false .
sampling Установите значение true для PGO с использованием выборки. По умолчанию — false .
benchmarks Список строк. Этот модуль создан для профилирования, если какой-либо тест в списке указан в опции сборки ANDROID_PGO_INSTRUMENT .
profile_file Файл профиля (относительно toolchain/pgo-profile ) для использования с PGO. Сборка предупреждает, что этот файл не существует, добавляя его в $DIST_DIR/pgo_profile_file_missing.txt если только для свойства enable_profile_use не установлено значение false ИЛИ для переменной сборки ANDROID_PGO_NO_PROFILE_USE установлено значение true .
enable_profile_use Установите значение false , если профили не должны использоваться во время сборки. Может использоваться во время начальной загрузки, чтобы включить сбор профилей или временно отключить PGO. По умолчанию true .
cflags Список дополнительных флагов для использования во время инструментированной сборки.

Пример модуля с PGO:

cc_library {
    name: "libexample",
    srcs: [
        "src1.cpp",
        "src2.cpp",
    ],
    static: [
        "libstatic1",
        "libstatic2",
    ],
    shared: [
        "libshared1",
    ]
    pgo: {
        instrumentation: true,
        benchmarks: [
            "benchmark1",
            "benchmark2",
        ],
        profile_file: "example.profdata",
    }
}

Если тесты benchmark1 и benchmark2 демонстрируют репрезентативное поведение для библиотек libstatic1 , libstatic2 или libshared1 , свойство pgo этих библиотек также может включать тесты. Модуль defaults в Android.bp может включать общую спецификацию pgo для набора библиотек, чтобы избежать повторения одних и тех же правил сборки для нескольких модулей.

Чтобы выбрать разные файлы профиля или выборочно отключить PGO для архитектуры, укажите свойства profile_file , enable_profile_use и cflags для каждой архитектуры. Пример (целевая архитектура выделена жирным шрифтом ):

cc_library {
    name: "libexample",
    srcs: [
          "src1.cpp",
          "src2.cpp",
    ],
    static: [
          "libstatic1",
          "libstatic2",
    ],
    shared: [
          "libshared1",
    ],
    pgo: {
         instrumentation: true,
         benchmarks: [
              "benchmark1",
              "benchmark2",
         ],
    }

    target: {
         android_arm: {
              pgo: {
                   profile_file: "example_arm.profdata",
              }
         },
         android_arm64: {
              pgo: {
                   profile_file: "example_arm64.profdata",
              }
         }
    }
}

Чтобы разрешить ссылки на библиотеку времени выполнения профилирования во время профилирования на основе инструментов, передайте компоновщику флаг сборки -fprofile-generate . Статические библиотеки, оснащенные PGO, все общие библиотеки и любые двоичные файлы, которые напрямую зависят от статической библиотеки, также должны быть инструментированы для PGO. Однако таким общим библиотекам или исполняемым файлам не обязательно использовать профили PGO, и их свойству enable_profile_use можно присвоить значение false . За пределами этого ограничения вы можете применять PGO к любой статической, общей библиотеке или исполняемому файлу.

Обработка файлов профиля LLVM

При выполнении инструментированной библиотеки или исполняемого файла создается файл профиля с именем default_ unique_id _0.profraw в /data/local/tmp (где unique_id — это числовой хэш, уникальный для этой библиотеки). Если этот файл уже существует, среда выполнения профилирования объединяет новый профиль со старым во время записи профилей. Обратите внимание, что /data/local/tmp недоступен разработчикам приложений; вместо этого им следует использовать что-то вроде /storage/emulated/0/Android/data/ packagename /files . Чтобы изменить расположение файла профиля, установите переменную среды LLVM_PROFILE_FILE во время выполнения.

Затем утилита llvm-profdata используется для преобразования файла .profraw (и, возможно, объединения нескольких файлов .profraw ) в файл .profdata :

  llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>

profile.profdata затем можно вернуть в дерево исходного кода для использования во время сборки.

Если во время тестирования загружается несколько инструментированных двоичных файлов/библиотек, каждая библиотека создает отдельный файл .profraw с отдельным уникальным идентификатором. Обычно все эти файлы можно объединить в один файл .profdata и использовать для сборки PGO. В тех случаях, когда библиотека используется другим тестом, эта библиотека должна быть оптимизирована с использованием профилей из обоих тестов. В этой ситуации полезна опция show llvm-profdata :

  llvm-profdata merge -output=default_unique_id.profdata default_unique_id_0.profraw
llvm-profdata show -all-functions default_unique_id.profdata

Чтобы сопоставить unique_id с отдельными библиотеками, найдите в выводе show для каждого unique_id имя функции, уникальное для библиотеки.

Практический пример: PGO по АРТ

В тематическом исследовании АРТ представлена ​​в качестве наглядного примера; однако это неточное описание реального набора библиотек, профилированных для ART, или их взаимозависимостей.

Предварительный компилятор dex2oat в ART зависит от libart-compiler.so , который, в свою очередь, зависит от libart.so . Среда выполнения ART реализована в основном в libart.so . Тесты для компилятора и среды выполнения будут разными:

Контрольный показатель Профилированные библиотеки
dex2oat dex2oat (исполняемый файл), libart-compiler.so , libart.so
art_runtime libart.so
  1. Добавьте следующее свойство pgo в dex2oat , libart-compiler.so :
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. Добавьте следующее свойство pgo в libart.so :
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. Создайте инструментированные сборки для тестов dex2oat и art_runtime , используя:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. В качестве альтернативы создайте единую инструментированную сборку со всеми инструментированными библиотеками, используя:

        make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime
        (or)
        make ANDROID_PGO_INSTRUMENT=ALL

    Вторая команда собирает все модули с поддержкой PGO для профилирования.

  5. Запустите тесты с использованием dex2oat и art_runtime , чтобы получить:
    • Три файла .profraw из dex2oat ( dex2oat_exe.profdata , dex2oat_libart-compiler.profdata и dexeoat_libart.profdata ), идентифицированные с помощью метода, описанного в разделе «Обработка файлов профиля LLVM» .
    • Один art_runtime_libart.profdata .
  6. Создайте общий файл profdata для исполняемого файла dex2oat и libart-compiler.so , используя:
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. Получите профиль для libart.so , объединив профили из двух тестов:
    llvm-profdata merge -output=libart.profdata \
        dex2oat_libart.profdata art_runtime_libart.profdata

    Необработанные значения для libart.so из двух профилей могут быть несопоставимыми, поскольку тесты различаются количеством тестовых случаев и продолжительностью их выполнения. В этом случае вы можете использовать взвешенное слияние:

    llvm-profdata merge -output=libart.profdata \
        -weighted-input=2,dex2oat_libart.profdata \
        -weighted-input=1,art_runtime_libart.profdata

    Приведенная выше команда присваивает профилю из dex2oat двойной вес. Фактический вес следует определять на основе знаний предметной области или экспериментов.

  8. Проверьте файлы профилей dex2oat.profdata и libart.profdata в toolchain/pgo-profiles для использования во время сборки.