Systrace'i Anlamak

systrace, Android cihaz performansını analiz etmek için birincil araçtır. Ancak, gerçekten diğer araçların etrafını sarar. Bu, atrace etrafındaki ana bilgisayar tarafı sarmalayıcı, kullanıcı alanı izlemeyi kontrol eden ve ftrace ayarını yapan aygıt tarafında yürütülebilir dosya ve Linux çekirdeğindeki birincil izleme mekanizmasıdır. systrace, izlemeyi etkinleştirmek için atrace kullanır, ardından ftrace arabelleğini okur ve hepsini bağımsız bir HTML görüntüleyicide sarar. (Daha yeni çekirdekler Linux Gelişmiş Berkeley Paket Filtresi (eBPF) desteğine sahip olsa da, aşağıdaki belgeler Pixel/Pixel XL'de kullanılan 3.18 çekirdeğe (eFPF yok) ilişkindir.)

systrace, Google Android ve Google Chrome ekiplerine aittir ve Catapult projesinin bir parçası olarak açık kaynak kodludur. Systrace'e ek olarak, Catapult diğer faydalı yardımcı programları içerir. Örneğin, ftrace, systrace veya atrace tarafından doğrudan etkinleştirilebilenden daha fazla özelliğe sahiptir ve performans sorunlarının ayıklanması için kritik olan bazı gelişmiş işlevler içerir. (Bu özellikler kök erişimi ve genellikle yeni bir çekirdek gerektirir.)

Koşu sistemi

Pixel/Pixel XL'de jitter hatalarını ayıklarken aşağıdaki komutla başlayın:

./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000

GPU ve görüntü hattı etkinliği için gereken ek izleme noktaları ile birleştirildiğinde, bu size kullanıcı girişinden ekranda görüntülenen çerçeveye kadar izleme yeteneği verir. Olayları kaybetmemek için arabellek boyutunu büyük bir değere ayarlayın (çünkü büyük bir arabellek olmadan bazı CPU'lar izlemenin bir noktasından sonra hiçbir olay içermez).

Systrace'den geçerken, her olayın CPU'daki bir şey tarafından tetiklendiğini unutmayın.

Systrace, ftrace üzerine kurulu olduğundan ve ftrace CPU üzerinde çalıştığından, CPU'daki bir şey, donanım değişikliklerini kaydeden ftrace arabelleğini yazmalıdır. Bu, bir ekran çitinin neden durumunu değiştirdiğini merak ediyorsanız, geçişinin tam noktasında CPU'da neyin çalıştığını görebileceğiniz anlamına gelir (CPU üzerinde çalışan bir şey, günlükte bu değişikliği tetikledi). Bu kavram, systrace kullanarak performansı analiz etmenin temelidir.

Örnek: Çalışma çerçevesi

Bu örnek, normal bir UI ardışık düzeni için bir sistemi açıklar. Örneği takip etmek için, izlemelerin zip dosyasını (bu bölümde bahsedilen diğer izleri de içerir) indirin, dosyayı açın ve systrace_tutorial.html dosyasını tarayıcınızda açın. Bu systrace'in büyük bir dosya olduğu konusunda uyarılmalıdır; systrace'i günlük işlerinizde kullanmıyorsanız, bu muhtemelen daha önce tek bir izde gördüğünüzden çok daha fazla bilgi içeren çok daha büyük bir izdir.

TouchLatency gibi tutarlı, periyodik bir iş yükü için UI ardışık düzeni aşağıdakileri içerir:

  1. SurfaceFlinger'daki EventThread, uygulama UI iş parçacığını uyandırarak yeni bir çerçeve oluşturma zamanının geldiğini bildirir.
  2. Uygulama, CPU ve GPU kaynaklarını kullanarak UI iş parçacığı, RenderThread ve hwuiTasks'ta bir çerçeve oluşturur. Bu, kullanıcı arayüzü için harcanan kapasitenin büyük kısmıdır.
  3. Uygulama, oluşturulan çerçeveyi bir bağlayıcı kullanarak SurfaceFlinger'a gönderir, ardından SurfaceFlinger uyku moduna geçer.
  4. SurfaceFlinger'daki ikinci bir EventThread, kompozisyonu tetiklemek ve çıktıyı görüntülemek için SurfaceFlinger'ı uyandırır. SurfaceFlinger yapılacak bir iş olmadığını belirlerse tekrar uyku moduna geçer.
  5. SurfaceFlinger, Donanım Oluşturucu (HWC)/Donanım Oluşturucu 2 (HWC2) veya GL kullanarak kompozisyonu işler. HWC/HWC2 bileşimi daha hızlıdır ve daha düşük güçtür ancak bir çip (SoC) üzerindeki sisteme bağlı olarak sınırlamaları vardır. Bu genellikle ~4-6 ms sürer, ancak Android uygulamaları her zaman üçlü arabelleğe alındığından 2. adımla çakışabilir. (Uygulamalar her zaman üçlü arabelleğe alınırken, SurfaceFlinger'da bekleyen yalnızca bir bekleyen çerçeve olabilir, bu da çift arabelleğe alma ile aynı görünmesini sağlar.)
  6. SurfaceFlinger, satıcı sürücüsüyle görüntülenmesi için son çıktıyı gönderir ve EventThread uyanmasını bekleyerek uyku moduna geri döner.

15409 ms'den başlayan çerçeveden geçelim:

EventThread çalışan normal UI ardışık düzeni
Şekil 1. Normal UI ardışık düzeni, EventThread çalışıyor

Şekil 1, normal çerçevelerle çevrelenmiş normal bir çerçevedir, bu nedenle, UI ardışık düzeninin nasıl çalıştığını anlamak için iyi bir başlangıç ​​noktasıdır. TouchLatency için UI iş parçacığı satırı, farklı zamanlarda farklı renkler içerir. Çubuklar, iş parçacığı için farklı durumları belirtir:

  • gri . Uyuyor.
  • Mavi. Çalıştırılabilir (çalışabilir, ancak zamanlayıcı henüz çalıştırmayı seçmedi).
  • Yeşil. Aktif olarak çalışıyor (zamanlayıcı çalıştığını düşünüyor).
  • Kırmızı. Kesintisiz uyku (genellikle çekirdekte bir kilit üzerinde uyuma). G/Ç yükünün göstergesi olabilir. Performans sorunlarını ayıklamak için son derece yararlıdır.
  • Turuncu. G/Ç yükü nedeniyle kesintisiz uyku.

Kesintisiz uykunun nedenini görüntülemek için ( sched_blocked_reason izleme noktasından edinilebilir), kırmızı kesintisiz uyku dilimini seçin.

EventThread çalışırken, TouchLatency için UI iş parçacığı çalıştırılabilir hale gelir. Neyin uyandırdığını görmek için mavi bölüme tıklayın.

TouchLatency için UI iş parçacığı
Şekil 2. TouchLatency için UI iş parçacığı

Şekil 2, TouchLatency UI iş parçacığının EventThread'e karşılık gelen tid 6843 tarafından uyandırıldığını gösterir. UI iş parçacığı uyanır, bir çerçeve oluşturur ve SurfaceFlinger'ın tüketmesi için onu kuyruğa alır.

UI iş parçacığı uyanır, bir çerçeve oluşturur ve onu SurfaceFlinger'ın tüketmesi için sıkıştırır
Şekil 3. UI iş parçacığı uyanır, bir çerçeve oluşturur ve SurfaceFlinger'ın tüketmesi için onu kuyruğa alır

Bir binder_driver etiketi etkinleştirilmişse, o işlemle ilgili tüm işlemlerle ilgili bilgileri görüntülemek için bir bağlayıcı işlemi seçebilirsiniz.

Şekil 4. Bağlayıcı işlemi

Şekil 4, TouchLatency'nin RenderThread'i olan 9579 tid nedeniyle SurfaceFlinger'daki Binder:6832_1'in 15,423.65 ms'de çalıştırılabilir hale geldiğini göstermektedir. QueueBuffer'ı ciltleme işleminin her iki tarafında da görebilirsiniz.

SurfaceFlinger tarafında sıraBuffer sırasında, TouchLatency'den gelen bekleyen çerçevelerin sayısı 1'den 2'ye gider.

Bekleyen çerçeveler 1'den 2'ye gidiyor
Şekil 5. Bekleyen çerçeveler 1'den 2'ye gidiyor

Şekil 5, tamamlanmış iki çerçevenin olduğu ve uygulamanın üçüncü bir çerçeve oluşturmaya başlamak üzere olduğu üçlü arabelleğe almayı göstermektedir. Bunun nedeni, zaten bazı kareleri düşürmüş olmamızdır, bu nedenle uygulama, daha fazla atılan kareyi önlemek için bir yerine iki bekleyen kare tutar.

Kısa bir süre sonra, SurfaceFlinger'ın ana iş parçacığı ikinci bir EventThread tarafından uyandırılır, böylece eski bekleyen çerçeveyi ekrana yazdırabilir:

SurfaceFlinger'ın ana iş parçacığı ikinci bir EventThread tarafından uyandırıldı
Şekil 6. SurfaceFlinger'ın ana iş parçacığı ikinci bir EventThread tarafından uyandırılıyor

SurfaceFlinger önce eski bekleyen arabelleği kilitler, bu da bekleyen arabellek sayısının 2'den 1'e düşmesine neden olur.

SurfaceFlinger önce eski bekleyen arabelleğe kilitlenir
Şekil 7. SurfaceFlinger ilk önce bekleyen eski arabelleğe takılır

Tamponu kilitledikten sonra, SurfaceFlinger kompozisyonu kurar ve son kareyi ekrana gönderir. (Bu bölümlerden bazıları mdss izleme noktasının bir parçası olarak etkinleştirilmiştir, bu nedenle mdss dahil edilmeyebilirler.)

SurfaceFlinger kompozisyonu kurar ve son kareyi gönderir
Şekil 8. SurfaceFlinger kompozisyonu kurar ve son kareyi gönderir

Ardından, mdss_fb0 CPU 0'da uyanır. mdss_fb0 , ekrana işlenmiş bir çerçeve çıktısı vermek için görüntü ardışık düzeninin çekirdek iş parçacığıdır. mdss_fb0 kendi satırı olarak görebiliriz (aşağı kaydırarak görüntüleyin).

mdss_fb0 CPU 0'da uyanıyor
Şekil 9. mdss_fb0 CPU 0'da uyanıyor

mdss_fb0 uyanır, kısa süreliğine çalışır, kesintisiz uykuya geçer, sonra tekrar uyanır.

Örnek: Çalışmayan çerçeve

Bu örnek, Pixel/Pixel XL titremesinde hata ayıklamak için kullanılan bir sistemi açıklar. Örneği takip etmek için, izlemelerin zip dosyasını (bu bölümde bahsedilen diğer izleri içerir) indirin, dosyayı açın ve systrace_tutorial.html dosyasını tarayıcınızda açın.

Systrace'i açtığınızda, şöyle bir şey göreceksiniz:

Çoğu seçenek etkinken Pixel XL'de çalışan TouchLatency
Şekil 10. Pixel XL üzerinde çalışan TouchLatency (mdss ve kgsl izleme noktaları dahil çoğu seçenek etkin)

Jank ararken, SurfaceFlinger altındaki FrameMissed satırını kontrol edin. FrameMissed, HWC2 tarafından sağlanan bir yaşam kalitesi iyileştirmesidir. Diğer cihazlar için systrace görüntülerken, cihaz HWC2 kullanmıyorsa FrameMissed satırı mevcut olmayabilir. Her iki durumda da FrameMissed, SurfaceFlinger'ın son derece düzenli çalışma zamanlarından birinin eksik olması ve bir vsync'de uygulama için ( com.prefabulated.touchlatency ) değişmeyen bekleyen arabellek sayısı ile ilişkilidir.

SurfaceFlinger ile FrameMissed korelasyonu
Şekil 11. SurfaceFlinger ile FrameMissed korelasyonu

Şekil 11, 15598.29&nbps;ms'de kaçırılan bir çerçeveyi göstermektedir. SurfaceFlinger, vsync aralığında kısa bir süre uyandı ve herhangi bir iş yapmadan uykuya geri döndü; bu, SurfaceFlinger'ın ekrana yeniden bir çerçeve göndermeye çalışmaya değmeyeceğine karar verdiği anlamına geliyor. Neden? Niye?

Bu çerçeve için ardışık düzenin nasıl bozulduğunu anlamak için, systrace'de normal bir UI işlem hattının nasıl göründüğünü görmek için önce yukarıdaki çalışma çerçevesi örneğini inceleyin. Hazır olduğunuzda, kaçırılan kareye dönün ve geriye doğru çalışın. SurfaceFlinger'ın uyandığına ve hemen uykuya geçtiğine dikkat edin. TouchLatency'den bekleyen çerçevelerin sayısını görüntülerken, iki çerçeve vardır (neler olduğunu anlamaya yardımcı olacak iyi bir ipucu).

SurfaceFlinger uyanır ve hemen uykuya dalar
Şekil 12. SurfaceFlinger uyanır ve hemen uykuya dalar

SurfaceFlinger'da çerçevelerimiz olduğundan, bu bir uygulama sorunu değildir. Ayrıca, SurfaceFlinger doğru zamanda uyanıyor, yani bu bir SurfaceFlinger sorunu değil. SurfaceFlinger ve uygulama normal görünüyorsa, bu muhtemelen bir sürücü sorunudur.

mdss ve sync izleme noktaları etkinleştirildiğinden, çerçevelerin ekrana ne zaman gönderileceğini kontrol eden çitler (ekran sürücüsü ve SurfaceFlinger arasında paylaşılan) hakkında bilgi alabiliriz. Bu çitler, bir çerçevenin ekranda olduğunu gösteren mdss_fb0_retire altında listelenir. Bu çitler, sync izleme kategorisinin bir parçası olarak sağlanır. SurfaceFlinger'daki belirli olaylara karşılık gelen çitler, SOC ve sürücü yığınınıza bağlıdır, bu nedenle izlerinizdeki çit kategorilerinin anlamını anlamak için SOC satıcınızla birlikte çalışın.

mdss_fb0_emeklilik çitleri
Şekil 13. mdss_fb0_emekli çitler

Şekil 13, beklendiği gibi 16.7 ms değil, 33 ms için görüntülenen bir çerçeveyi göstermektedir. O dilimin yarısında, o çerçeve yenisiyle değiştirilmeliydi ama öyle değildi. Önceki kareyi görüntüleyin ve herhangi bir şey arayın.

Bozuk çerçeveden önceki çerçeve
Şekil 14. Bozuk çerçeveden önceki çerçeve

Şekil 14, 14.482 ms'lik bir çerçeveyi göstermektedir. Kırık iki kare segmenti 33,6 ms idi, bu kabaca iki kare için beklediğimiz şeydi (kare başına 60 Hz, 16,7 ms'de render yapıyoruz, bu yakın). Ancak 14.482 ms, 16.7 ms'ye hiç yakın değil, bu da görüntü hattında bir şeylerin çok yanlış olduğunu gösteriyor.

Onu neyin kontrol ettiğini belirlemek için çitin tam olarak nerede bittiğini araştırın.

Çit ucunu araştır
Şekil 15. Çit ucunu araştırın

Bir çalışma kuyruğu, çit değiştiğinde çalışan __vsync_retire_work_handler içerir. Çekirdek kaynağına baktığınızda, bunun ekran sürücüsünün bir parçası olduğunu görebilirsiniz. Görüntü hattı için kritik yolda görünüyor, bu nedenle mümkün olduğunca hızlı çalışması gerekiyor. Yaklaşık 70 kişi için çalıştırılabilir (uzun bir zamanlama gecikmesi değil), ancak bu bir çalışma kuyruğudur ve doğru şekilde planlanmayabilir.

Katkıda bulunup bulunmadığını belirlemek için önceki çerçeveyi kontrol edin; bazen dalgalanma zamanla birikebilir ve sonunda kaçırılan bir teslim tarihine neden olabilir.

Önceki kare
Şekil 16. Önceki kare

kworker'daki çalıştırılabilir satır, görüntüleyici seçildiğinde onu beyaza çevirdiği için görünmez, ancak istatistikler hikayeyi anlatır: Görüntü ardışık düzeni kritik yolunun bir kısmı için 2,3 ms zamanlayıcı gecikmesi kötü . Devam etmeden önce, görüntüleme ardışık düzeni kritik yolunun bu bölümünü bir çalışma kuyruğundan ( SCHED_OTHER CFS iş parçacığı olarak çalışır) özel bir SCHED_FIFO kthread'e taşıyarak gecikmeyi düzeltin. Bu işlev, çalışma sıralarının sağlayamadığı (ve amaçlamadığı) zamanlama garantilerine ihtiyaç duyar.

Sıçrayışın nedeni bu mu? Kesin olarak söylemek zor. Ekran açısından kritik iş parçacıklarının uyumasına neden olan çekirdek kilidi çekişmesi gibi teşhis edilmesi kolay durumların dışında, izlemeler genellikle sorunu belirtmez. Düşen çerçevenin nedeni bu titreme olabilir mi? Kesinlikle. Çit süreleri 16.7 ms olmalıdır, ancak bırakılan kareye giden karelerde buna hiç yakın değiller. Ekran boru hattının ne kadar sıkı bir şekilde bağlandığı göz önüne alındığında, çit zamanlamaları etrafındaki titreşimin çerçevenin düşmesine neden olması mümkündür.

Bu örnekte, çözüm, __vsync_retire_work_handler'ın bir çalışma kuyruğundan özel bir __vsync_retire_work_handler dönüştürülmesini içeriyordu. Bu, seken top testinde fark edilir titreşim iyileştirmeleri ve azaltılmış sarsıntı ile sonuçlandı. Sonraki izler, 16,7 ms'ye çok yakın olan çit zamanlamaları gösterir.