Использование оптимизации на основе профиля (PGO)

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

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

О Clang PGO

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

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

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

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

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

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

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

Использование PGO

Использование 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

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

Практический пример: 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. Создайте общий файл dex2oat для исполняемого файла 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 для использования во время сборки.