Il file degli ordini è una tecnica di ottimizzazione recente del linker. Questi file di ordine sono file di testo contenenti simboli che rappresentano funzioni. I linker come lld utilizzano i file di ordine per strutturare le funzioni in un ordine specifico. Questi programmi binari o librerie con simboli ordinati riducono gli errori delle pagine e migliorano il tempo di avvio di un programma grazie al caricamento efficiente dei simboli durante l'avvio a freddo di un programma.
Le funzionalità dei file di ordine possono essere aggiunte alla tua applicazione seguendo tre passaggi:
- Genera profili e file di mappatura
- Crea un file di ordine dai profili e dal file di mappatura
- Utilizza il file dell'ordine durante la build della release per definire il layout dei simboli
Genera file di ordine
La generazione di un file dell'ordine richiede tre passaggi:
- Crea una versione con strumentazione dell'app che scrive il file dell'ordine
- Esegui l'app per generare i profili
- Post-elaborazione dei profili e del file di mappatura
Crea una build strumentale
I profili vengono generati eseguendo una build dell'applicazione strumentata.
Una build con strumentazione richiede l'aggiunta di -forder-file-instrumentation
ai flag del compilatore e del linker, mentre -mllvm -orderfile-write-mapping=<filename>-mapping.txt
viene aggiunto rigorosamente ai flag del compilatore.
Il flag di strumentazione consente la strumentazione dei file di ordine per la profilazione e carica la libreria specifica necessaria per la profilazione.
D'altra parte, il flag di mappatura restituisce solo il file di mapping che mostra l'hash MD5 per ogni funzione all'interno del programma binario o della libreria.
Inoltre, assicurati di passare qualsiasi flag di ottimizzazione, ma -O0
perché sia
il flag di strumentazione sia quello di mappatura ne richiedono uno.
Se non viene passato alcun flag di ottimizzazione, il file di mapping non viene generato e la build instrumentata potrebbe generare hash errati nel file del profilo.
build-ndk
Assicurati di creare con APP_OPTIM=release
, in modo che ndk-build utilizzi una modalità di ottimizzazione diversa da -O0
. Quando crei con AGP, questa funzionalità
è automatica per le build di release.
LOCAL_CFLAGS += \
-forder-file-instrumentation \
-mllvm -orderfile-write-mapping=mapping.txt \
LOCAL_LDFLAGS += -forder-file-instrumentation
Marca
Assicurati di utilizzare CMAKE_BUILD_TYPE
diverso da Debug
, quindi CMake utilizza una
modalità di ottimizzazione diversa da -O0
. Quando crei con AGP, questo è automatico
per le build di release.
target_compile_options(orderfiledemo PRIVATE
-forder-file-instrumentation
-mllvm -orderfile-write-mapping=mapping.txt
)
target_link_options(orderfiledemo PRIVATE -forder-file-instrumentation)
Altri sistemi di build
Compila il codice utilizzando -forder-file-instrumentation -O1 -mllvm
-orderfile-write-mapping=mapping.txt
.
-O1
non è obbligatorio, ma non utilizzare -O0
.
Ometti -mllvm -orderfile-write-mapping=mapping.txt
durante il collegamento.
Tutti questi flag non sono necessari per una build di release, quindi dovrebbe essere controllata da una variabile di build. Per semplicità, puoi configurare tutto questo in CMakeLists.txt come nel nostro esempio.
Creare una libreria di file degli ordini
Oltre ai flag, è necessario configurare il file del profilo e il programma binario strumentato deve attivare esplicitamente la scrittura del profilo durante l'esecuzione.
- Chiama
__llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw")
per configurare il percorso del profilo. Anche se l'argomento passato è<filename>-%m.profraw
, il file del profilo viene salvato come<filename>-%m.profraw.order
. Assicurati che l'app possa scriverePROFILE_DIR
e di avere accesso alla directory.- A causa della profilazione di molte librerie condivise,
%m
è utile perché si espande in una firma univoca del modulo per la libreria, creando un profilo separato per ogni libreria. Per altri identificatori di pattern, visita questo link.
- A causa della profilazione di molte librerie condivise,
- Chiama
__llvm_profile_initialize_file()
per configurare il file del profilo - Chiama
__llvm_orderfile_dump()
per scrivere esplicitamente nel file del profilo
I profili vengono raccolti in memoria e la funzione di dump li scrive nel file. Assicurati che la funzione dump venga richiamata alla fine dell'avvio, in modo che il file del profilo abbia tutti i simboli fino alla fine dell'avvio.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_initialize_file(void);
extern int __llvm_orderfile_dump(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_initialize_file();
__llvm_orderfile_dump();
return;
}
Esegui la build per i profili
Esegui l'app instrumentata su un dispositivo fisico o virtuale per generare i profili.
Puoi estrarre i file del profilo utilizzando adb pull
.
adb shell "run-as <package-name> sh -c 'cat /data/user/0/<package-name>/cache/default-%m.profraw.order' | cat > /data/local/tmp/default-%m.profraw.order"
adb pull /data/local/tmp/default-%m.profraw.order .
Come accennato in precedenza, assicurati che tu possa accedere alla cartella contenente il file del profilo scritto. Se si tratta di un dispositivo virtuale, ti consigliamo di evitare gli emulatori con Play Store perché non hai accesso a molte cartelle.
Post-elaborare il profilo e il file di mappatura
Una volta ottenuti i profili, devi individuare il file di mappatura e convertire ogni profilo in formato esadecimale. In genere, puoi trovare il file di mapping nella cartella di build dell'app. Se hai entrambi, puoi utilizzare il nostro script per acquisire un file di profilo e il file di mapping corretto per generare un file di ordine.
Linux/Mac/ChromeOS
hexdump -C default-%m.profraw.order > default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
Windows
certutil -f -encodeHex default-%m.profraw.order default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
Per ulteriori informazioni sullo script, consulta questo README.
Utilizza il file dell'ordine per creare l'applicazione
Dopo aver generato un file di ordine, devi rimuovere i flag precedenti e le funzioni del file di ordine, perché sono solo per i passaggi di generazione.
Devi solo passare -Wl,--symbol-ordering-file=<filename>.orderfile
ai
flag di compilazione e linker.
A volte, è impossibile trovare o spostare i simboli. È possibile che vengano visualizzati avvisi in modo da poter passare -Wl,--no-warn-symbol-ordering
per eliminare questi avvisi.
build-ndk
LOCAL_CFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
LOCAL_LDFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
Marca
target_compile_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
target_link_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
Altri sistemi di build
Compila il codice utilizzando -Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
.
Per ulteriori informazioni, consulta l'esempio del file di ordine.
Dettagli implementazione file ordine
Esistono molti modi per generare file di ordine e utilizzarli per la creazione. L'NDK utilizza il metodo di LLVM, rendendolo quindi il più utile per le librerie condivise C o C++ rispetto all'app Java o Kotlin effettiva. Clang prende ogni nome di funzione (simbolo) e ne crea un hash MD5 e restituisce questa relazione a un file di mapping. L'hash MD5 di una funzione viene scritto nel file del profilo (formato profraw) quando la funzione viene eseguita per la prima volta. Eventuali esecuzioni successive della funzione non scrivono l'hash MD5 nel file del profilo perché intende evitare duplicati. Di conseguenza, nell'ordine viene registrata solo la prima esecuzione della funzione. Esaminando il file del profilo e di mapping, puoi prendere ogni hash MD5 e sostituirlo con la funzione corrispondente e ottenere un file di ordine.
Esempi di file di profilo in formato esadecimale e file di mapping sono disponibili rispettivamente come example.prof e example-mapping.txt.