Il sistema di build Android per Android 13 e versioni precedenti supporta l'utilizzo dell'ottimizzazione guidata dal profilo (PGO) di Clang su moduli Android nativi che dispongono di regole di build del progetto . Questa pagina descrive Clang PGO, come generare e aggiornare continuamente i profili utilizzati per PGO e come integrare PGO con il sistema di compilazione (con caso d'uso).
NB: Questo documento descrive l'uso di PGO nella piattaforma Android. Per informazioni sull'utilizzo di PGO da un'app Android, visitare questa pagina .
A proposito di Clang PGO
Clang può eseguire l'ottimizzazione guidata dal profilo utilizzando due tipi di profili:
- I profili basati sulla strumentazione vengono generati da un programma target strumentato. Questi profili sono dettagliati e impongono un elevato sovraccarico di runtime.
- I profili basati sul campionamento vengono generalmente prodotti campionando i contatori hardware. Impongono un basso sovraccarico di runtime e possono essere raccolti senza alcuna strumentazione o modifica al binario. Sono meno dettagliati dei profili basati sulla strumentazione.
Tutti i profili devono essere generati da un carico di lavoro rappresentativo che eserciti il comportamento tipico dell'app. Mentre Clang supporta sia basato su AST ( -fprofile-instr-generate
) che LLVM IR ( -fprofile-generate)
, Android supporta solo LLVM IR per PGO basato su strumentazione.
Sono necessari i seguenti flag per creare la raccolta dei profili:
-
-fprofile-generate
per strumentazione basata su IR. Con questa opzione, il backend utilizza un approccio di spanning tree minimo ponderato per ridurre il numero di punti di strumentazione e ottimizzare il loro posizionamento su bordi di peso ridotto (utilizzare questa opzione anche per la fase 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 su disco all'uscita dal programma. -
-gline-tables-only
per la raccolta di profili basata su campionamento per generare informazioni di debug minime.
È possibile utilizzare un profilo per PGO utilizzando -fprofile-use= pathname
o -fprofile-sample-use= pathname
rispettivamente per i profili basati sulla strumentazione e basati sul campionamento.
Nota: quando vengono apportate modifiche al codice, se Clang non può più utilizzare i dati del profilo genera un avviso -Wprofile-instr-out-of-date
.
Usa PGO
L'utilizzo di PGO prevede i seguenti passaggi:
- Costruisci la libreria/eseguibile con la strumentazione passando
-fprofile-generate
al compilatore e al linker. - Raccogli i profili eseguendo un carico di lavoro rappresentativo sul binario strumentato.
- Postelaborare i profili utilizzando l'utilità
llvm-profdata
(per i dettagli, vedere Gestione dei file di profilo LLVM ). - Utilizzare i profili per applicare PGO passando
-fprofile-use=<>.profdata
al compilatore e al linker.
Per PGO in Android, i profili devono essere raccolti offline e archiviati 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 avverte che i profili sono obsoleti).
Raccogli profili
Clang può utilizzare i profili raccolti eseguendo benchmark utilizzando una build strumentata della libreria o campionando i contatori hardware durante l'esecuzione del benchmark. Al momento, Android non supporta l'utilizzo della raccolta di profili basata su campionamento, pertanto è necessario raccogliere i profili utilizzando una build strumentata:
- Identificare un benchmark e l'insieme di biblioteche collettivamente esercitate da quel benchmark.
- Aggiungi le proprietà
pgo
al benchmark e alle librerie (dettagli di seguito). - Produci una build Android con una copia strumentata di queste librerie utilizzando:
make ANDROID_PGO_INSTRUMENT=benchmark
benchmark
è un segnaposto che identifica la raccolta di librerie strumentate durante la compilazione. Gli input rappresentativi effettivi (e possibilmente un altro eseguibile che si collega a una libreria sottoposta a benchmark) non sono specifici di PGO e vanno oltre lo scopo di questo documento.
- Flash o sincronizza la build strumentata su un dispositivo.
- Esegui il benchmark per raccogliere i profili.
- Utilizzare lo strumento
llvm-profdata
(discusso di seguito) per post-elaborare i profili e renderli pronti per essere archiviati nell'albero di origine.
Utilizza i profili durante la creazione
Controlla i profili in toolchain/pgo-profiles
in un albero Android. Il nome deve corrispondere a quanto specificato nella sottoproprietà profile_file
della proprietà pgo
per la libreria. Il sistema di compilazione passa automaticamente il file del profilo a Clang durante la creazione della libreria. La variabile di ambiente ANDROID_PGO_DISABLE_PROFILE_USE
può essere impostata su true
per disabilitare temporaneamente PGO e misurarne il vantaggio in termini di prestazioni.
Per specificare ulteriori directory di profili specifici del prodotto, aggiungerle alla variabile make PGO_ADDITIONAL_PROFILE_DIRECTORIES
in un BoardConfig.mk
. Se vengono specificati percorsi aggiuntivi, i profili in questi percorsi sovrascrivono quelli in toolchain/pgo-profiles
.
Quando si genera un'immagine di rilascio utilizzando la destinazione 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 di profilo sono stati eliminati accidentalmente (il che disabilita silenziosamente PGO).
Abilita PGO nei file Android.bp
Per abilitare PGO nei file Android.bp
per i moduli nativi, è sufficiente specificare la proprietà pgo
. Questa proprietà ha le seguenti sottoproprietà:
Proprietà | Descrizione |
---|---|
instrumentation | Impostato su true per PGO che utilizza la strumentazione. L'impostazione predefinita è false . |
sampling | Impostato su true per PGO che utilizza il campionamento. L'impostazione predefinita è false . |
benchmarks | Elenco delle stringhe. Questo modulo è creato per la profilazione se qualsiasi benchmark nell'elenco è specificato nell'opzione di compilazione ANDROID_PGO_INSTRUMENT . |
profile_file | File di profilo (relativo a toolchain/pgo-profile ) da utilizzare con PGO. La build avvisa che questo file non esiste aggiungendo questo file 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 build ANDROID_PGO_NO_PROFILE_USE sia impostata su true . |
enable_profile_use | Impostato su false se i profili non devono essere utilizzati durante la compilazione. Può essere utilizzato durante il bootstrap per abilitare la raccolta dei profili o per disabilitare temporaneamente PGO. L'impostazione predefinita è true . |
cflags | Elenco di flag aggiuntivi da utilizzare durante una compilazione strumentata. |
Esempio di 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
esercitano 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 set di librerie per evitare di ripetere le stesse regole di compilazione per diversi moduli.
Per selezionare file di profilo diversi o disabilitare selettivamente PGO per un'architettura, specificare le proprietà profile_file
, enable_profile_use
e cflags
per architettura. Esempio (con l'obiettivo 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 runtime di profilazione durante la profilatura basata sulla strumentazione, passare il flag di build -fprofile-generate
al linker. Anche le librerie statiche dotate di PGO, tutte le librerie condivise e qualsiasi file binario che dipende direttamente dalla libreria statica devono essere dotate di PGO. Tuttavia, tali librerie condivise o eseguibili non necessitano di utilizzare profili PGO e la loro proprietà enable_profile_use
può essere impostata su false
. Al di fuori di questa restrizione, è possibile applicare PGO a qualsiasi libreria statica, libreria condivisa o eseguibile.
Gestire i file del profilo LLVM
L'esecuzione di una libreria instrumentata o di un eseguibile 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 vecchio durante la scrittura dei profili. Tieni presente che /data/local/tmp
non è accessibile agli sviluppatori di app; dovrebbero invece usare da qualche parte come /storage/emulated/0/Android/data/ packagename /files
. Per modificare la posizione del file di profilo, impostare la variabile di ambiente LLVM_PROFILE_FILE
in fase di runtime.
L'utilità llvm-profdata
viene quindi utilizzata per convertire il file .profraw
(ed eventualmente unire più file .profraw
) in un file .profdata
:
llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>
profile.profdata
può quindi essere archiviato nell'albero dei sorgenti per essere utilizzato durante la compilazione.
Se durante un benchmark vengono caricati più file binari/librerie strumentate, ciascuna libreria genera un file .profraw
separato con un ID univoco separato. In genere, tutti questi file possono essere uniti in un singolo file .profdata
e utilizzati per la compilazione PGO. Nei casi in cui una libreria viene utilizzata da un altro benchmark, tale libreria 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 unique_id a singole librerie, cercare nell'output show
per ogni unique_id un nome di funzione univoco per la libreria.
Caso di studio: PGO per ART
Il caso di studio presenta l'ART come un esempio riconoscibile; tuttavia, non è una descrizione accurata dell'effettivo insieme di librerie profilate per ART o delle loro interdipendenze.
Il compilatore anticipato dex2oat
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:
Segno di riferimento | Biblioteche 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 strumentate per i benchmark
dex2oat
eart_runtime
utilizzando:make ANDROID_PGO_INSTRUMENT=dex2oat make ANDROID_PGO_INSTRUMENT=art_runtime
- Eseguire i benchmark esercitando
dex2oat
eart_runtime
per ottenere:- Tre file
.profraw
dadex2oat
(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
- Produci 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 per
libart.so
unendo i profili dai due benchmark:llvm-profdata merge -output=libart.profdata \ dex2oat_libart.profdata art_runtime_libart.profdata
I conteggi grezzi per
libart.so
dai due profili potrebbero essere disparati perché i benchmark differiscono nel numero di casi di test e nella durata per cui vengono eseguiti. In questo caso, puoi utilizzare una fusione ponderata:llvm-profdata merge -output=libart.profdata \ -weighted-input=2,dex2oat_libart.profdata \ -weighted-input=1,art_runtime_libart.profdata
Il comando precedente assegna il doppio del peso al profilo da
dex2oat
. Il peso effettivo dovrebbe essere determinato in base alla conoscenza del settore o alla sperimentazione. - Controlla i file del profilo
dex2oat.profdata
elibart.profdata
intoolchain/pgo-profiles
da utilizzare durante la compilazione.
In alternativa, crea una singola build strumentata con tutte le librerie strumentate utilizzando:
make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime (or) make ANDROID_PGO_INSTRUMENT=ALL
Il secondo comando crea tutti i moduli abilitati per PGO per la profilazione.