Ottimizzazione basata sul profilo

Ottimizzazione guidata dal profilo è un modello di ottimizzazione ben noto tecnica. In PGO, i profili di runtime delle esecuzioni di un programma vengono utilizzati per fare scelte ottimali riguardo all'incorporamento e al layout del codice. Questo porta a di miglioramento delle prestazioni e riduzione delle dimensioni del codice.

Puoi eseguire il deployment di PGO nell'applicazione o nella libreria seguendo questi passaggi: 1. Identifica un carico di lavoro rappresentativo. 2. Raccogliere i profili. 3. Utilizzare i profili in una build di release.

Passaggio 1: identifica un carico di lavoro rappresentativo

In primo luogo, identifica un benchmark o un carico di lavoro rappresentativo per la tua applicazione. Si tratta di un passaggio fondamentale perché i profili raccolti dal carico di lavoro identificano le regioni calde e fredde del codice. Quando vengono utilizzati i profili, il compilatore eseguire ottimizzazioni aggressive e l'integrazione nelle regioni più calde. Il compilatore può anche scegliere di ridurre le dimensioni del codice delle regioni fredde mentre le prestazioni dei dispositivi.

L'identificazione di un buon carico di lavoro è utile anche per tenere traccia delle prestazioni in generale.

Passaggio 2: raccogli i profili

La raccolta del profilo prevede tre passaggi: - creazione di codice nativo con la strumentazione, - esecuzione dell'app con strumentazione sul dispositivo e generazione di profili; e - unione/post-elaborazione dei profili sull'host.

Crea build strumentata

I profili vengono raccolti eseguendo il carico di lavoro dal passaggio 1 su una della build dell'applicazione. Per generare una build instrumentata, aggiungi -fprofile-generate ai flag di compilatore e linker. Questo flag deve essere controllato da una variabile build separata poiché il flag non è necessario durante per la creazione predefinita.

Genera profili

Quindi, esegui l'app con gli strumenti sul dispositivo e genera i profili. I profili vengono raccolti in memoria quando il file binario strumentato viene eseguito e scritto in un file all'uscita. Tuttavia, le funzioni registrate con atexit non sono chiamato in un'app Android, l'app si interrompe.

L'applicazione/il carico di lavoro deve svolgere un lavoro aggiuntivo per impostare un percorso per il file del profilo e poi attivare esplicitamente la scrittura del profilo.

  • Per impostare il percorso file del profilo, chiama __llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw. %m è utile in presenza di più librerie condivise. %m` si espande in un modulo univoco firma per quella libreria, in modo da avere un profilo separato per ogni libreria. Consulta qui per altri utili specificatori di pattern. PROFILE_DIR è una directory che scrivibile dall'app. Guarda la demo per rilevare questa directory in fase di runtime.
  • Per attivare esplicitamente la scrittura di un profilo, chiama __llvm_profile_write_file personalizzata.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_write_file(void);
}

#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
  // ...
  // run workload
  // ...

  // set path and write profiles after workload execution
  __llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
  __llvm_profile_write_file();
  return;
}

Nota: generare il file di profilo è più semplice se il carico di lavoro è un file binario autonomo, imposta la variabile di ambiente LLVM_PROFILE_FILE su %t/default-%m.profraw prima di eseguire il programma binario.

Profili post-elaborazione

I file del profilo sono in formato .profraw. Occorre prima recuperarli il dispositivo utilizzando adb pull. Dopo il recupero, utilizza l'utilità llvm-profdata in l'NDK per convertire da .profraw a .profdata, che possono poi essere passati all'account come compilatore.

$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
    merge --output=pgo_profile.profdata \
    <list-of-profraw-files>

Usa llvm-profdata e clang della stessa release NDK per evitare la versione la mancata corrispondenza tra i formati file del profilo.

Passaggio 3: usa i profili per creare un'applicazione

Usa il profilo del passaggio precedente durante una build della release del tuo un'applicazione passando -fprofile-use=<>.profdata a compilatore e linker. La i profili possono essere utilizzati anche quando il codice si evolve: il compilatore Clang è in grado di tollerare lieve mancata corrispondenza tra l'origine e i profili.

Nota: in generale, per la maggior parte delle librerie, i profili sono comuni a tutte le architetture. Ad esempio, i profili generati dalla build arm64 della libreria possono essere utilizzati per in tutte le architetture. L'avvertenza è che se ci sono architetture specifiche percorsi di codice nella libreria (arm vs x86 o 32-bit rispetto a 64-bit), profili separati per ciascuna di queste configurazioni.

Riassumendo

https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo mostra una demo end-to-end sull'utilizzo di PGO da un'app. Fornisce ulteriori più dettagliati trattati in questo documento.

  • La build di CMake regole che spiega come configurare una variabile CMake che crea codice nativo con la strumentazione. Se la variabile di build non è impostata, il codice nativo viene ottimizzato utilizzando generati con i profili PGO.
  • In una build instrumentata, pgodemo.cpp e scrive: i profili sono l'esecuzione del carico di lavoro.
  • È disponibile una posizione accessibile in scrittura per i profili in fase di runtime in MainActivity.kt utilizzando applicationContext.cacheDir.toString().
  • Per estrarre profili dal dispositivo senza richiedere adb root, usa adb ricetta qui.