Il sistema di compilazione di Android per Android 13 e versioni precedenti supporta l'utilizzo dell'ottimizzazione basata su profilo (PGO) di Clang sui moduli Android nativi che hanno regole di compilazione blueprint. Questa pagina descrive la PGO di Clang, come generare e aggiornare continuamente i profili utilizzati per la PGO e come integrare la PGO con il sistema di compilazione (con use case).
Nota: questo documento descrive l'utilizzo di PGO nella piattaforma Android. Per scoprire di più sull'utilizzo di giochi di gru a pesca verticale online da un'app per Android, visita questa pagina.
Informazioni su Clang PGO
Clang può eseguire l'ottimizzazione basata su profilo utilizzando due tipi di profili:
- I profili basati sull'instrumentazione vengono generati da un programma di destinazione sottoposto a instrumentazione. Questi profili sono dettagliati e comportano un elevato costo aggiuntivo in fase di esecuzione.
- I profili basati sul campionamento vengono in genere generati da contatori hardware di campionamento. Impongono un basso sovraccarico di runtime e possono essere raccolti senza alcuna strumentazione o modifica del file binario. Sono meno dettagliati dei profili basati sulla misurazione.
Tutti i profili devono essere generati da un carico di lavoro rappresentativo che eserciti il comportamento tipico dell'app. Sebbene Clang supporti sia il profilo basato su AST (-fprofile-instr-generate
) sia quello basato su LLVM IR (-fprofile-generate)
), Android supporta solo il profilo basato su LLVM IR per il PGO basato sull'instrumentazione.
Per la compilazione per la raccolta dei profili sono necessari i seguenti flag:
-fprofile-generate
per la strumentazione basata su IR. Con questa opzione, il backend utilizza un approccio di albero ricoprente minimo ponderato per ridurre il numero di punti di misurazione e ottimizzare il loro posizionamento in base ai bordi a basso peso (utilizza questa opzione anche per il passaggio di collegamento). Il driver Clang passa automaticamente il runtime di profilazione (libclang_rt.profile-arch-android.a
) al linker. Questa libreria contiene routine per scrivere i profili sul disco al termine del programma.-gline-tables-only
per la raccolta dei profili basata su campionamento per generare informazioni di debug minime.
Un profilo può essere utilizzato per la PGO utilizzando
-fprofile-use=pathname
o
-fprofile-sample-use=pathname
rispettivamente per i profili basati su strumentazione e su campionamento.
Nota: man mano che vengono apportate modifiche al codice, se Clang non può più utilizzare i dati del profilo, genera un avviso -Wprofile-instr-out-of-date
.
Utilizzare PGO
L'utilizzo di PGO prevede i seguenti passaggi:
- Compila la libreria/l'eseguibile con la misurazione passando
-fprofile-generate
al compilatore e al linker. - Raccogli i profili eseguendo un carico di lavoro rappresentativo sul codice binario instrumentato.
- Esegui il post-trattamento dei profili utilizzando l'utilità
llvm-profdata
(per maggiori dettagli, vedi Gestire i file di profilo LLVM). - Utilizza i profili per applicare la PGO passando
-fprofile-use=<>.profdata
al compilatore e al linker.
Per la PGO in Android, i profili devono essere raccolti offline e controllati insieme al codice per garantire build riproducibili. I profili possono essere utilizzati man mano che il codice si evolve, ma devono essere rigenerati periodicamente (o ogni volta che Clang avvisa che i profili non sono aggiornati).
Raccogliere i profili
Clang può utilizzare i profili raccolti eseguendo benchmark con una compilazione instrumentata della libreria o campionando i contatori hardware durante l'esecuzione del benchmark. Al momento, Android non supporta l'utilizzo della raccolta dei profili basata sul campionamento, pertanto devi raccogliere i profili utilizzando una build instrumentata:
- Identifica un benchmark e l'insieme di librerie esercitate collettivamente da quel benchmark.
- Aggiungi le proprietà
pgo
al benchmark e alle librerie (dettagli di seguito). - Genera una build Android con una copia instrumentata di queste librerie utilizzando:
make ANDROID_PGO_INSTRUMENT=benchmark
benchmark
è un segnaposto che identifica la raccolta di librerie sottoposte a ispezione durante la compilazione. Gli input rappresentativi effettivi (e possibilmente un altro file eseguibile che esegue il collegamento a una libreria di cui viene eseguito il benchmark) non sono specifici per la PGO e non rientrano nell'ambito di questo documento.
- Esegui il flashing o la sincronizzazione della build con strumenti su un dispositivo.
- Esegui il benchmark per raccogliere i profili.
- Utilizza lo strumento
llvm-profdata
(descritto di seguito) per eseguire il post-trattamento dei profili e prepararli per il check-in nell'albero di origine.
Utilizzare i profili durante la compilazione
Controlla i profili in toolchain/pgo-profiles
in un albero Android. Il nome deve corrispondere a quello specificato nella proprietà secondaria profile_file
della proprietà pgo
per la raccolta. Il sistema di compilazione passa automaticamente il file del profilo a Clang
durante la compilazione della libreria. La variabile di ambiente ANDROID_PGO_DISABLE_PROFILE_USE
può essere impostata su true
per
disattivare temporaneamente la PGO e misurarne il vantaggio in termini di prestazioni.
Per specificare altre directory di profili specifici per prodotto, aggiungile alla variabile PGO_ADDITIONAL_PROFILE_DIRECTORIES
in un BoardConfig.mk
. Se vengono specificati percorsi aggiuntivi, i profili in questi percorsi sostituiscono quelli in toolchain/pgo-profiles
.
Quando generi un'immagine di release utilizzando il target dist
per
make
, il sistema di compilazione scrive i nomi dei file di profilo mancanti
in $DIST_DIR/pgo_profile_file_missing.txt
. Puoi controllare questo
file per vedere quali file del profilo sono stati eliminati accidentalmente (il che disattiva silenziosamente PGO).
Attivare PGO nei file Android.bp
Per attivare la PGO nei file Android.bp
per i moduli nativi, basta
specificare la proprietà pgo
. Questa proprietà ha le seguenti proprietà secondarie:
Proprietà | Descrizione |
---|---|
instrumentation
|
Imposta su true per la PGO utilizzando la misurazione. Il valore predefinito è
false . |
sampling
|
Impostato su true per la PGO con il campionamento. Il valore predefinito è
false . |
benchmarks
|
Elenco di stringhe. Questo modulo è progettato per il profiling se un benchmark
nell'elenco è specificato nell'opzione ANDROID_PGO_INSTRUMENT build. |
profile_file
|
File del profilo (relativo a toolchain/pgo-profile ) da utilizzare
con PGO. La compilazione avvisa che questo file non esiste aggiungendolo
a $DIST_DIR/pgo_profile_file_missing.txt
a meno che la proprietà enable_profile_use non sia impostata su
false OPPURE la variabile di compilazione ANDROID_PGO_NO_PROFILE_USE non sia impostata su
true . |
enable_profile_use
|
Imposta su false se i profili non devono essere utilizzati durante la compilazione. Può essere utilizzato durante il bootstrap per attivare la raccolta dei profili o per disattivare temporaneamente la PGO. Il valore predefinito è true . |
cflags
|
Elenco di flag aggiuntivi da utilizzare durante una compilazione con strumenti. |
Esempio di un modulo 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", } }
Se i benchmark benchmark1
e benchmark2
adottano un comportamento rappresentativo per le librerie libstatic1
,
libstatic2
o libshared1
, la proprietà pgo
di queste librerie può includere anche i benchmark. Il
modulo defaults
in Android.bp
può includere una specifica pgo
comune per un insieme di librerie per evitare di ripetere le
stesse regole di compilazione per più moduli.
Per selezionare file di profilo diversi o disattivare selettivamente la PGO per un'architettura, specifica le proprietà profile_file
, enable_profile_use
e cflags
per l'architettura. Esempio (con il target dell'architettura in
grassetto):
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", } } } }
Per risolvere i riferimenti alla libreria di runtime di profilazione durante la profilazione basata su strumenti, passa il flag di compilazione -fprofile-generate
al linker. Anche le librerie statiche instrumentate con PGO, tutte le librerie condivise e qualsiasi programma binario che dipende direttamente dalla libreria statica devono essere instrumentate per PGO. Tuttavia, queste librerie o eseguibili condivisi non devono utilizzare profili PGO e la loro proprietà enable_profile_use
può essere impostata su false
.
Al di fuori di questa limitazione, puoi applicare la PGO a qualsiasi libreria statica, libreria condivisa o eseguibile.
Gestire i file di profilo LLVM
L'esecuzione di una libreria o di un file eseguibile sottoposto a ispezione produce un file di profilo
denominato default_unique_id_0.profraw
in
/data/local/tmp
(dove unique_id
è un
hash numerico univoco per questa libreria). Se questo file esiste già, il runtime di profilazione unisce il nuovo profilo con quello precedente durante la scrittura dei profili. Tieni presente che /data/local/tmp
non è accessibile agli sviluppatori di app, che devono utilizzare un sito come /storage/emulated/0/Android/data/packagename/files
.
Per modificare la posizione del file del profilo, imposta la variabile di ambiente LLVM_PROFILE_FILE
in fase di runtime.
L'utilità llvm-profdata
viene poi utilizzata per convertire il file .profraw
(e possibilmente
unire più file .profraw
) in un file .profdata
:
llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>
profile.profdata
può quindi essere sottoposto a check-in nell'albero di origine per essere utilizzato durante la compilazione.
Se durante un benchmark vengono caricati più binari/librerie con strumenti di misurazione, ogni libreria genera un file .profraw
separato con un ID univoco distinto. In genere, tutti questi file possono essere uniti in un unico
.profdata
file e utilizzati per la compilazione PGO. Se una libreria viene utilizzata da un altro benchmark, deve essere ottimizzata utilizzando i profili di entrambi i benchmark. In questa situazione, l'opzione show
di llvm-profdata
è utile:
llvm-profdata merge -output=default_unique_id.profdata default_unique_id_0.profraw llvm-profdata show -all-functions default_unique_id.profdata
Per mappare gli unique_id alle singole librerie, cerca nell'output di show
per ogni unique_id un nome funzione univoco per la libreria.
Case study: giochi di realtà aumentata per ART
Il caso studio presenta ART come un esempio pertinente, ma non è una descrizione accurata dell'insieme effettivo di librerie profilate per ART o delle relative interdipendenze.
Il compilatore dex2oat
ahead-of-time in ART dipende da
libart-compiler.so
, che a sua volta dipende da
libart.so
. Il runtime ART è implementato principalmente in
libart.so
. I benchmark per il compilatore e il runtime saranno diversi:
Benchmark | Librerie profilate |
---|---|
dex2oat
|
dex2oat (eseguibile), libart-compiler.so ,
libart.so |
art_runtime
|
libart.so
|
- Aggiungi la seguente proprietà
pgo
adex2oat
,libart-compiler.so
:pgo: { instrumentation: true, benchmarks: ["dex2oat",], profile_file: "dex2oat.profdata", }
- Aggiungi la seguente proprietà
pgo
alibart.so
:pgo: { instrumentation: true, benchmarks: ["art_runtime", "dex2oat",], profile_file: "libart.profdata", }
- Crea build con strumenti per i benchmark
dex2oat
eart_runtime
utilizzando:make ANDROID_PGO_INSTRUMENT=dex2oat make ANDROID_PGO_INSTRUMENT=art_runtime
- Esegui i benchmark con
dex2oat
eart_runtime
per ottenere:- Tre file
.profraw
didex2oat
(dex2oat_exe.profdata
,dex2oat_libart-compiler.profdata
edexeoat_libart.profdata
), identificati utilizzando il metodo descritto in Gestione dei file di profilo LLVM. - Un singolo
art_runtime_libart.profdata
.
- Tre file
- Genera un file profdata comune per l'eseguibile
dex2oat
elibart-compiler.so
utilizzando:llvm-profdata merge -output=dex2oat.profdata \ dex2oat_exe.profdata dex2oat_libart-compiler.profdata
- Ottieni il profilo di
libart.so
unendo i profili dei due benchmark:llvm-profdata merge -output=libart.profdata \ dex2oat_libart.profdata art_runtime_libart.profdata
I conteggi non elaborati per
libart.so
dei due profili potrebbero essere diversi perché i benchmark differiscono per il numero di casi di test e per la durata per cui vengono eseguiti. In questo caso, puoi utilizzare un'unione ponderata:llvm-profdata merge -output=libart.profdata \ -weighted-input=2,dex2oat_libart.profdata \ -weighted-input=1,art_runtime_libart.profdata
Il comando riportato sopra assegna il doppio del peso al profilo da
dex2oat
. Il peso effettivo deve essere determinato in base alle conoscenze o alla sperimentazione nel dominio. - Controlla i file del profilo
dex2oat.profdata
elibart.profdata
intoolchain/pgo-profiles
per utilizzarli durante la compilazione.
In alternativa, crea una singola build con tutte le librerie instrumentate utilizzando:
make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime (or) make ANDROID_PGO_INSTRUMENT=ALL
Il secondo comando compila tutti i moduli PGO abilitati per il profiling.