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:
- Cree la biblioteca/ejecutable con instrumentación pasando
-fprofile-generate
al compilador y al vinculador. - Recopile perfiles ejecutando una carga de trabajo representativa en el binario instrumentado.
- Realice un posprocesamiento de los perfiles utilizando la utilidad
llvm-profdata
(para obtener más detalles, consulte Manejo de archivos de perfil LLVM ). - 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:
- Identificar un punto de referencia y el conjunto de bibliotecas ejercidas colectivamente por ese punto de referencia.
- Agregue propiedades
pgo
al punto de referencia y a las bibliotecas (detalles a continuación). - 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.
- Actualice o sincronice la compilación instrumentada en un dispositivo.
- Ejecute el punto de referencia para recopilar perfiles.
- 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 |
- Agregue la siguiente propiedad
pgo
adex2oat
,libart-compiler.so
:pgo: { instrumentation: true, benchmarks: ["dex2oat",], profile_file: "dex2oat.profdata", }
- Agregue la siguiente propiedad
pgo
alibart.so
:pgo: { instrumentation: true, benchmarks: ["art_runtime", "dex2oat",], profile_file: "libart.profdata", }
- Cree compilaciones instrumentadas para los puntos de referencia
dex2oat
yart_runtime
usando:make ANDROID_PGO_INSTRUMENT=dex2oat make ANDROID_PGO_INSTRUMENT=art_runtime
- Ejecute los puntos de referencia ejerciendo
dex2oat
yart_runtime
para obtener:- Tres archivos
.profraw
dedex2oat
(dex2oat_exe.profdata
,dex2oat_libart-compiler.profdata
ydexeoat_libart.profdata
), identificados mediante el método descrito en Manejo de archivos de perfil LLVM . - Un único
art_runtime_libart.profdata
.
- Tres archivos
- Produzca un archivo profdata común para el ejecutable
dex2oat
ylibart-compiler.so
usando:llvm-profdata merge -output=dex2oat.profdata \ dex2oat_exe.profdata dex2oat_libart-compiler.profdata
- 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. - Verifique los archivos de perfil
dex2oat.profdata
ylibart.profdata
entoolchain/pgo-profiles
para usarlos durante la compilación.
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.