Genel olarak kodumu ne sıklıkla ve ne zaman optimize etmeliyim?


13

'Normal' iş programlama optimizasyon adımında gerçekten gerekli olana kadar bırakılır. Yani gerçekten gerekli olana kadar iyimser olmamalısınız.

Donald Knuth'un ne olduğunu hatırlayın "Zamanın yaklaşık% 97'sini küçük verimlilikleri unutmalıyız: erken optimizasyon tüm kötülüklerin köküdür"

Çaba harcamadığımdan emin olmak için ne zaman optimizasyon yapmalıyım? Bunu bir yöntem düzeyinde yapmalı mıyım? Sınıf seviyesi? Modül seviyesi?

Ayrıca optimizasyon ölçümüm ne yapmalı? Keneler? Kare hızı? Toplam zaman?

Yanıtlar:


18

Çalıştığım yerde, her zaman birden çok profil düzeyi kullanıyoruz; bir sorun görürseniz, neler olduğunu anlayana kadar listeyi biraz daha aşağı kaydırırsınız:

  • "İnsan profiler", aka sadece oyun oynamak ; yavaş veya “aksaklık” hissediyor mu? Sarsıntılı animasyonlar fark ettiniz mi? (Bir geliştirici olarak, bazı performans sorunlarına ve diğerlerine karşı daha duyarlı olacağınızı unutmayın. Buna göre ekstra testler planlayın.)
  • Kayar pencere 5 saniyelik ortalama FPS olan FPS ekranını açın . Hesaplamak ve görüntülemek için çok az ek yük.
  • Kodun her bölümü çevresinde basit bir "kronometre" zamanlayıcısı kullanarak çerçevenin farklı bölümlerini (ör. Vblank, preframe, güncelleme, çarpışma, oluşturma, postframe) temsil eden dörtlü bir dizi (ROYGBIV renkleri) olan profil çubuklarını açın . İstediğimizi vurgulamak için, bir ekran genişliği değerinin çubuğunu 60Hz hedef çerçeveyi temsil edecek şekilde ayarladık, bu nedenle örneğin bütçenin% 50'si (yalnızca yarım çubuk) veya% 50'nin ( çubuk sarılır ve bir buçuk çubuk olur). Çerçevenin çoğunu genellikle ne yediğini söylemek de oldukça kolaydır: kırmızı = render, sarı = güncelleme, vb ...
  • Her fonksiyonun etrafına kod gibi "kronometre" ekleyen özel bir enstrümanlı yapı oluşturun. (Bunu yaparken büyük bir performans, dcache ve icache vurulabileceğinizi unutmayın, bu yüzden kesinlikle müdahaleci olur. Ancak CPU'da uygun bir örnekleme profili veya iyi bir desteğe sahip değilseniz, bu kabul edilebilir bir seçenektir. bizimki yaptığımızda / çıkış girip daha sonra calltraces yeniden fonksiyon üzerindeki verilerin minimum kayıt hakkında.), biz çok taklit gprof'ın çıkış biçimi 'ın.
  • En iyisi, bir örnekleme profili oluştur ; VTune ve CodeAnalyst x86 ve x64 için kullanılabilir, burada size veri verebilecek çeşitli simülasyon veya benzetim ortamlarınız var.

(Mutlu, kayıtsız, sinirlenmiş ve öfkeli - dört fotoğrafını çeken ve kare yapısına göre iç yapıların köşesinde uygun bir resim sergileyen bir grafik programcısının GDC'sinden eğlenceli bir hikaye var. içerik oluşturucuları, tüm nesneleri ve ortamları için karmaşık gölgelendiricileri açmamayı çabucak öğrendiler : programcıyı kızdırırlardı. Geri bildirim gücüne bakın.)

"Profil çubuklarını" grafik gibi eğlenceli şeyler de yapabileceğinizi unutmayın, böylece ani desenler ("her 7 karede bir kare kaybediyoruz") veya benzerlerini görebilirsiniz.

, Doğrudan cevap olsa için: Tecrübelerime göre bu cazip gelebilir ederken (ve genellikle ödüllendirme - Ben genellikle şeyler öğrenmek) optimize talimatlar sayısı veya icache ya dcache performansına tek fonksiyonları / modüllerini yeniden yazmak için, ve biz aslında yok gerek yapmak bu bazen özellikle iğrenç bir performans problemimiz olduğunda, düzenli olarak ele aldığımız performans sorunlarının büyük çoğunluğu tasarıma iner . Örneğin:

  • Oynatıcı için "saldırı" durumu animasyon karelerini RAM'de önbelleğe almalı mı yoksa diskten yeniden yüklemeli miyiz? Her düşmana ne dersin? Hepsini yapacak RAM'imiz yok, ancak disk yükleri pahalı! Aynı anda 5 veya 6 farklı düşman ortaya çıkarsa otostopu görebilirsiniz! (Tamam, yumurtlamaya ne dersin?)
  • Tüm parçacıklar arasında tek bir işlem mi yapıyoruz yoksa tek bir parçacığımızdaki tüm işlemleri mi yapıyoruz? (Bu bir icache / dcache dengesidir ve cevap her zaman net değildir.) Tüm parçacıkları ayırmaya ve konumları birlikte depolamaya (ünlü "dizilerin yapısı") karşı tüm parçacık verilerini tek bir yerde tutmaya (" yapı dizisi ").

Herhangi bir üniversite düzeyinde bilgisayar bilimi dersinde iğrenç hale gelene kadar duyuyorsunuz, ama: gerçekten veri yapıları ve algoritmalar ile ilgili. Algoritma ve veri akışı tasarımı üzerinde biraz zaman harcamanız, genel olarak para için daha fazla patlama sağlayacak. ( Burada bir fikir edinmek için bir Sony Geliştirici Hizmetleri görevlisinin Nesne Odaklı Programlama slaytlarının mükemmel tuzaklarını okuduğunuzdan emin olun .) Bu, optimizasyon gibi "hissetmez"; geçerli kodun daha hızlı çalışmasını sağlamak yerine çoğunlukla beyaz tahta veya UML aracıyla veya çok sayıda prototip oluştururken harcanan zamandır. Ama genellikle çok daha değerli.

Ve bir başka yararlı sezgisel: Eğer motorunuzun "çekirdeğine" yakınsanız, optimize etmek için fazladan çabaya ve denemeye değer olabilir (örneğin, bu matris çarpanlarını vektörleyin!). Çekirdekten ne kadar uzak olursanız, profil oluşturma araçlarınızdan biri size aksini söylemedikçe, bu konuda daha az endişe duymalısınız.


6
  1. En doğru veri yapılarını ve algoritmaları kullanın.
  2. Profilinizi ve sıcak noktalarınızın tam olarak nerede olduğunu öğreninceye kadar mikro optimizasyon yapmayın.
  3. Akıllı olmak için endişelenme. Derleyici zaten düşündüğünüz tüm küçük hileleri yapıyor ("Oh! Dört ile çarpmam gerekiyor! İki sola kaydırırım!")
  4. Önbellek hatalarına dikkat edin.

1
Derleyiciye güvenmek sadece belirli bir nokta için akıllıdır. Evet, düşünemeyeceğiniz (ve montaj olmadan yapamayacağınız) bazı gözetleme deliği optimizasyonları yapacak, ancak algoritmanızın ne yapması gerektiği konusunda akıllıca bir optimizasyon yapamaz. Ayrıca, ne yaptığınızı biliyorsanız montaj veya içsel olarak kritik kod uygulayarak ne kadar döngü kazanabileceğinize şaşıracaksınız. Derleyiciler, ortaya çıktıkları kadar akıllı değildir, onlara açıkça her yerde söylemediğiniz sürece (dini olarak 'kısıtla' kullanmak gibi) yaptığınız şeyleri bilmezler.
Kaj

1
Ve tekrar söylemeliyim ki, sadece sıcak noktaları ararsanız, çok sayıda döngüyü kaçıracağınız için yorum yapmalıyım çünkü tahtada herhangi bir damlama döngüsü bulamazsınız (örneğin smartpointers .... dereferences her yerde, asla gösterilmiyor) etkin program olarak etkin bir şekilde tüm programınız bir etkin noktadır).
Kaj

1
Her iki noktanıza da katılıyorum, ancak bunların çoğunu "doğru veri yapılarını ve algoritmaları kullanın" altında toplayacağım. Her yerde ref sayımlı akıllı işaretçilerden geçiyorsanız ve sayma yoluyla döngüleri kanıyorsa, kesinlikle yanlış veri yapısını seçtiniz.
Münih

5

Ancak "erken kötüleşme" de unutmayın. Her kod satırında hardcore olmanıza gerek olmasa da, gerçek zamanlı performans sonuçları olan bir oyun üzerinde çalıştığınızı fark etmenin bir gerekçesi vardır. Bunun dışında, orada ne olduğu ve çerçeve başına ne kadar zaman kaldığı hakkında bir fikir edinmek için düzenli olarak profil oluşturma eğilimindeyim. Bana göre kare başına zaman, kare hızı hedefleri ile doğrudan nerede olduğumu söylediğinden en mantıklısıdır. Ayrıca zirvelerin nerede olduğunu ve bunlara neyin neden olduğunu bulmaya çalışın - Sivri uçlu yüksek bir kare hızı üzerinde kararlı bir kare hızı tercih ederim.
Herkes size etkin noktaları ölçmenizi ve optimize etmenizi söylese de, bu teknik size gizli yerlerde kaybolan performansı göstermez. Örneğin, kodunuzdaki her '+' işlemi olması gerekenin iki katı kadar sürerse, etkin nokta olarak görünmez ve bu nedenle asla optimize etmez veya fark etmezsiniz, ancak size çok fazla performansa mal olabilir. Bu döngülerin kaç tanesinin hiç tespit edilmeden uzaklaştığına şaşıracaksınız. Ne yaptığınızın farkında olun.


Bu benim için çok yanlış görünüyor. Elbette, '+' cihazım her çağrıldığında iki kat daha uzun sürebilir, ancak bu sadece sıkı bir döngüde önemlidir. Sıkı bir döngü içinde, tek bir '+' değiştirmek, döngü dışında bir '+' değiştirmekten daha fazla büyüklük siparişleri yapabilir. Bir milisaniyenin kurtarılabileceği mikrosaniyenin onda birini neden düşünelim?
Wilduck

1
O zaman damlama kaybının arkasındaki fikri anlamıyorsunuz. '+' (sadece örnek olarak), sadece sıkı döngülerde değil, çerçeve başına yüz binlerce kez denir. Bu, kartta çok fazla döngü kaybettiğinizde birkaç döngü kaybederse, aramalar kod tabanınız / yürütme yolunuz arasında eşit olarak dağıtıldığı için hiçbir zaman etkin nokta olarak görünmez. Yani mikrosaniyenin onda biri hakkında değil, gerçekten mikrosaniyenin onda biri kadar binlerce kat daha fazla milisaniye ekliyorsunuz. Düşük asılı meyveye (sıkı döngüler) gittikten sonra bir kereden fazla milisaniye kazandım.
Kaj

Damlayan bir musluk gibi. Neden bu küçük düşüşü kurtarmak konusunda endişeleniyorsun? - "Musluğunuz saniyede bir damla damlıyorsa, yılda 2700 galon boşa harcanmasını bekleyebilirsiniz".
Kaj

Oh, sanırım operatör + aşırı yüklendiğinde kastettiğim açık değildi, bu yüzden koddaki her '+' değerini etkileyecekti - gerçekten koddaki her '+' yı optimize etmek istemezsiniz. Kötü örnek sanırım .... Ben bir uygulama exaple 'özellikle işlevsellik aşırı yükleme veya diğer şaşırttıcı C ++ yapıları tarafından gizlendiğinde, uygulamanın varsayılandan daha yavaş olabilir her yerde çağrılan çekirdek işlevsellik için demekti.
Kaj

3

Bir oyun piyasaya sürülmeye hazır olduğunda (ya final ya da beta) ya da fark edilir derecede yavaş olduğunda, bu muhtemelen uygulamanızı profillemek için en iyi zamandır . Tabii ki, profil oluşturucuyu istediğiniz zaman çalıştırabilirsiniz; ama evet, erken optimizasyon tüm kötülüklerin köküdür. Temelsiz optimizasyon da; bazı kodların yavaş olduğunu göstermek için gerçek verilere ihtiyacınız vardır. Bir profiler bunu sizin için yapar.

Bir profil oluşturucuyu bilmiyorsanız öğrenin! İşte bir profilcinin kullanışlılığını gösteren iyi bir blog yazısı .

Oyun kodu optimizasyonunun çoğu, her bir kare için ihtiyacınız olan CPU döngülerini azaltmaya gelir. Bunu yapmanın bir yolu, her rutini yazarken optimize etmek ve mümkün olduğunca hızlı olmasını sağlamaktır. Bununla birlikte, CPU döngülerinin% 90'ının kodun% 10'unda harcandığını söyleyen yaygın bir söz vardır. Bu, tüm optimizasyon çalışmalarınızı bu darboğaz rutinlerine yönlendirmenin, her şeyi eşit bir şekilde optimize etme etkisinin 10 katı olacağı anlamına gelir. Peki bu rutinleri nasıl tanımlıyorsunuz? Profil oluşturma bunu kolaylaştırır.

Aksi takdirde, küçük oyununuzda yetersiz bir algoritma olmasına rağmen 200 FPS'de çalışıyorsa, gerçekten optimize etmek için bir nedeniniz var mı? Hedef makinenizin özellikleri hakkında iyi bir fikriniz olmalı ve oyunun bu makinede iyi çalıştığından emin olmalısınız, ancak bunun ötesinde herhangi bir şey (tartışmalı olarak) oyunu kodlamak veya parlatmak için daha iyi harcanabilecek zaman kaybıdır.


Düşük asılı meyve gerçekten kodun% 10'unda olma eğilimindedir ve sonunda profilleme ile kolayca yakalanırken, sadece bunun için profilleme yapmak, çok denen ancak biraz sahip olan rutinleri kaçırmanızı sağlayacaktır. her biri biraz kötü kod - profilinizde görünmezler, ancak arama başına çok fazla döngü kanarlar. Gerçekten ekliyor.
Kaj

@Kaj, İyi profilciler, kötü algoritmanın yüzlerce bireysel yürütmesinin tümünü toplar ve toplamı gösterir. Sonra "Peki ya 10 kötü yönteminiz varsa ve hepsi frekansın 1 / 10'unda çağrıldıysa?" Tüm zamanınızı bu 10 yöntemle geçirirseniz, paranız için çok daha büyük bir patlama elde edeceğiniz düşük asılı meyvelerin tümünü kaçırırsınız.
John McDonald

2

Profil oluşturmayı yararlı buluyorum. Aktif olarak optimize etmemiş olsanız bile, herhangi bir zamanda performansınızı neyin sınırlandırdığı hakkında bir fikriniz olması iyi olur. Birçok oyun, oyun döngüsünün çeşitli bölümlerinin her kareyi ne kadar sürdüğünü gösteren basit bir grafik grafik (genellikle sadece renkli bir çubuk) görüntüleyen bir tür aşırı yüklenebilir HUD'ye sahiptir.

Performans analizini ve optimizasyonunu çok geç bir aşamaya bırakmak kötü bir fikir olacaktır. Oyunu zaten oluşturduysanız ve CPU bütçenizden% 200 daha fazla iseniz ve bunu optimizasyon yoluyla bulamıyorsanız, mahvoldunuz.

Yazarken grafik, fizik vb. İçin bütçelerin ne olduğunu bilmeniz gerekir. Performansınızın ne olacağı hakkında hiçbir fikriniz yoksa bunu yapamazsınız ve hem performansınızın ne olduğunu hem de ne kadar gevşek olabileceğini bilmeden bunu tahmin edemezsiniz.

Bu yüzden, ilk günden itibaren bazı performans istatistiklerini oluşturun.

Bir şeylerle ne zaman başa çıkacağınıza gelince - yine de, muhtemelen çok geç bırakmamak için, motorunuzun yarısını yeniden düzenlemeniz gerekir. Öte yandan, algoritmayı yarın tamamen değiştirebileceğinizi veya gerçek oyun verilerini koymadıysanız, her döngüyü sıkıştırmak için şeyleri optimize etmek için fazla sarılmayın.

Devam ederken düşük asılı meyveleri alın, büyük şeyleri periyodik olarak ele alın ve iyi olmalısınız.


Oyun içi profil oluşturucuya eklemek için (tamamen katılıyorum), oyun içi profilleyicinizi birden çok çubuk görüntüleyecek şekilde genişletmek (birden çok çerçeve için), oyun davranışını ani artışlarla ilişkilendirmenize yardımcı olur ve ortalama yakalamanızda görünmeyecek darboğazları bulmanıza yardımcı olabilir bir profiler ile.
Kaj

2

Eğer Knuth'un alıntısına bağlamında bakarsanız, bir profiler gibi araçlarla optimize etmemiz gerektiğini açıklamaya devam eder.

Çok temel mimari yerleştirildikten sonra uygulamanızı sürekli olarak profil ve bellek profili oluşturmalısınız.

Profilleme sadece hızı artırmanıza yardımcı olmayacak, hataları bulmanıza da yardımcı olacaktır. Programınız aniden hızı büyük ölçüde değiştirirse, bunun nedeni genellikle bir hatadır. Eğer profil değil fark edilmeden gidebilir.

Optimize etmenin püf noktası, bunu tasarımla yapmaktır. Son dakikaya kadar beklemeyin. Programınızın tasarımının, gerçekten kötü iç döngü hileleri olmadan ihtiyacınız olan performansı verdiğinden emin olun.


1

Projem için, temel motoruma genellikle ÇOK ihtiyaç duyulan bazı optimizasyonlar uyguluyorum. Örneğin, her zaman SSE2 ve 3DNow kullanarak iyi bir sağlam SIMD uygulaması uygulamak isterim! Bu, kayan nokta matematikimin olmasını istediğim yerde ipucu olmasını sağlar. Başka bir iyi uygulama, kodlamak için geri dönmek yerine optimizasyon alışkanlığı kazanmaktır. Çoğu zaman bu küçük uygulamalar zaten kodladığınız kadar zaman alıcıdır. Bir özelliği kodlamadan önce, bunu yapmanın en etkili yolunu araştırdığınızdan emin olun.

Sonuç olarak, bence, zaten emildikten sonra kodunuzu daha verimli hale getirmek için daha sert.


0

En kolay yolun sağduyunuzu kullanmak olduğunu söyleyebilirim - bir şey yavaş çalışıyor gibi görünüyorsa, ona bir göz atın. Bunun bir darboğaz olup olmadığını görün.
Hız işlevlerinin aldığı hıza ve ne sıklıkta çağrıldığına bakmak için bir profil oluşturucu kullanın.
İhtiyacınız olmayan bir şeyi optimize etmeye çalışırken kesinlikle optimizasyon veya zaman harcamaya gerek yoktur.


0

Kodunuz yavaş çalışıyorsa, bir profil oluşturucuyu çalıştırın ve tam olarak neyin daha yavaş çalışmasına neden olduğunu görün. Veya proaktif olabilirsiniz ve performans sorunlarını fark etmeye başlamadan önce çalışan bir profil oluşturucunuz olabilir.

Kare hızınız oyunun acı çekmeye başladığı bir noktaya düştüğünde optimize etmek istersiniz. En olası suçlu CPU'nuzun çok fazla tüketilmesi olacaktır (% 100).


GPU'nun CPU kadar muhtemel olduğunu söyleyebilirim. Gerçekten de, şeylerin ne kadar sıkı bir şekilde bağlı olduğuna bağlı olarak, ağır bir CPU'nun çerçevenin yarısına bağlı olması ve GPU'nun diğer yarısını ağır bir şekilde bağlaması tamamen mümkündür. Aptal profil oluşturma, her ikisinde de% 100'den daha az kullanım gösterebilir.
Profilinizin

0

Kodunuzu ... gerektiği kadar optimize etmelisiniz.

Geçmişte yaptığım şey, profili sürekli olarak sürekli çalıştırmaktır (en azından ekranda her zaman kare hızı sayacında). Oyun yavaşlıyorsa (örneğin min spec makinenizdeki hedef karenizin altında), profil oluşturucuyu açın ve sıcak noktaların görünüp görünmediğine bakın.

Bazen kod olmayabilir. Geçmişte karşılaştığım sorunların çoğu gpu odaklıydı (bu iPhone'da oldu). Doldurma sorunları, çok fazla çizim çağrısı, yeterli geometriyi harmanlama, verimsiz gölgelendiriciler ...

Zor sorunlar (yani yol bulma, fizik) için verimsiz algoritmalar dışında, çok nadiren kodun suçlu olduğu konularla karşılaştım. Ve bu zor problemler, algoritmayı doğru hale getirmek ve daha küçük şeyler hakkında endişelenmemek için çok çaba harcadığınız şeyler olmalıdır.


0

Benim için en iyi takip iyi hazırlanmış veri modeli. Ve optimizasyon-ana adımdan önce. Yani büyük bir şey uygulamaya başlamadan önce. En iyi duruma getirmenin diğer nedeni, kaynaklar üzerinde kontrolü kaybettiğimde, Uygulamanın çok fazla CPU yükü / GPU yüküne veya belleğe ihtiyacı olduğu ve neden bilmiyorum :) veya çok fazla.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.