Sistem izlemeyi yapılandırın

Sistem izlemeyi, uygulamanızın CPU ve iş parçacığı profilini kısa süreli olarak kaydedecek şekilde yapılandırabilirsiniz. Ardından, oyununuzun performansını iyileştirmek için bir sistem izlemesinden alınan çıkış raporunu kullanabilirsiniz.

Oyun tabanlı sistem izleme oluşturma

Systrace aracı iki şekilde kullanılabilir:

Systrace, aşağıdaki işlemleri yapan alt düzey bir araçtır:

  • Kesin referans sağlar. Systrace, çıktıları doğrudan çekirdekten yakalar. Böylece yakaladığı metrikler, bir dizi sistem çağrısının raporladığı metriklerle neredeyse aynıdır.
  • Az sayıda kaynak tüketir. Systrace, bellek içi arabelleğe veri akışı sağladığından cihazda genellikle %1'den az bir ek yüke neden olur.

Optimum ayarlar

Araca makul bir argüman dizisi sağlamanız önemlidir:

  • Kategoriler: Oyun tabanlı bir sistem izleme için etkinleştirilecek en iyi kategori grubu şunlardır: {sched, freq, idle, am, wm, gfx, view, sync, binder_driver, hal, dalvik}.
  • Arabellek boyutu: Genel bir kural olarak CPU çekirdeği başına 10 MB'lık bir arabellek boyutu, yaklaşık 20 saniye uzunluğunda bir iz için izin verilmesidir. Örneğin, bir cihazın iki dört çekirdekli CPU'su (toplam 8 çekirdek) varsa systrace programına geçirmek için uygun değer 80.000 KB (80 MB) olur.

    Oyununuz bağlam açısından çok fazla geçiş yapıyorsa arabelleği CPU çekirdeği başına 15 MB'a yükseltin.

  • Özel etkinlikler: Oyununuzda yakalanacak özel etkinlikler tanımlarsanız Systrace'in bu özel etkinlikleri çıkış raporuna dahil etmesini sağlayan -a işaretini etkinleştirin.

systrace komut satırı programını kullanıyorsanız kategori grubu, arabellek boyutu ve özel etkinlikler için en iyi uygulamalardan yararlanan bir sistem izlemesi yakalamak amacıyla aşağıdaki komutu kullanın:

python systrace.py -a com.example.myapp -b 80000 -o my_systrace_report.html \
  sched freq idle am wm gfx view sync binder_driver hal dalvik

Systrace sistem uygulamasını bir cihazda kullanıyorsanız kategori grubu, arabellek boyutu ve özel etkinlikler için en iyi uygulamalardan yararlanan bir sistem izlemesi yakalamak üzere aşağıdaki adımları uygulayın:

  1. Hata ayıklaması yapılabilecek uygulamaları izle seçeneğini etkinleştirin.

    Bu ayarı kullanmak için cihazda 256 MB veya 512 MB kullanılabilir alan (CPU'nun 4 ya da 8 çekirdekli olmasına bağlı olarak) ve 64 MB'lık her bir bellek parçasının bitişik parça halinde mevcut olması gerekir.

  2. Kategoriler'i seçin ve ardından aşağıdaki listede yer alan kategorileri etkinleştirin:

    • am: Etkinlik Yöneticisi
    • binder_driver: Bağlayıcı Çekirdek sürücüsü
    • dalvik: Dalvik Sanal Makinesi
    • freq: CPU Frekansı
    • gfx: Grafikler
    • hal: Donanım Modülleri
    • idle: CPU Boşta
    • sched: CPU Planlama
    • sync: Senkronizasyon
    • view: Sistemi Göster
    • wm: Pencere Yöneticisi
  3. Kayıt izleme'yi etkinleştirin.

  4. Oyununuzu yükleyin.

  5. Oyununuzda, cihaz performansını ölçmek istediğiniz oyuna karşılık gelen etkileşimleri gerçekleştirin.

  6. Oyununuzda istenmeyen davranışlarla karşılaştıktan kısa bir süre sonra sistem izlemeyi kapatın.

Sorunu daha ayrıntılı analiz etmek için gereken performans istatistiklerini topladınız.

Cihaz üzerindeki sistem izleri, disk alanından tasarruf etmek için dosyaları sıkıştırılmış iz biçiminde (*.ctrace) kaydeder. Rapor oluştururken bu dosyayı açmak için komut satırı programını kullanın ve --from-file seçeneğini ekleyin:

python systrace.py --from-file=/data/local/traces/my_game_trace.ctrace \
  -o my_systrace_report.html

Belirli performans alanlarını iyileştirme

Bu bölümde mobil oyunlarda performansla ilgili bazı yaygın endişeler vurgulanmakta ve oyununuzun bu yönlerini nasıl tanımlayıp iyileştireceğiniz açıklanmaktadır.

Yükleme hızı

Oyuncular oyununuzun aksiyonuna mümkün olduğunca çabuk girmek isterler. Bu nedenle, oyununuzun yükleme sürelerini mümkün olduğunca iyileştirmek önemlidir. Aşağıdaki önlemler genellikle yükleme sürelerine yardımcı olur:

  • Geç yükleme işlemi gerçekleştirin. Oyununuzda ardışık sahnelerde veya seviyelerde aynı öğeleri kullanıyorsanız bu öğeleri yalnızca bir kez yükleyin.
  • Öğelerinizin boyutunu küçültün. Bu şekilde, bu öğelerin sıkıştırılmamış sürümlerini oyununuzun APK'sıyla gruplandırabilirsiniz.
  • Disk verimliliği yüksek bir sıkıştırma yöntemi kullanın. Bu tür bir yönteme örnek olarak zlib verilebilir.
  • mono yerine IL2CPP kullanın. (Yalnızca Unity kullanıyorsanız geçerlidir.) IL2CPP, C# komut dosyalarınız için daha iyi yürütme performansı sağlar.
  • Oyununuzu çok iş parçacıklı hale getirin. Daha ayrıntılı bilgi için kare hızı tutarlılığı bölümünü inceleyin.

Kare hızı tutarlılığı

Oyun deneyiminin en önemli unsurlarından biri tutarlı bir kare hızı elde etmektir. Bu hedefe daha kolay ulaşmak için, bu bölümde açıklanan optimizasyon tekniklerini izleyin.

Çoklu iş parçacığı işleme

Birden fazla platform için geliştirme yaparken oyununuzdaki tüm etkinliği tek bir iş parçacığına yerleştirmek doğaldır. Bu yürütme yöntemi, birçok oyun motorunda kolayca uygulanabilecek olsa da Android cihazlarda çalışırken ideal değildir. Bu nedenle, tek iş parçacıklı oyunlar genellikle yavaş yüklenir ve tutarlı bir kare hızına sahip olmaz.

Şekil 1'de gösterilen Sistem, aynı anda yalnızca bir CPU ile çalışan oyunların tipik bir davranışıdır:

Bir sistem izlemedeki
iş parçacıklarının diyagramı

Şekil 1. Tek iş parçacıklı oyun için Systrace raporu

Oyununuzun performansını iyileştirmek için oyununuzu çoklu iş parçacıklı hale getirin. Genellikle en iyi model 2 iş parçacığıdır:

  • Oyununuzun ana modüllerini içeren ve oluşturma komutları gönderen bir oyun ileti dizisi.
  • Oluşturma komutlarını alan ve bunları cihaz GPU'sunun bir sahneyi görüntülemek için kullanabileceği grafik komutlarına çeviren bir render iş parçacığı.

Vulkan API, 2 ortak arabelleği paralel olarak iletme yeteneği sayesinde bu modelin kapsamını genişletiyor. Bu özelliği kullanarak, birden fazla oluşturma iş parçacığını birden çok CPU'ya dağıtabilir, böylece sahnenin oluşturma süresini daha da iyileştirebilirsiniz.

Oyununuzun çoklu iş parçacığı performansını artırmak için motora özel bazı değişiklikler de yapabilirsiniz:

  • Oyununuzu Unity oyun motorunu kullanarak geliştiriyorsanız Çok İş parçacıklı Oluşturma ve GPU Dış Kapatma seçeneklerini etkinleştirin.
  • Özel bir oluşturma motoru kullanıyorsanız oluşturma komut ardışık düzeni ile grafik komut ardışık düzeninin doğru bir şekilde hizalandığından emin olun. Aksi takdirde, oyununuzun sahnelerinin görüntülenmesinde gecikmelere neden olabilirsiniz.

Bu değişiklikleri uyguladıktan sonra, oyununuzun Şekil 2'de gösterildiği gibi aynı anda en az 2 CPU'yu işgal ettiğini görürsünüz:

Bir sistem izlemedeki
iş parçacıklarının diyagramı

Şekil 2. Çok iş parçacıklı oyun için Systrace raporu

Kullanıcı arayüzü öğesi yükleniyor

Bir sistem izlemesi içindeki çerçeve yığınının şeması
Şekil 3. Düzinelerce kullanıcı arayüzü öğesini aynı anda oluşturan bir oyunun sistem raporu

Zengin özelliklere sahip bir oyun oluştururken oyuncuya aynı anda birçok farklı seçenek ve işlem göstermek cazip gelebilir. Bununla birlikte, tutarlı bir kare hızını korumak için mobil ekranların nispeten küçük boyutunu göz önünde bulundurmak ve kullanıcı arayüzünüzü mümkün olduğunca basit tutmak önemlidir.

Şekil 3'te gösterilen Sistem raporu, bir mobil cihazın özelliklerine bağlı olarak çok fazla öğe oluşturmaya çalışan bir kullanıcı arayüzü çerçevesine örnektir.

Kullanıcı arayüzü güncelleme süresini 2-3 milisaniyeye düşürmek iyi bir hedeftir. Aşağıdakine benzer optimizasyonlar gerçekleştirerek bu tür hızlı güncellemelere ulaşabilirsiniz:

  • Yalnızca ekrandaki taşınan öğeleri güncelleyin.
  • Kullanıcı arayüzü dokularının ve katmanlarının sayısını sınırlayın. Aynı malzemeyi kullanan grafik çağrılarını (ör. gölgelendiriciler ve dokular) birleştirmeyi düşünün.
  • Öğe animasyonu işlemlerini GPU'ya erteleyin.
  • Daha agresif kesik atma ve tıkanıklık giderme işlemleri gerçekleştirmek.
  • Mümkünse Vulkan API'sini kullanarak çizim işlemleri gerçekleştirin. Çekim çağrısının yükü Vulkan'da daha düşüktür.

Güç tüketimi

Önceki bölümde bahsettiğimiz optimizasyonları yaptıktan sonra bile oyununuzun kare hızının ilk 45-50 dakika içinde düştüğünü görebilirsiniz. Ayrıca, cihaz zamanla ısınmaya ve daha fazla pil tüketmeye başlayabilir.

Çoğu durumda, bu istenmeyen termal veri grubu ve güç tüketimi, oyununuzun iş yükünün cihazların CPU'larına nasıl dağıtıldığıyla ilgilidir. Oyununuzun güç tüketimi verimliliğini artırmak için aşağıdaki bölümlerde gösterilen en iyi uygulamaları uygulayın.

Yoğun bellek kullanan ileti dizilerini tek bir CPU'da tutma

Birçok mobil cihazda, L1 önbellekleri belirli CPU'larda, L2 önbellekleri ise aynı saati paylaşan CPU kümesinde bulunur. L1 önbellek isabetlerini en üst düzeye çıkarmak için genellikle en iyi yöntem oyununuzun ana iş parçacığını, belleği ağırlıklı diğer iş parçacıklarıyla birlikte tek bir CPU'da çalıştırmaktır.

Kısa süreli işleri düşük güçlü CPU'lara erteleyin

Unity dahil olmak üzere çoğu oyun motorunun, çalışan iş parçacığı işlemlerini oyununuzun ana iş parçacığına göre farklı bir CPU'ya ertelemesini bilir. Ancak motor, cihazın özel mimarisinin farkında değildir ve oyununuzun iş yükünü olabildiğince iyi tahmin edemez.

Çip üzerinde sistemdeki çoğu cihazın, biri cihazın hızlı CPU'ları ve diğeri cihazın yavaş CPU'ları için olmak üzere en az 2 paylaşılan saati vardır. Bu mimarinin sonucu, hızlı bir CPU'nun maksimum hızda çalışması gerektiğinde diğer tüm hızlı CPU'ların da maksimum hızda çalışmasıdır.

Şekil 4'te gösterilen örnek rapor, hızlı CPU'lardan yararlanan bir oyunu göstermektedir. Ancak bu yüksek etkinlik seviyesi, hızlı bir şekilde yüksek miktarda güç ve ısı üretir.

Bir sistem izlemedeki
iş parçacıklarının diyagramı

Şekil 4. İş parçacıklarının cihazın CPU'larına optimum olmayan şekilde atanmasını gösteren sistem raporu

Genel güç kullanımını azaltmak için planlayıcıya ses yükleme, çalışan iş parçacıklarını çalıştırma ve koreografı yürütme gibi daha kısa süreli çalışmaların cihazdaki yavaş CPU'ya göre ertelenmesini önermek en iyisidir. İstenen kare hızını korurken bu işin tamamını yavaş CPU'lara aktarın.

Çoğu cihaz, yavaş CPU'ları hızlı CPU'lardan önce listeler, ancak cihazınızın SOC'sinin bu sırayı kullandığını varsayamazsınız. Kontrol etmek için GitHub'daki bu CPU topoloji keşif kodunda gösterilenlere benzer komutları çalıştırın.

Cihazınızdaki yavaş CPU'ları öğrendikten sonra kısa süreli iş parçacıklarınız için yakın ilgi alanlarını bildirebilirsiniz. Cihaz planlayıcısının buna uyması gerekir. Bunu yapmak için her ileti dizisine aşağıdaki kodu ekleyin:

#include <sched.h>
#include <sys/types.h>
#include <unistd.h>

pid_t my_pid; // PID of the process containing your thread.

// Assumes that cpu0, cpu1, cpu2, and cpu3 are the "slow CPUs".
cpu_set_t my_cpu_set;
CPU_ZERO(&my_cpu_set);
CPU_SET(0, &my_cpu_set);
CPU_SET(1, &my_cpu_set);
CPU_SET(2, &my_cpu_set);
CPU_SET(3, &my_cpu_set);
sched_setaffinity(my_pid, sizeof(cpu_set_t), &my_cpu_set);

Termal stres

Cihazlar aşırı ısındığında CPU ve/veya GPU'yu kısıtlayabilirler. Bu da oyunları beklenmedik şekillerde etkileyebilir. Karmaşık grafikler, yoğun hesaplamalar veya sürekli ağ etkinliği içeren oyunlarda sorunlarla karşılaşma olasılığı daha yüksektir.

Cihazdaki sıcaklık değişikliklerini izlemek ve güç kullanımını düşürüp cihaz sıcaklığını düşük tutmak için gerekli işlemleri yapmak üzere termal API'yi kullanın. Cihaz termal stres bildirdiğinde, güç kullanımını azaltmak için devam eden etkinlikleri geri alabilirsiniz. Örneğin, kare hızını veya poligon mozaiklemesini azaltın.

İlk olarak PowerManager nesnesini tanımlayın ve onCreate() yönteminde başlatın. Nesneye bir termal durum işleyicisi ekleyin.

Kotlin

class MainActivity : AppCompatActivity() {
    lateinit var powerManager: PowerManager

    override fun onCreate(savedInstanceState: Bundle?) {
        powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
        powerManager.addThermalStatusListener(thermalListener)
    }
}

Java

public class MainActivity extends AppCompatActivity {
    PowerManager powerManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        powerManager.addThermalStatusListener(thermalListener);
    }
}

Dinleyici bir durum değişikliği algıladığında yapılacak işlemleri tanımlayın. Oyununuzda C/C++ kullanılıyorsa JNI kullanarak yerel oyun kodunuzu çağırmak veya yerel Thermal API'yi kullanmak için onThermalStatusChanged() içindeki termal durum seviyelerine kod ekleyin.

Kotlin

val thermalListener = object : PowerManager.OnThermalStatusChangedListener() {
    override fun onThermalStatusChanged(status: Int) {
        when (status) {
            PowerManager.THERMAL_STATUS_NONE -> {
                // No thermal status, so no action necessary
            }

            PowerManager.THERMAL_STATUS_LIGHT -> {
                // Add code to handle light thermal increase
            }

            PowerManager.THERMAL_STATUS_MODERATE -> {
                // Add code to handle moderate thermal increase
            }

            PowerManager.THERMAL_STATUS_SEVERE -> {
                // Add code to handle severe thermal increase
            }

            PowerManager.THERMAL_STATUS_CRITICAL -> {
                // Add code to handle critical thermal increase
            }

            PowerManager.THERMAL_STATUS_EMERGENCY -> {
                // Add code to handle emergency thermal increase
            }

            PowerManager.THERMAL_STATUS_SHUTDOWN -> {
                // Add code to handle immediate shutdown
            }
        }
    }
}

Java

PowerManager.OnThermalStatusChangedListener thermalListener =
    new PowerManager.OnThermalStatusChangedListener () {

    @Override
    public void onThermalStatusChanged(int status) {

        switch (status)
        {
            case PowerManager.THERMAL_STATUS_NONE:
                // No thermal status, so no action necessary
                break;

            case PowerManager.THERMAL_STATUS_LIGHT:
                // Add code to handle light thermal increase
                break;

            case PowerManager.THERMAL_STATUS_MODERATE:
                // Add code to handle moderate thermal increase
                break;

            case PowerManager.THERMAL_STATUS_SEVERE:
                // Add code to handle severe thermal increase
                break;

            case PowerManager.THERMAL_STATUS_CRITICAL:
                // Add code to handle critical thermal increase
                break;

            case PowerManager.THERMAL_STATUS_EMERGENCY:
                // Add code to handle emergency thermal increase
                break;

            case PowerManager.THERMAL_STATUS_SHUTDOWN:
                // Add code to handle immediate shutdown
                break;
        }
    }
};

Dokunmadan ekran gecikmesi

Kareleri mümkün olduğunca hızlı oluşturan oyunlar, kare arabelleğinin fazla dolduğu GPU'ya bağlı bir senaryo oluşturur. CPU'nun GPU'yu beklemesi gerekir. Bu da, oynatıcının girişi ile girişin ekranda etkili olması arasında fark edilebilir bir gecikmeye neden olur.

Oyununuzun kare hızını artırıp iyileştiremeyeceğinizi belirlemek için aşağıdaki adımları uygulayın:

  1. gfx ve input kategorilerini içeren bir Systrace raporu oluşturun. Bu kategoriler, özellikle dokunma-görüntüleme gecikmesini belirlemek için yararlı ölçümler içerir.
  2. Systrace raporunun SurfaceView bölümünü inceleyin. Fazla dolu bir tampon, Şekil 5'te gösterildiği gibi beklemedeki tampon sayısının 1 ile 2 arasında salınmasına neden olur:

    Sistem izleme içindeki arabellek sırası şeması

    Şekil 5. Düzenli aralıklarla çizim komutlarını kabul edemeyecek kadar dolu olan bir arabelleğin aşırı doldurulduğunu gösteren sistem raporu

Kare hızındaki bu tutarsızlığı azaltmak için aşağıdaki bölümlerde açıklanan işlemleri tamamlayın:

Android Frame Pacing API'sini oyununuza entegre edin

Android Frame Pacing API'si, oyununuzun daha tutarlı bir kare hızı elde etmesi için kare değiştirme işlemleri gerçekleştirmenize ve bir değiştirme aralığı tanımlamanıza yardımcı olur.

Oyununuzun kullanıcı arayüzü olmayan öğelerinin çözünürlüğünü azaltın

Modern mobil cihazlardaki ekranlar, bir oynatıcının işleyebileceğinden çok daha fazla piksel içerir. Bu nedenle, 5 veya 10 piksellik bir çalışmanın tamamı tek bir renk içerecek şekilde küçültülebilir. Çoğu ekran önbelleğinin yapısı göz önünde bulundurulduğunda en iyi yöntem, çözünürlüğü yalnızca tek bir boyutta düşürmektir.

Ancak oyununuzun kullanıcı arayüzü öğelerinin çözünürlüğünü azaltmayın. Tüm oyuncularınız için yeterince büyük bir dokunma hedefi boyutu korumak amacıyla bu öğelerdeki çizgi kalınlığını korumak önemlidir.

Sorunsuz oluşturma

SurfaceFlinger, oyununuzdaki bir sahneyi göstermek için ekran arabelleğine kilitlendiğinde CPU etkinliği anlık olarak artar. CPU etkinliğindeki bu artışlar eşit olmayan şekilde gerçekleşiyorsa oyununuzda takılmalar görülebilir. Şekil 6'daki diyagramda bunun nedeni gösterilmiştir:

Çizime çok geç başladığı için
bir Vsync penceresi olmayan karelerin şeması

Şekil 6. Bir karenin Vsync'i nasıl kaçırabileceğini gösteren sistem raporu

Bir kare, çizime çok geç başlarsa, hatta birkaç milisaniye geçse bile sonraki görüntüleme penceresi kaçırılabilir. Bu durumda karenin, bir sonraki Vsync'in gösterilmesi için (30 FPS'de bir oyun çalıştırılırken 33 milisaniye) beklemesi gerekir. Bu, oyuncunun bakış açısından fark edilebilir bir gecikmeye neden olur.

Bu durumu çözmek için VSync dalga önünde her zaman yeni bir kare sunan Android Frame Pacing API'sini kullanın.

Bellek durumu

Oyununuzu uzun süre çalıştırdığınızda cihazın bellek yetersiz hataları oluşabilir.

Bu durumda, bir Systrace raporundaki CPU etkinliğini kontrol edin ve sistemin kswapd arka plan programına ne sıklıkta çağrı yaptığını görün. Oyununuz yürütülürken çok sayıda çağrı varsa oyununuzun belleği nasıl yönettiğini ve temizlediğini daha yakından incelemek en iyisidir.

Daha fazla bilgi için Oyunlarda belleği etkili bir şekilde yönetme başlıklı makaleye göz atın.

İleti dizisi durumu

Bir Sistem raporunun tipik öğelerinde gezinirken, Şekil 7'de gösterildiği gibi rapor içindeki ileti dizisini seçerek belirli bir iş parçacığının olası her bir iş parçacığı durumunda harcadığı süreyi görüntüleyebilirsiniz:

Systrace raporunun şeması

Şekil 7. Bir ileti dizisi seçildiğinde raporun bu ileti dizisi için durum özetini nasıl gösterdiğini gösteren sistem raporu

Şekil 7'de gösterildiği gibi, oyununuzun ileti dizilerinin "çalışıyor" veya "çalıştırılabilir" durumunda olması gerektiği kadar sık olmadığını görebilirsiniz. Aşağıdaki listede, belirli bir iş parçacığının düzenli olarak olağan dışı bir duruma geçmesinin birkaç yaygın nedeni gösterilmektedir:

  • Bir iş parçacığı uzun süre uyuyorsa kilit anlaşmazlığından veya GPU etkinliğini bekliyor olabilir.
  • Bir iş parçacığı G/Ç'de sürekli olarak engellenirse ya bir defada diskten çok fazla veri okuyorsunuzdur ya da oyununuz aşırı yoğunlaşıyordur.

Ek kaynaklar

Oyununuzun performansını artırma hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynakları inceleyin:

Videolar