Uso de la optimización guiada por perfiles (PGO)

El sistema de compilación de Android admite el uso de la optimización guiada por perfil (PGO) de Clang en módulos nativos de Android que tienen reglas de compilación de blueprint . Esta página describe Clang PGO, cómo generar y actualizar continuamente los perfiles utilizados para PGO y cómo integrar PGO con el sistema de compilación (con un 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 elevada 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 o 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 es compatible tanto con AST ( -fprofile-instr-generate ) como con LLVM IR ( -fprofile-generate) , Android solo admite LLVM IR para PGO basado en instrumentación.

Se necesitan los siguientes indicadores para compilar 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 de Clang pasa automáticamente el tiempo de ejecución de creación de perfiles ( libclang_rt.profile- arch -android.a ) al enlazador. 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 muestras para generar información de depuración mínima.

Se puede usar un perfil para PGO usando -fprofile-instr-use= pathname o -fprofile-sample-use= pathname para perfiles basados ​​en instrumentación y basados ​​en 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 -Wprofile-instr-out-of-date .

Usando PGO

El uso de PGO implica los siguientes pasos:

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

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 usar a medida que el código evoluciona, pero deben regenerarse periódicamente (o siempre que Clang advierta que los perfiles están obsoletos).

Recopilación de perfiles

Clang puede usar perfiles recopilados mediante la ejecución de puntos de referencia utilizando una compilación instrumentada de la biblioteca o mediante el muestreo de contadores de hardware cuando se ejecuta el punto de referencia. En este momento, Android no admite el uso de la recopilación de perfiles basada en muestras, por lo que debe recopilar perfiles mediante una compilación instrumentada:

  1. Identifique un punto de referencia y el conjunto de bibliotecas ejercidas colectivamente por ese punto de referencia.
  2. Agregue propiedades de pgo al punto de referencia y 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 compilació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 (discutida a continuación) para procesar los perfiles y prepararlos para que se registren en el árbol de origen.

Uso de perfiles durante la compilación

Verifique los perfiles en toolchain/pgo-profiles en un árbol de Android. El nombre debe coincidir con lo que se especifica en la profile_file profile_file de la propiedad pgo para la biblioteca. El sistema de compilación pasa automáticamente el archivo de perfil a Clang al compilar 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 específicos de productos adicionales, agréguelos a la variable make PGO_ADDITIONAL_PROFILE_DIRECTORIES en un 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 dist target to make , el sistema de compilación escribe los nombres de los archivos de perfil que faltan en $DIST_DIR/pgo_profile_file_missing.txt . Puede verificar este archivo para ver qué archivos de perfil se eliminaron accidentalmente (lo que desactiva silenciosamente PGO).

Habilitación de 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 Establecer en true para PGO usando instrumentación. El valor predeterminado es false .
sampling Establézcalo en true para PGO mediante muestreo. El valor predeterminado es false .
benchmarks Lista de cadenas. Este módulo está diseñado para generar 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 la cadena de 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é establecida en false O la variable de compilación ANDROID_PGO_NO_PROFILE_USE esté configurada en true .
enable_profile_use Establézcalo en false si los perfiles no deben usarse durante la compilación. Se puede usar durante el arranque para habilitar la recopilación de perfiles o para deshabilitar temporalmente PGO. El valor predeterminado es true .
cflags Lista de banderas 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 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 enable_profile_use profile_file cflags por arquitectura. Ejemplo (con el objetivo de la 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 las referencias a la biblioteca en tiempo de ejecución de generación de perfiles durante la generación de perfiles basada en instrumentación, pase el indicador de compilación -fprofile-generate al enlazador. 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 usar 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.

Manejo de archivos de perfil LLVM

La ejecución de una biblioteca instrumentada o ejecutable produce un archivo de perfil denominado default_ unique_id _0.profraw en /data/local/tmp (donde unique_id es un hash numérico que es 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 usa 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>

A continuación, profile.profdata se puede verificar en el árbol de fuentes para su uso durante la compilación.

Si se cargan múltiples binarios/bibliotecas instrumentados durante una evaluación comparativa, cada biblioteca genera un archivo .profraw independiente con una ID única independiente. Por lo general, todos estos archivos se pueden combinar en un solo archivo .profdata y se pueden usar para compilar PGO. En los casos en que una biblioteca es 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 id_únicos a bibliotecas individuales, busque en el resultado de show para cada id_único un nombre de función que sea único para la biblioteca.

Estudio de caso: PGO para ART

El estudio de caso presenta 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. Ejecuta los benchmarks ejercitando 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 solo art_runtime_libart.profdata .
  6. Genere 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 para 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 sin procesar 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 de su ejecución. En este caso, puede usar 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 del dominio o la experimentación.

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