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:
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.
Kategoriler'i seçin ve ardından aşağıdaki listede yer alan kategorileri etkinleştirin:
am
: Etkinlik Yöneticisibinder_driver
: Bağlayıcı Çekirdek sürücüsüdalvik
: Dalvik Sanal Makinesifreq
: CPU Frekansıgfx
: Grafiklerhal
: Donanım Modülleriidle
: CPU Boştasched
: CPU Planlamasync
: Senkronizasyonview
: Sistemi Gösterwm
: Pencere Yöneticisi
Kayıt izleme'yi etkinleştirin.
Oyununuzu yükleyin.
Oyununuzda, cihaz performansını ölçmek istediğiniz oyuna karşılık gelen etkileşimleri gerçekleştirin.
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:
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:
Kullanıcı arayüzü öğesi yükleniyor
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.
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:
gfx
veinput
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.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:Ş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:
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:
Ş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
- Android Game Developer Summit 2018'de düzenlenen Systrace for Games sunumu