Hesaplama açısından yoğun olan kodu “tanıma dışında optimize edilmiş” belgelemek ve öğretmek nasıl?


11

Bazen, en ağır düşük düzeyli optimizasyona ihtiyaç duyan, yeterince yoğun olan kodun% 1'i vardır. Genel olarak video işleme, görüntü işleme ve her türlü sinyal işleme örnek gösterilebilir.

Amaçlar , kodun sürdürülemez hale gelmemesi ve yeni geliştiriciler tarafından kaldırılmaya eğilimli hale gelmemesi için optimizasyon tekniklerini belgelemek ve öğretmektir . (*)

(*) Gelecekteki bazı öngörülemeyen işlemcilerde belirli bir optimizasyonun tamamen yararsız olmasına rağmen, kod yine de silinecektir.

Yazılım tekliflerinin (ticari veya açık kaynaklı) en hızlı koda sahip olarak ve en yeni CPU mimarisini kullanarak rekabet avantajlarını koruduğu göz önüne alındığında, yazılım yazarlarının belirli bir çıktı için aynı çıktıyı alırken daha hızlı çalışabilmeleri için kodlarını değiştirmeleri gerekir. görev, az miktarda yuvarlama hatasına tahammül eden whlist.

Tipik olarak, bir yazılım yazarı, gerçekleşen her optimizasyon / algoritma yeniden yazımının bir belgesi olarak bir işlevin birçok sürümünü tutabilir. Bu sürümler optimizasyon tekniklerini incelemek için başkalarını nasıl kullanılabilir hale getirir?

İlişkili:


1
Koddaki farklı sürümleri, yorumladı, okuyucuya neler olduğunu anlatan çok sayıda yorumla tutabilirsiniz.
Mike Dunlavey

1
Onlara sadece kodun ne yaptığını söylemeyin, neden bu şekilde daha hızlı olduğunu söyleyin. Gerekirse, kendi, wiki benzeri, dokümanlarınız veya İnternet'teki kaynaklarınız için algoritmalara bağlantılar ekleyin (sadece bu durumda link-rot'un farkında olun, orijinal dokümanın bir bağlantısıyla kendi doküman sisteminize kopyalamak akıllıca olabilir. .)
Marjan Venema

1
@MikeDunlavey: Ah, lütfen yorum yapma. Aynı işlevin birkaç uygulamasına sahip olun ve en hızlı olanı çağırın. Bu şekilde, kodun farklı bir sürümüne kolayca geçebilir ve tümünü kıyaslayabilirsiniz.
11:55

2
@sleske Bazen daha fazla ikili koda sahip olmak kodu yavaşlatabilir.
quant_dev

@quant_dev: Evet, bu olabilir. Ben sadece kod güncel tutmak için (ideal) düzenli olarak inşa ve çalıştırmak önemli olduğunu düşünüyorum. Belki sadece hata ayıklama modunda oluşturun.
sleske

Yanıtlar:


10

Kısa cevap

Optimizasyonları yerel tutun, açık hale getirin, iyi belgelendirin ve optimize edilmiş sürümleri hem kaynak kodu hem de çalışma zamanı performansı açısından birbiriyle ve optimize edilmemiş sürümle karşılaştırmayı kolaylaştırın.

Tam cevap

Böyle optimizasyon gerçekten varsa vardır ürününüz için o kadar önemli, o zaman optimizasyon önce kullanışlı değildi sadece neden bilmek değil, aynı zamanda gelecekte yararlı olup olmayacağını bilmek yardım geliştiriciler için yeterli bilgi sağlamak gerekir.

İdeal olarak, performans testini oluşturma sürecinize dahil etmeniz gerekir, böylece yeni teknolojilerin eski optimizasyonları ne zaman geçersiz kılacağını öğrenirsiniz.

Hatırlamak:

Program Optimizasyonunun İlk Kuralı: Yapmayın.

İkinci Program Optimizasyonu Kuralı (yalnızca uzmanlar için!): Henüz yapma. "

- Michael A.Jackson

Şimdi zamanın olup olmadığını bilmek için kıyaslama ve test gerektirir.

Bahsettiğiniz gibi, yüksek düzeyde optimize edilmiş kodla ilgili en büyük sorun, bakımının zor olmasıdır, bu nedenle, mümkün olduğunca optimize edilmiş bölümleri optimize edilmemiş bölümlerden ayrı tutmanız gerekir. Bunu derleme zamanı bağlantısıyla yapsanız da, çalışma zamanı sanal işlev çağrıları veya aradaki bir şey önemli değil. Önemli olan, testlerinizi yaptığınızda, şu anda ilgilendiğiniz tüm sürümlere karşı test edebilmenizdir .

Üretim kodunun temel optimize edilmemiş versiyonunun her zaman kodun amacını anlamak için kullanılabileceği , daha sonra optimize edilmiş versiyonu veya versiyonları içeren bunun yanında farklı optimize edilmiş modüller inşa edebileceği, her yerde açıkça belgelediği bir sistem kurmaya meyilli olacağım optimize edilmiş sürüm temel çizgiden farklıdır. Testlerinizi (ünite ve entegrasyon) çalıştırdığınızda, testi optimize edilmemiş versiyonda ve mevcut tüm optimize edilmiş modüllerde çalıştırırsınız.

Misal

Örneğin, bir Hızlı Fourier Dönüşümü işleviniz olduğunu varsayalım . Belki de içinde temel, algoritmik bir uygulama fft.cve testler vardır fft_tests.c.

Daha sonra Pentium geliyor ve MMX talimatlarınıfft_mmx.c kullanarak sabit nokta sürümünü uygulamaya karar veriyorsunuz . Daha sonra Pentium 3 birlikte geliyor ve kullanan bir sürümünü eklemeye karar akış SIMD Extensions içinde .fft_sse.c

Şimdi CUDA eklemek istiyorsunuz , bu yüzden eklersiniz fft_cuda.c, ancak yıllardır kullandığınız test veri kümesiyle CUDA sürümünün SSE sürümünden daha yavaş olduğunu bulun! Biraz analiz yaparsınız ve 100 kat daha büyük bir veri kümesi eklersiniz ve beklediğiniz hızlanmayı elde edersiniz, ancak şimdi CUDA sürümünü kullanmak için kurulum süresinin önemli olduğunu ve küçük veri kümeleriyle Bu kurulum maliyeti olmadan algoritma.

Bu vakaların her birinde aynı algoritmayı uyguluyorsunuz, hepsi aynı şekilde davranmalı, ancak farklı mimarilerde farklı verimlilik ve hızlarla çalışacaklar (eğer çalışırlarsa). Kod açısından bakıldığında, aynı arabirimin neden farklı şekillerde uygulandığını bulmak için herhangi bir kaynak dosya çiftini karşılaştırabilirsiniz ve genellikle en kolay yol orijinal optimize edilmemiş sürüme geri dönmektir.

Aynı şey, optimize edilmemiş algoritmayı uygulayan bir temel sınıf ve türetilmiş sınıfların farklı optimizasyonlar uyguladığı bir OOP uygulaması için de geçerlidir.

Önemli olan aynı şeyleri tutmaktır aynıdır böylece, farklılıklar ortada .


7

Özellikle Video ve Görüntü işleme örneğini aldığınız için, kod aynı sürümün bir parçası olarak tutulabilir, ancak içeriğe bağlı olarak etkin veya etkin değildir.

Bahsetmediğiniz halde, Cburada olduğunu varsayıyorum .

Kodda en basit yol C, bir optimizasyon yapar (ve aynı zamanda taşınabilir hale getirmeye çalışırken de geçerlidir)

 
#ifdef OPTIMIZATION_XYZ_ENABLE 
   // your optimzied code here... 
#else  
   // your basic code here...

#define OPTIMIZATION_XYZ_ENABLEMakefile'de derleme sırasında etkinleştirdiğinizde , her şey buna göre çalışır.

Genellikle, çok fazla işlev optimize edildiğinde işlevlerin ortasında birkaç satır kod kesmek dağınık hale gelebilir. Bu nedenle, bu durumda belirli bir işlevi yerine getirmek için farklı işlev işaretçileri tanımlanır .

ana kod her zaman aşağıdaki gibi bir işlev işaretçisi aracılığıyla yürütülür


   codec->computed_idct(blocks); 

Ancak işlev işaretçileri, örneğin türüne bağlı olarak tanımlanır (örn. Burada idct işlevi, farklı CPU mimarisi için optimize edilmiştir.



if(OPTIMIZE_X86) {
  codec->computed_idct = compute_idct_x86; 
}
else if(OPTIMZE_ARM) {
  codec->computed_idct = compute_idct_ARM;
}
else {
  codec->computed_idct = compute_idct_C; 
}

libjpeg kodu ve libmpeg2 kodunu görmelisiniz ve bu tür teknikler için ffmpeg olabilir .


6

Bir araştırmacı olarak biraz "darboğaz" kodunu yazıyorum. Bununla birlikte, bir kez üretime alındıktan sonra, ürünün içine entegre edilmesi ve daha sonra destek sağlanması, geliştiricilere düşer. Tahmin edebileceğiniz gibi, programın neyi ve nasıl çalışması gerektiğini net bir şekilde iletmek son derece önemlidir.

Bu adımı başarıyla tamamlamanın üç temel bileşeni olduğunu buldum

  1. Kullanılan algoritma kesinlikle açık olmalıdır.
  2. Her uygulama hattının amacı açık olmalıdır.
  3. Beklenen sonuçlardan sapmalar mümkün olan en kısa sürede belirlenmelidir.

İlk adım olarak, her zaman algoritmayı belgeleyen kısa bir teknik inceleme yazıyorum . Buradaki amaç, aslında başka bir kişinin sadece beyaz kağıdı kullanarak sıfırdan uygulayabilmesi için yazmaktır. Eğer iyi bilinen, yayınlanmış bir algoritma ise referansları vermek ve anahtar denklemleri tekrarlamak yeterlidir. Orijinal çalışma ise, biraz daha açık olmanız gerekir. Bu size kodun ne yapması gerektiğini söyleyecektir .

Geliştirmeye verilen fiili uygulama, tüm incelikleri açıkça ortaya konacak şekilde belgelenmelidir. Kilitlenmeyi önlemek için kilitleri belirli bir sırada alırsanız, bir yorum ekleyin. Önbellek tutarlılığı sorunları nedeniyle bir matrisin satırları yerine sütunlar üzerinde yineleme yaparsanız, bir yorum ekleyin. Biraz zekice bir şey yaparsanız, yorum yapın. Teknik incelemeyi garanti edemiyorsanız ve kod asla ayrılmayacaksa (VCS veya benzeri bir sistem aracılığıyla), teknik incelemeye geri dönebilirsiniz. Sonuç kolayca% 50'den fazla yorum olabilir. Sorun değil. Bu , kodun neden yaptığını yaptığını size söyleyecektir .

Son olarak, değişiklikler karşısında doğruluğu garanti edebilmeniz gerekir. Neyse ki otomatik test ve sürekli entegrasyon platformlarında kullanışlı bir araçtır . Bunlar , kodun gerçekte ne yaptığını size söyleyecektir .

En içten tavsiyem adımların hiçbirini gözden kaçırmamak olacaktır. Onlara daha sonra ihtiyacınız olacak;)


Kapsamlı cevabınız için teşekkürler. Tüm noktalarınıza katılıyorum. Otomatik test açısından, sabit noktalı aritmetik ve SIMD kodunun sayısal aralığını yeterince kapsamanın zor olduğunu, iki kez yakıldığımı bir şey buldum. Sadece yorumlarda belirtilen önkoşullar (pekiştirme kodu olmadan) her zaman karşılanmadı.
rwong

Cevabınızı henüz kabul etmememin nedeni, "kısa bir teknik incelemenin" ne anlama geldiği ve bu konuyu üretmek için ne tür bir çaba göstermesi gerektiği konusunda daha fazla rehberliğe ihtiyacım olması. Bazı endüstriler için bu, ana iş kolunun bir parçasıdır, ancak diğer endüstrilerde maliyet göz önünde bulundurulmalı ve yasal olarak mevcut kısayollar alınmış olmalıdır.
11:02

Her şeyden önce, otomatik test, kayan nokta aritmetiği ve paralel kod ile ilgili acınızı hissediyorum. Korkarım ki tüm durumlar için geçerli bir çözüm yok. Genellikle oldukça liberal toleranslarla çalışırım, ancak endüstrinizde bu mümkün olmayabilir.
drxzcl

2
Uygulamada, teknik inceleme genellikle "kabartmak" bölümleri olmadan bilimsel bir makalenin ilk taslağına benzemektedir (anlamlı bir giriş yok, özet yok, minimal sonuçlar / tartışma ve sadece onu anlamak için gerekli referanslar). Yazıyı, algoritma geliştirme ve / veya algoritma seçiminin bir raporu ve ayrılmaz bir parçası olarak görüyorum. Bu algoritmayı uygulamayı seçtiniz (diyelim ki spektral FFT). Tam olarak nedir? Neden bunu diğerlerine tercih ettin? Paralellik özellikleri nelerdir? Çaba, seçim / geliştirme çalışmasıyla orantılı olmalıdır.
drxzcl

5

Bu en iyi kod her kapsamlı kod bloğunun açıklayıcı yorum önceden olduğu noktaya kadar kapsamlı bir yorum ile çözüleceğine inanıyorum.

Yorumlar, teknik özelliklere veya donanım referans malzemesine yapılan atıfları içermelidir.

Uygun olduğu yerde sektör genelinde terminoloji ve algoritma adları kullanın - örneğin 'X mimarisi, hizalanmamış okumalar için CPU tuzakları oluşturur, bu nedenle bu Duff'ın Cihazı bir sonraki hizalama sınırını doldurur'.

Neler olup bittiğinin yanlış anlaşılmasını sağlamak için yüzünüzde değişken adlandırma kullanacağım. Macarca değil, iki dikey piksel arasındaki bayt cinsinden mesafeyi tanımlamak için 'adım' gibi şeyler.

Bunu, yüksek düzey diyagramlara ve blok tasarımına sahip, insan tarafından okunabilir kısa bir belge ile de destekleyeceğim.


1
Aynı projede tek bir şey için tek bir tutarlı terminoloji kullanmak (örneğin, "adım", "hizalama" gibi benzer anlamlar üzerinden "adım" kullanmak yardımcı olacaktır). Birkaç projenin kod tabanını bir projeye entegre ederken bu biraz zor.
rwong
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.