Bu beni şu anki endüstri senaryosunda okuyucunun ne kadar önemli olduğunu merak etmeme neden oldu.
Performansın üçüncü parti kodundan gelmediği performans kritik alanlarda ağır kaldırma yapıyoruz, ama kendi başımıza, o zaman bu önem sırasındaki şeyleri CPU perspektifinden ele almaya meyilliyim (GPU kazandığım bir joker karakter. içine girmeyin):
- Hafıza Verimliliği (örneğin: referansın yeri).
- algoritmik
- Çok iş parçacığı
- SIMD
- Diğer Optimizasyonlar (statik dal tahmini ipuçları, örneğin)
Bu listenin yalnızca önemine değil, bakım üzerindeki etkisi, ne kadar kolay oldukları (eğer önceden düşünülmeye değer değilse), listedeki diğer kişilerle etkileşimleri vb.
Hafıza Verimliliği
Çoğu, algoritmik yerine bellek verimliliği seçimime şaşırmış olabilir. Bunun nedeni, hafıza verimliliğinin bu listedeki diğer 4 öğeyle etkileşime girmesi ve bunun dikkate alınması genellikle "uygulama" kategorisinden ziyade "tasarım" kategorisinde olması. Kuşkusuz, burada bir miktar tavuk ya da yumurta problemi vardır çünkü hafıza verimliliğini anlamak için listedeki 4 öğenin hepsinin göz önünde bulundurulması gerekirken, diğer 4 öğenin tümü de hafıza verimliliğini dikkate almayı gerektirir. Yine de her şeyin merkezinde.
Örneğin, doğrusal zaman ardışık erişim ve geriye sabit zaman eklemeleri sunan ve küçük elemanlar için başka hiçbir şey sunan bir veri yapısına ihtiyacımız varsa, burada ulaşmak için saf seçim, bağlantılı bir liste olacaktır. Bu hafıza verimliliğini göz ardı ediyor. Karışımdaki bellek verimliliğini göz önüne aldığımızda, bu senaryoda daha bitişik yapılar seçiyoruz, örneğin birbirine bağlanmış yetiştirilebilir dizi temelli yapılar veya daha fazla bitişik düğüm (örneğin: bir düğüme 128 eleman yerleştiren) bir havuz ayırıcısı tarafından desteklenen bağlantılı bir liste. Bunlar aynı algoritmik karmaşıklığa sahip olmasına rağmen çarpıcı bir kenara sahiptir. Aynı şekilde, bir bellek algoritmasından ötürü bir algoritmanın karmaşıklığına rağmen, bir dizilimin genellikle hızlı sıralamalarını seçiyoruz.
Aynı şekilde, eğer hafıza erişim kalıplarımız doğada o kadar ayrıntılı ve dağınıksa, kodun en tanecikli seviyelerinde kilitlenirken yanlış paylaşım miktarını en üst düzeye çıkardığımız için verimli çoklu okumaya sahip olamayız. Bu nedenle, bellek verimliliği verimlilik çok iş parçacığını çoğaltır. Bu konudan en iyi şekilde yararlanmak için bir önkoşuldur.
Listedeki her bir öğe, verilerle karmaşık bir etkileşime sahiptir ve verinin nasıl temsil edildiğine odaklanmak, en sonunda, bellek verimliliği alanındadır. Yukarıdakilerin her biri, verileri temsil etmek veya erişmek için uygun olmayan bir yöntemle tıkanabilir.
Bellek verimliliğinin bu kadar önemli olmasının bir başka nedeni de bütün kod tabanında uygulayabilmesi . Genel olarak, insanlar verimsizliklerin buradaki ve buradaki çalışmaların küçük önemsiz bölümlerinden biriktiğini düşündüklerinde, bir profilleyiciyi yakalamaları gerektiğinin bir işaretidir. Yine de düşük gecikmeli alanlar veya çok sınırlı donanıma sahip olanlar, profil çıkardıktan sonra bile, tahsis etme, kopyalama ve hafızaya erişme. Tipik olarak bu, tüm kod tabanının, kod tabanı boyunca uygulanan yepyeni bir standartlar dizisine yol açabilecek bir performans sorununa duyarlı olabileceği tek zamandır ve bellek verimliliği genellikle bunun merkezindedir.
algoritmik
Bu, hemen hemen verilen bir şeydir, çünkü bir sıralama algoritmasındaki seçim, sıralama yapmak için aylar aylar süren toplu girişler arasındaki farkı yaratabilir. Seçim, eğer gerçekten de alt-parite veya kübik algoritmalar ile bir lineermik sistem arasında veya en azından 1.000.000 çekirdek makineye sahip olana kadar (lineer ve logaritmik veya sabit) arasındaysa, en büyük etkiyi yaratır (bu durumda hafıza) verimlilik daha da önemli hale gelirdi).
Ancak, kişisel listemin en üstünde değil, çünkü kendi alanında yetkin olan herhangi biri sıkıntı giderme için bir hızlandırma yapısı kullanmayı bilecektir, örneğin algoritmik bilgiye göre doygun olduğumuzu ve bunun gibi bir türevi kullanmak gibi şeyleri bildiğimizi biliyoruz. önek tabanlı aramalar için sayı tabanı ağacı bebek eşyalarıdır. Çalıştığımız alanla ilgili bu tür temel bilgilerden yoksun olmak, algoritmik verimlilik kesinlikle en üst seviyeye çıkacaktır, ancak çoğu zaman algoritmik verimlilik önemsizdir.
Ayrıca, yeni algoritmalar icat etmek bazı alanlarda bir zorunluluk olabilir (örneğin: mesh işlemede daha önce bulunmadığı için yüzlerce tane icat etmem gerekti ya da diğer ürünlerdeki benzer özelliklerin uygulanması bir makalede yayınlanmayan özel sırlardı). ). Bununla birlikte, sorun çözme bölümünü geçtikten ve doğru sonuçları almanın bir yolunu bulduğumuzda ve verimlilik hedef haline geldiğinde, gerçekten kazanmanın tek yolu, verilerle nasıl etkileşime girdiğimizi düşünmektir (bellek). Bellek verimliliğini anlamadan, yeni algoritma, daha hızlı ve daha basit bir algoritma sağlamak için ihtiyaç duyulan tek şey bellek verimliliğini biraz daha düşünmek olduğunda, daha hızlı hale getirmek için boşuna çabalarla gereksiz yere karmaşık hale gelebilir.
Son olarak, algoritmalar "uygulama" kategorisinde bellek verimliliğinden daha fazla olma eğilimindedir. Başlangıçta kullanılan en uygun bir alt algoritma bile olsa, daha önceden iyileştirilmesi daha kolaydır. Örneğin, düşük kaliteli bir görüntü işleme algoritması genellikle kod tabanında yalnızca bir yerel yerde uygulanır. Daha sonra daha iyi bir tane ile değiştirilebilir. Bununla birlikte, tüm görüntü işleme algoritmaları, Pixel
en uygun alt bellek temsiline sahip bir arayüze bağlıysa , ancak bunu düzeltmenin tek yolu, çoklu piksellerin temsil edilme şeklini değiştirmektir (tek bir tane değil) SOL ve kod tabanını tamamen yeniden yazmak zorunda kalacaksınız.Image
arayüz. Aynı tür bir sıralama algoritmasını değiştirmek için de geçerlidir - bu genellikle bir uygulama detayıdır; sıralanan verilerin temelini temsil etmesinde veya mesajlardan geçirilme biçiminde yapılan tam bir değişiklik, arayüzlerin yeniden tasarlanmasını gerektirebilir.
Çok iş parçacığı
Multithreading, donanım bağlamında oynayan mikro düzeyde bir optimizasyon olduğundan performans bağlamında zor bir durumdur, ancak donanımımız gerçekten bu yönde ölçeklenir. Zaten 32 çekirdeği olan akranlarım var (sadece 4'üm var).
Yine de mulithreading, amacı yazılımı hızlandırmak için kullanılıyorsa, muhtemelen bir profesyonel tarafından bilinen en tehlikeli mikro optimizasyonlardan biridir. Yarış durumu mümkün olan en ölümcül hatadır, çünkü doğası gereği belirsizdir (belki de birkaç ayda bir geliştiricinin makinesinde hata ayıklama bağlamı dışında en elverişsiz bir zamanda ortaya çıkabilir). Bu yüzden tartışmasızlık ve tüm bunların arasında potansiyel kod doğruluğu konusundaki en olumsuz bozulmaya sahiptir, çünkü özellikle çoklu kullanım ile ilgili hatalar, en dikkatli testlerin bile radarı altında kolayca uçabilmektedir.
Bununla birlikte, bu çok önemli hale geliyor. Halihazırda sahip olduğumuz çekirdek sayısı göz önüne alındığında, bellek verimi (bazen yüzlerce kez daha hızlı hale getirebilen) gibi bir şey hala her zaman trump olmasa da, daha fazla çekirdek görüyoruz. Tabii ki, 100 çekirdekli makinelerde bile, listenin en üstünde bellek verimliliğini koyardım, çünkü iplik verimliliği genellikle onsuz mümkün değildir. Bir program böyle bir makinede yüz iplikler kullanabilir ve yine de verimli bellek gösterimi ve erişim düzenleri (kilitleme düzenlerine bağlı olacak şekilde) bulunmadığında yavaş olabilir.
SIMD
SIMD ayrıca biraz garip çünkü kayıtlar daha da genişliyor, daha da genişleme planları var. Başlangıçta 64-bit MMX kayıtlarını ve ardından paralel olarak 4 SPFP işlemi yapabilen 128-bit XMM kayıtlarını gördük. Şimdi paralel olarak 8 yetenekli 256-bit YMM kayıt görüyoruz. Ve zaten 16'ya paralel olarak izin verecek olan 512 bitlik kayıtlar için zaten planlar var.
Bunlar multithreading'in verimliliği ile etkileşime girecek ve çoğalacaktır. Ancak SIMD, çok iş parçacığı kadar sürdürülebilirliği de azaltabilir. Onlarla ilgili hataların bir kilitlenme veya yarış durumu olarak çoğaltılması ve düzeltilmesi zor olmasa da, taşınabilirlik zordur ve kodun herkesin makinesinde çalışmasını sağlamak (ve donanım özelliklerine göre uygun talimatları kullanmak); garip.
Başka bir şey ise, bugün derleyiciler genellikle ustalıkla yazılmış SIMD kodunu geçmemelerine rağmen, kolayca naif denemeleri yenerler. Artık manuel olarak yapmak zorunda olmadığımız veya en azından kendinden veya doğrudan montaj kodu (belki de sadece küçük bir insan rehberliği) yazmak için el ile kullanmak zorunda kalmayacağımız bir noktaya gelebilirler.
Yine de, vectorized işlem için verimli bir bellek düzeni olmadan, SIMD işe yaramaz. Sadece bir işlem yapmak için sadece bir skaler alanı geniş bir sicile yükleyerek bitireceğiz. Tüm bu öğelerin temelinde, bellek düzenlerine gerçekten verimli olmak için bir bağımlılık var.
Diğer Optimizasyonlar
Bunlar genellikle, eğer kelime sadece algoritmik odağın ötesine geçmeyi değil, aynı zamanda performans üzerinde küçük bir etkiye sahip olan değişikliklere doğru ilerlemeyi önerirse, bugünlerde “mikro” olarak adlandırmaya başlayacağımı önereceğim şeyler.
Genellikle dal tahmini için optimizasyon yapmaya çalışmak, algoritma veya hafıza verimliliğinde bir değişiklik gerektirir. Örneğin, bu yalnızca statik tahmin için ipuçları ve yeniden düzenleme kodu ile deneniyorsa, bu tür kodların yalnızca ilk kez uygulanmasını geliştirmeye meyilliyse, etkilerini sorgulanabilir hale getirir. Genellikle düpedüz ihmal edilemez.
Performans İçin Çok Okunmaya Geri Dön
Her neyse, performans bağlamında çok okuyuculuk ne kadar önemli? 4 çekirdekli makinemde ideal olarak 5 kat daha hızlı işler yapabilir (hiper-okudum ile ne alabilirim). 32 çekirdeği olan meslektaşım için çok daha önemli olurdu. Ve önümüzdeki yıllarda giderek daha önemli hale gelecektir.
Bu yüzden oldukça önemli. Fakat eğer hafıza verimliliği kilitlerin korunmasına izin vermek, yanlış paylaşımları azaltmak, vb.
Performans Dışında Çok Okumak
Çok iş parçacığı her zaman basit bir verim türü anlamda saf performansla ilgili değildir. Bazen, kullanıcının yanıt verebilirliğini artırmak için olası bir işlem maliyetinde bile bir yükü dengelemek veya kullanıcının işleri bitirmesini beklemeden daha fazla çoklu görev yapmasına izin vermek için kullanılır (ör: dosya indirirken göz atmaya devam et).
Bu gibi durumlarda, okuyucunun en üst seviyeye (belki de bellek verimliliğinin üstünde bile) yükseldiğini, çünkü donanımdan en iyi şekilde yararlanmaktan ziyade kullanıcı-uç tasarımla ilgili olduğunu düşünüyorum. Arayüz tasarımlarına ve tüm kod tabanımızı bu tür senaryolarda yapılandırma şeklimize sık sık hakim olacak.
Çok büyük bir veri yapısına erişen sıkı bir döngüyü basit bir şekilde paralel hale getirmediğimizde, çoklu okuma gerçekten zorlu "tasarım" kategorisine gider ve tasarım her zaman uygulamanın önüne geçer.
Bu yüzden, bu gibi durumlarda, açık okuyucuyu baştan sona okumayı düşünmek kesinlikle kritik, hatta bellek gösterimi ve erişimden daha önemli.