Profil Kılavuzlu Optimizasyon

Profil odaklı optimizasyon (PGO), iyi bilinen bir derleyici optimizasyon tekniğidir. PGO'da, derleyici tarafından satır içi yapma ve kod düzeniyle ilgili en uygun seçimleri yapmak için programın yürütme işlemlerindeki çalışma zamanı profilleri kullanılır. Bu da performansın artmasını ve kod boyutunun küçülmesini sağlar.

PGO, uygulamanıza veya kitaplığınıza aşağıdaki adımlarla dağıtılabilir: 1. Temsil edici bir iş yükü belirleyin. 2. Profilleri toplayın. 3. Profilleri bir yayın derlemesinde kullanın.

1. Adım: Temsilci bir iş yükü belirleyin

Öncelikle, uygulamanız için temsili bir karşılaştırma veya iş yükü belirleyin. İş yükünden toplanan profiller koddaki yoğun ve az kullanılan bölgeleri tanımladığından bu adım kritik öneme sahiptir. Derleyici, profilleri kullanırken yoğun kullanılan bölgelerde agresif optimizasyonlar ve satır içi yerleştirme yapar. Derleyici, performanstan ödün vererek kullanılmayan bölgelerin kod boyutunu azaltmayı da seçebilir.

İyi bir iş yükünü belirlemek, genel performansı takip etmek için de yararlıdır.

2. Adım: Profilleri toplayın

Profil toplama işlemi üç adımdan oluşur: - enstrümantasyonlu yerel kod oluşturma, - araçlı uygulamayı cihazda çalıştırma ve profil oluşturma ve - ana makinede profilleri birleştirme/son işleme.

Enstrümante Edilmiş Derleme Oluşturma

Profiller, 1. adımdaki iş yükünün uygulamanın enstrümante edilmiş bir derlemesinde çalıştırılmasıyla toplanır. Enstrümante edilmiş bir derleme oluşturmak için derleyici ve bağlayıcı işaretlerine -fprofile-generate ekleyin. Varsayılan derleme sırasında bu işarete ihtiyaç duyulmadığı için ayrı bir derleme değişkeni tarafından kontrol edilmelidir.

Profil Oluşturma

Ardından, enstrümante edilmiş uygulamayı cihazda çalıştırın ve profiller oluşturun. Profiller, enstrümante edilmiş ikili çalıştırıldığında bellekte toplanır ve çıkışta bir dosyaya yazılır. Ancak, atexit işlevine kaydedilen işlevler bir Android uygulamasında çağrılmaz. Uygulama hemen kapatılır.

Uygulamanın/iş yükünün, profil dosyası için bir yol belirlemek ve ardından profil yazma işlemini açıkça tetiklemek üzere ek işlem yapması gerekir.

  • Profil dosyası yolunu ayarlamak için __llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw yöntemini çağırın. %m, birden fazla paylaşılan kitaplık olduğunda kullanışlıdır. %m, ilgili kitaplık için benzersiz bir modül imzasına genişler. Böylece her kitaplık için ayrı bir profil oluşturulur. Diğer yararlı kalıp belirteçleri için buraya göz atın. PROFILE_DIR, uygulamadan yazılabilen bir dizindir. Bu dizini çalışma zamanında algılamak için demo bölümüne bakın.
  • Profil yazma işlemini açıkça tetiklemek için __llvm_profile_write_file işlevini çağırın.
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;
}

Not: İş yükü bağımsız bir ikili dosyaysa profil dosyasını oluşturmak daha kolaydır. İkili dosyayı çalıştırmadan önce LLVM_PROFILE_FILE ortam değişkenini %t/default-%m.profraw olarak ayarlayın.

İşlem Sonrası Profilleri

Profil dosyaları .profraw biçimindedir. Öncelikle adb pull kullanılarak cihazdan getirilmeleri gerekir. Getirme işleminden sonra, .profraw'dan .profdata'e dönüştürmek için NDK'daki llvm-profdata yardımcı programını kullanın. Bu, derleyiciye iletilebilir.

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

Profil dosyası biçimlerinin sürüm uyuşmazlığını önlemek için aynı NDK sürümünden llvm-profdata ve clang kullanın.

3. Adım Uygulama Oluşturmak İçin Profilleri Kullanma

Derleyiciye ve bağlayıcıya -fprofile-use=<>.profdata'ü ileterek uygulamanızın sürüm derlemesi sırasında önceki adımdaki profili kullanın. Profiller, kod geliştikçe bile kullanılabilir. Clang derleyicisi, kaynak ve profiller arasındaki küçük uyuşmazlıklara tolerans gösterebilir.

Not: Genel olarak, çoğu kitaplıkta profiller mimariler arasında ortaktır. Örneğin, kitaplığın arm64 derlemesinden oluşturulan profiller tüm mimariler için kullanılabilir. Bununla birlikte, kitaplıkta mimariye özel kod yolları varsa (arm ve x86 veya 32 bit ve 64 bit) bu tür her yapılandırma için ayrı profiller kullanılmalıdır.

Özet

https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo, PGO'yu bir uygulamadan kullanmayla ilgili uçtan uca bir demo gösterir. Bu dokümanda gözden geçirilmeyen ek ayrıntılar sağlanır.

  • CMake derleme kuralları, enstrümantasyonla yerel kod oluşturan bir CMake değişkeninin nasıl ayarlanacağını gösterir. Derleme değişkeni ayarlanmadığında yerel kod, daha önce oluşturulmuş PGO profilleri kullanılarak optimize edilir.
  • Araçlı bir derlemede pgodemo.cpp, profillerin iş yükü yürütme olduğunu yazar.
  • MainActivity.kt'de çalışma zamanında applicationContext.cacheDir.toString() kullanılarak profiller için yazılabilir bir konum elde edilir.
  • adb root gerektirmeden cihazdan profil almak için adb tarifini burada kullanın.