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:
- Cree la biblioteca/ejecutable con instrumentación pasando
-fprofile-generate
al compilador y al enlazador. - Recopile perfiles ejecutando una carga de trabajo representativa en el binario instrumentado.
- Realice un procesamiento posterior de los perfiles con la utilidad
llvm-profdata
(para obtener detalles, consulte Manejo de archivos de perfil LLVM ). - 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:
- Identifique un punto de referencia y el conjunto de bibliotecas ejercidas colectivamente por ese punto de referencia.
- Agregue propiedades de
pgo
al punto de referencia y 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 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.
- Actualice o sincronice la compilación instrumentada en un dispositivo.
- Ejecute el punto de referencia para recopilar perfiles.
- 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 |
- 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
- Ejecuta los benchmarks ejercitando
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 solo
art_runtime_libart.profdata
.
- Tres archivos
- Genere 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 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. - 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.