Utilice la optimización guiada por perfiles

El sistema de compilación de Android para Android 13 y versiones anteriores admite el uso de la optimización guiada por perfiles (PGO) de Clang en módulos nativos de Android que tienen reglas de compilación de planos . Esta página describe Clang PGO, cómo generar y actualizar continuamente perfiles utilizados para PGO y cómo integrar PGO con el sistema de compilación (con caso de uso).

NB: este documento describe el uso de PGO en la plataforma Android. Para obtener información sobre el uso de PGO desde una aplicación de Android, visite esta página .

Acerca de Clang PGO

Clang puede realizar una optimización guiada por perfiles utilizando dos tipos de perfiles:

  • Los perfiles basados ​​en instrumentación se generan a partir de un programa objetivo instrumentado. Estos perfiles son detallados e imponen una gran sobrecarga de tiempo de ejecución.
  • Los perfiles basados ​​en muestreo generalmente se producen mediante contadores de hardware de muestreo. Imponen una sobrecarga de tiempo de ejecución baja y se pueden recopilar sin ninguna instrumentación ni modificación del binario. Son menos detallados que los perfiles basados ​​en instrumentación.

Todos los perfiles deben generarse a partir de una carga de trabajo representativa que ejerza el comportamiento típico de la aplicación. Si bien Clang admite sistemas basados ​​en AST ( -fprofile-instr-generate ) y LLVM IR ( -fprofile-generate) , Android solo admite LLVM basado en IR para PGO basado en instrumentación.

Se necesitan las siguientes banderas para crear la recopilación de perfiles:

  • -fprofile-generate para instrumentación basada en IR. Con esta opción, el backend utiliza un enfoque de árbol de expansión mínimo ponderado para reducir la cantidad de puntos de instrumentación y optimizar su ubicación en bordes de bajo peso (use esta opción también para el paso de enlace). El controlador Clang pasa automáticamente el tiempo de ejecución de creación de perfiles ( libclang_rt.profile- arch -android.a ) al vinculador. Esta biblioteca contiene rutinas para escribir los perfiles en el disco al salir del programa.
  • -gline-tables-only para la recopilación de perfiles basada en muestreo para generar información de depuración mínima.

Se puede utilizar un perfil para PGO usando -fprofile-use= pathname o -fprofile-sample-use= pathname para perfiles basados ​​en instrumentación y muestreo, respectivamente.

Nota: A medida que se realizan cambios en el código, si Clang ya no puede usar los datos del perfil, genera una advertencia -Wprofile-instr-out-of-date .

Usar PGO

El uso de PGO implica los siguientes pasos:

  1. Cree la biblioteca/ejecutable con instrumentación pasando -fprofile-generate al compilador y al vinculador.
  2. Recopile perfiles ejecutando una carga de trabajo representativa en el binario instrumentado.
  3. Realice un posprocesamiento de los perfiles utilizando la utilidad llvm-profdata (para obtener más detalles, consulte Manejo de archivos de perfil LLVM ).
  4. Utilice los perfiles para aplicar PGO pasando -fprofile-use=<>.profdata al compilador y al vinculador.

Para PGO en Android, los perfiles deben recopilarse sin conexión y registrarse junto con el código para garantizar compilaciones reproducibles. Los perfiles se pueden utilizar a medida que el código evoluciona, pero deben regenerarse periódicamente (o cada vez que Clang advierte que los perfiles están obsoletos).

Recopilar perfiles

Clang puede usar perfiles recopilados ejecutando pruebas comparativas utilizando una compilación instrumentada de la biblioteca o tomando muestras de contadores de hardware cuando se ejecuta la prueba comparativa. En este momento, Android no admite el uso de la recopilación de perfiles basada en muestreo, por lo que debes recopilar perfiles mediante una compilación instrumentada:

  1. Identificar un punto de referencia y el conjunto de bibliotecas ejercidas colectivamente por ese punto de referencia.
  2. Agregue propiedades pgo al punto de referencia y a las bibliotecas (detalles a continuación).
  3. Produzca una compilación de Android con una copia instrumentada de estas bibliotecas usando:
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark es un marcador de posición que identifica la colección de bibliotecas instrumentadas durante la construcción. Las entradas representativas reales (y posiblemente otro ejecutable que se vincule con una biblioteca que se está comparando) no son específicas de PGO y están fuera del alcance de este documento.

  1. Actualice o sincronice la compilación instrumentada en un dispositivo.
  2. Ejecute el punto de referencia para recopilar perfiles.
  3. Utilice la herramienta llvm-profdata (que se analiza a continuación) para posprocesar los perfiles y prepararlos para registrarlos en el árbol de origen.

Usar perfiles durante la construcción

Verifique los perfiles en toolchain/pgo-profiles en un árbol de Android. El nombre debe coincidir con lo especificado en la subpropiedad profile_file de la propiedad pgo de la biblioteca. El sistema de compilación pasa automáticamente el archivo de perfil a Clang al crear la biblioteca. La variable de entorno ANDROID_PGO_DISABLE_PROFILE_USE se puede establecer en true para deshabilitar temporalmente PGO y medir su beneficio de rendimiento.

Para especificar directorios de perfiles adicionales específicos del producto, agréguelos a la variable make PGO_ADDITIONAL_PROFILE_DIRECTORIES en BoardConfig.mk . Si se especifican rutas adicionales, los perfiles en estas rutas anulan los de toolchain/pgo-profiles .

Al generar una imagen de lanzamiento usando el objetivo dist para make , el sistema de compilación escribe los nombres de los archivos de perfil faltantes en $DIST_DIR/pgo_profile_file_missing.txt . Puede consultar este archivo para ver qué archivos de perfil se eliminaron accidentalmente (lo que desactiva silenciosamente PGO).

Habilite PGO en archivos Android.bp

Para habilitar PGO en archivos Android.bp para módulos nativos, simplemente especifique la propiedad pgo . Esta propiedad tiene las siguientes subpropiedades:

Propiedad Descripción
instrumentation Establezca en true para PGO usando instrumentación. El valor predeterminado es false .
sampling Establezca en true para PGO usando muestreo. El valor predeterminado es false .
benchmarks Lista de cadenas. Este módulo está diseñado para crear perfiles si se especifica algún punto de referencia en la lista en la opción de compilación ANDROID_PGO_INSTRUMENT .
profile_file Archivo de perfil (relativo a toolchain/pgo-profile ) para usar con PGO. La compilación advierte que este archivo no existe al agregarlo a $DIST_DIR/pgo_profile_file_missing.txt a menos que la propiedad enable_profile_use esté configurada en false O la variable de compilación ANDROID_PGO_NO_PROFILE_USE esté configurada en true .
enable_profile_use Configúrelo en false si los perfiles no deben usarse durante la compilación. Se puede utilizar durante el arranque para habilitar la recopilación de perfiles o para deshabilitar temporalmente PGO. El valor predeterminado es true .
cflags Lista de indicadores adicionales para usar durante una compilación instrumentada.

Ejemplo de un módulo con 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",
    }
}

Si los puntos de referencia benchmark1 y benchmark2 ejercen un comportamiento representativo para las bibliotecas libstatic1 , libstatic2 o libshared1 , la propiedad pgo de estas bibliotecas también puede incluir los puntos de referencia. El módulo defaults en Android.bp puede incluir una especificación pgo común para un conjunto de bibliotecas para evitar repetir las mismas reglas de compilación para varios módulos.

Para seleccionar diferentes archivos de perfil o deshabilitar selectivamente PGO para una arquitectura, especifique las propiedades profile_file , enable_profile_use y cflags por arquitectura. Ejemplo (con el objetivo de arquitectura en negrita ):

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",
              }
         }
    }
}

Para resolver referencias a la biblioteca de tiempo de ejecución de creación de perfiles durante la creación de perfiles basada en instrumentación, pase el indicador de compilación -fprofile-generate al vinculador. Las bibliotecas estáticas instrumentadas con PGO, todas las bibliotecas compartidas y cualquier binario que dependa directamente de la biblioteca estática también deben instrumentarse para PGO. Sin embargo, dichas bibliotecas compartidas o ejecutables no necesitan utilizar perfiles PGO y su propiedad enable_profile_use se puede establecer en false . Fuera de esta restricción, puede aplicar PGO a cualquier biblioteca estática, biblioteca compartida o ejecutable.

Manejar archivos de perfil LLVM

La ejecución de una biblioteca instrumentada o un ejecutable produce un archivo de perfil llamado default_ unique_id _0.profraw en /data/local/tmp (donde unique_id es un hash numérico exclusivo de esta biblioteca). Si este archivo ya existe, el tiempo de ejecución de creación de perfiles fusiona el nuevo perfil con el antiguo mientras escribe los perfiles. Tenga en cuenta que los desarrolladores de aplicaciones no pueden acceder a /data/local/tmp ; deberían usar algún lugar como /storage/emulated/0/Android/data/ packagename /files en su lugar. Para cambiar la ubicación del archivo de perfil, configure la variable de entorno LLVM_PROFILE_FILE en tiempo de ejecución.

Luego, la utilidad llvm-profdata se utiliza para convertir el archivo .profraw (y posiblemente fusionar varios archivos .profraw ) en un archivo .profdata :

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

Luego, profile.profdata se puede registrar en el árbol de fuentes para usarlo durante la compilación.

Si se cargan varios binarios/bibliotecas instrumentadas durante una prueba comparativa, cada biblioteca genera un archivo .profraw separado con una identificación única separada. Normalmente, todos estos archivos se pueden fusionar en un único archivo .profdata y usarse para la compilación de PGO. En los casos en que una biblioteca sea ejercida por otro punto de referencia, esa biblioteca debe optimizarse utilizando perfiles de ambos puntos de referencia. En esta situación, la opción show de llvm-profdata es útil:

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

Para asignar Unique_id a bibliotecas individuales, busque en el resultado show para cada Unique_id un nombre de función que sea exclusivo de la biblioteca.

Estudio de caso: PGO para ART

El estudio de caso presenta el ART como un ejemplo identificable; sin embargo, no es una descripción precisa del conjunto real de bibliotecas perfiladas para ART o sus interdependencias.

El compilador adelantado dex2oat en ART depende de libart-compiler.so , que a su vez depende de libart.so . El tiempo de ejecución de ART se implementa principalmente en libart.so . Los puntos de referencia para el compilador y el tiempo de ejecución serán diferentes:

Punto de referencia Bibliotecas perfiladas
dex2oat dex2oat (ejecutable), libart-compiler.so , libart.so
art_runtime libart.so
  1. Agregue la siguiente propiedad pgo a dex2oat , libart-compiler.so :
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. Agregue la siguiente propiedad pgo a libart.so :
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. Cree compilaciones instrumentadas para los puntos de referencia dex2oat y art_runtime usando:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. Alternativamente, cree una única compilación instrumentada con todas las bibliotecas instrumentadas usando:

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

    El segundo comando construye todos los módulos habilitados para PGO para la creación de perfiles.

  5. Ejecute los puntos de referencia ejerciendo dex2oat y art_runtime para obtener:
    • Tres archivos .profraw de dex2oat ( dex2oat_exe.profdata , dex2oat_libart-compiler.profdata y dexeoat_libart.profdata ), identificados mediante el método descrito en Manejo de archivos de perfil LLVM .
    • Un único art_runtime_libart.profdata .
  6. Produzca un archivo profdata común para el ejecutable dex2oat y libart-compiler.so usando:
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. Obtenga el perfil de libart.so fusionando los perfiles de los dos puntos de referencia:
    llvm-profdata merge -output=libart.profdata \
        dex2oat_libart.profdata art_runtime_libart.profdata

    Los recuentos brutos de libart.so de los dos perfiles pueden ser dispares porque los puntos de referencia difieren en la cantidad de casos de prueba y la duración durante la cual se ejecutan. En este caso, puedes utilizar una combinación ponderada:

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

    El comando anterior asigna el doble de peso al perfil de dex2oat . El peso real debe determinarse en función del conocimiento o la experimentación del dominio.

  8. Verifique los archivos de perfil dex2oat.profdata y libart.profdata en toolchain/pgo-profiles para usarlos durante la compilación.