Son çare performans optimizasyonu stratejileri [kapalı]


609

Bu sitede zaten çok sayıda performans sorusu var, ancak bana göre neredeyse hepsi çok probleme özgü ve oldukça dar. Ve neredeyse hepsi erken optimizasyondan kaçınmak için tavsiyeyi tekrarlar.

Diyelim ki:

  • kod zaten doğru çalışıyor
  • seçilen algoritmalar problemin koşulları için zaten optimal
  • kod ölçüldü ve rahatsız edici rutinler izole edildi
  • tüm optimizasyon girişimleri de konuları daha da kötüleştirmemek için ölçülecektir

Burada aradığım şey, yapacak başka bir şey kalmadığı zaman ne olursa olsun kritik bir algoritmada son yüzde birkaçına kadar çıkacak stratejiler ve püf noktaları.

İdeal olarak, cevapları dili agnostik hale getirmeye çalışın ve varsa önerilen stratejilerin alt taraflarını belirtin.

İlk önerilerimle bir yanıt ekleyeceğim ve Yığın Taşması topluluğunun düşünebileceği başka şeyleri dört gözle bekleyeceğim.

Yanıtlar:


427

Tamam, problemi, iyileştirilmesi için fazla yer olmadığı anlaşılıyor. Bu benim deneyimime göre oldukça nadirdir. Bunu, Kasım 1993'teki Dr. Dobbs makalesinde, belirgin bir atık olmadan geleneksel olarak iyi tasarlanmış önemsiz bir programdan başlayarak ve duvar saati 48 saniyeden kısalıncaya kadar bir dizi optimizasyon yoluyla açıklamaya çalıştım. 1.1 saniyeye ve kaynak kodu boyutu 4. My tanı aracı kat azaldı bu oldu . Değişiklik sırası şuydu:

  • Bulunan ilk sorun, yarıdan uzun süredir hesaplanan liste kümelerinin (şimdi "yineleyiciler" ve "kapsayıcı sınıfları" olarak adlandırılır) kullanılmasıydı. Bunlar oldukça basit bir kodla değiştirildi ve zaman 20 saniyeye indirildi.

  • Şimdi en büyük zaman alıcı daha liste oluşturma. Yüzde olarak, daha önce çok büyük değildi, ama şimdi daha büyük sorunun giderilmesinden kaynaklanıyor. Hızlanmanın bir yolunu buluyorum ve zaman 17 saniyeye düşüyor.

  • Şimdi bariz suçlular bulmak daha zor, ama hakkında bir şeyler yapabileceğim birkaç küçük tane var ve zaman 13 saniyeye düşüyor.

Şimdi bir duvara çarpmış gibiyim. Örnekler bana tam olarak ne yaptığını söylüyor, ancak geliştirebileceğim bir şey bulamıyorum. Daha sonra programın temel tasarımına, işlem odaklı yapısına odaklanıyorum ve yaptığı tüm liste aramasının sorunun gereksinimlerine göre zorunlu olup olmadığını soruyorum.

Sonra, program kodunun daha küçük bir kaynaktan gerçekten oluşturulduğu (önişlemci makroları aracılığıyla) ve programın programcının oldukça tahmin edilebilir olduğunu bildiği şeyleri sürekli olarak çözmediği bir yeniden tasarıma çarptım. Başka bir deyişle, yapılacak şeylerin sırasını "yorumlamayın", "derleyin".

  • Bu yeniden tasarım, kaynak kodunu 4 kat küçülterek yapılır ve süre 10 saniyeye düşürülür.

Şimdi, çok hızlı olduğu için, örneklemesi zor, bu yüzden yapmak için 10 kat daha fazla iş veriyorum, ancak aşağıdaki süreler orijinal iş yüküne dayanıyor.

  • Daha fazla tanı, kuyruk yönetiminde zaman harcadığını ortaya koymaktadır. Bu astarlar süreyi 7 saniyeye düşürür.

  • Şimdi büyük bir zaman alıcı, yaptığım teşhis baskısı. Yıkayın - 4 saniye.

  • Şimdi en büyük zaman alıcılar malloc ve ücretsiz çağrılardır . Nesneleri geri dönüştürme - 2,6 saniye.

  • Örneklemeye devam ederken, hala kesinlikle gerekli olmayan işlemleri buluyorum - 1.1 saniye.

Toplam hız faktörü: 43,6

Şimdi iki program birbirine benzemiyor, ancak oyuncak olmayan yazılımda her zaman böyle bir ilerleme gördüm. Önce azalan bir noktaya ulaşıncaya kadar kolay şeyleri ve sonra daha zor olanı elde edersiniz. Ardından, elde ettiğiniz içgörü, tekrar azalan getirilere ulaşana kadar yeni bir hızlanma turu başlatarak yeniden tasarıma yol açabilir. Şimdi bu o olsun merak mantıklı olabilir noktadır ++iya i++ya for(;;)ya while(1)daha hızlı: Ben Yığın taşması bu yüzden sık görmek tür sorular.

Not: Neden profiler kullanmadım merak edilebilir. Cevap, bu "problemlerin" neredeyse her birinin, numunelerin yerini saptayan bir fonksiyon çağrı sitesi olmasıdır. Profilciler, bugün bile, ifadelerin ve çağrı talimatlarının bulunması, tüm işlevlerden daha önemli ve düzeltilmesi daha kolay olduğu fikrine pek yaklaşmıyor.

Aslında bunu yapmak için bir profil oluşturdum, ancak kodun ne yaptığına dair gerçek bir aşağılık yakınlığı için, parmaklarınızı doğru bir şekilde almanın yerini tutamaz. Örneklerin sayısının az olması bir sorun değildir, çünkü bulunan sorunların hiçbiri o kadar küçük değildir ki kolayca gözden kaçırılırlar.

ADDED: jerryjvl bazı örnekler istedi. İşte ilk sorun. Birlikte zamanın yarısını alan az sayıda ayrı kod satırından oluşur:

 /* IF ALL TASKS DONE, SEND ITC_ACKOP, AND DELETE OP */
if (ptop->current_task >= ILST_LENGTH(ptop->tasklist){
. . .
/* FOR EACH OPERATION REQUEST */
for ( ptop = ILST_FIRST(oplist); ptop != NULL; ptop = ILST_NEXT(oplist, ptop)){
. . .
/* GET CURRENT TASK */
ptask = ILST_NTH(ptop->tasklist, ptop->current_task)

Bunlar ILST liste kümesini kullanıyordu (liste sınıfına benzer). "Bilgi gizleme" ile olağan bir şekilde uygulanırlar, yani sınıf kullanıcılarının nasıl uygulandıklarına dikkat etmeleri gerekmezdi. Bu satırlar (yaklaşık 800 satır kod dışında) yazıldığında, bunların bir "darboğaz" olabileceği fikrine verilmedi (o kelimeden nefret ediyorum). Bunlar sadece bir şeyler yapmanın önerilen yoludur. Gezde bunlardan kaçınılması gerektiğini söylemek kolaydır , ancak benim deneyimime göre tüm performans sorunları böyledir. Genel olarak, performans problemleri yaratmaktan kaçınmak iyidir. Yaratılmış olanları bulmak ve düzeltmek daha da iyidir ("kaçınılması gereken" olsalar bile).

İkinci sorun, iki ayrı satırda:

 /* ADD TASK TO TASK LIST */
ILST_APPEND(ptop->tasklist, ptask)
. . .
/* ADD TRANSACTION TO TRANSACTION QUEUE */
ILST_APPEND(trnque, ptrn)

Bunlar, öğelerini sonuna ekleyerek listeler oluşturuyor. (Düzeltme, öğeleri diziler halinde toplamak ve listeleri bir kerede oluşturmaktı.) İlginç olan, bu ifadelerin yalnızca orijinal sürenin 3 / 48'ine mal olması (yani çağrı yığınında). Aslında başlangıçta büyük bir problem . Ancak, ilk sorunu çıkardıktan sonra, zamanın 3/20 maliyeti ve bu yüzden şimdi "büyük balık" idi. Genel olarak böyle devam eder.

Bu projenin yardım ettiğim gerçek bir projeden damıtıldığını ekleyebilirim. Bu projede, bir görevin bitip bitmediğini görmek için bir iç döngü içinde veritabanı erişim rutinini çağırmak gibi performans sorunları çok daha dramatikti (hızlandırmalar gibi).

REFERANS EKLENDİ: kaynak kodu, hem orijinal hem yeniden tasarlanmış, bulunabilir www.ddj.com dosyası 9311.zip, dosyalar slug.asc ve slug.zip içinde, 1993 için.

EDIT 2011/11/26: Şimdi Visual C ++ kaynak kodu ve nasıl ayarlanmış bir darbe açıklaması içeren bir SourceForge projesi var . Sadece yukarıda açıklanan senaryonun ilk yarısını geçer ve tam olarak aynı sırayı takip etmez, ancak yine de 2-3 derecelik bir hız artışı elde eder.


3
Yukarıda özetlediğiniz adımların bazı ayrıntılarını okumak isterim. Lezzet optimizasyonunun bazı parçalarını dahil etmek mümkün müdür? (yazı çok uzun yapmadan?)
jerryjvl

8
... Ayrıca şu anda baskısı tükenmiş bir kitap da yazdım, bu yüzden Amazon'da gülünç bir fiyat kazanacak - "Daha İyi Uygulamalar İnşa Et" ISBN 0442017405. Esasen aynı materyal ilk bölümde.
Mike Dunlavey

3
@Mike Dunlavey, Google'a zaten taradığınızı söylemenizi öneririm. Muhtemelen yayıncıyı satın alan kişi ile zaten bir anlaşmaları vardır.
Thorbjørn Ravn Andersen

19
@ Thorbjørn: Sadece takip etmek için GoogleBooks ile bağlandım, tüm formları doldurdum ve basılı bir kopya gönderdim. Gerçekten gerçekten telif hakkına sahip olup olmadığımı soran bir e-posta aldım. Reuters tarafından satın alınan International Thompson tarafından satın alınan yayıncı Van Nostrand Reinhold ve onları aramaya veya e-posta ile göndermeye çalıştığımda kara bir delik gibi. Yani çok zor durumda - henüz gerçekten onu kovalayacak enerjim olmadı.
Mike Dunlavey


188

Öneriler:

  • Yeniden hesaplamak yerine ön hesaplama : göreceli olarak sınırlı girdi aralığına sahip hesaplamalar içeren döngüler veya tekrarlanan çağrılar, geçerli aralıktaki tüm değerler için bu hesaplamanın sonucunu içeren bir arama (dizi veya sözlük) yapmayı düşünün. girişleri. Ardından algoritma içinde basit bir arama kullanın.
    Aşağı taraflar : önceden hesaplanmış değerlerden birkaçı gerçekten kullanılırsa bu durum daha da kötüleşebilir, ayrıca arama önemli bir hafıza alabilir.
  • Kütüphane yöntemlerini kullanmayın : çoğu kütüphanenin çok çeşitli senaryolar altında doğru şekilde çalışması ve parametreler vb. Üzerinde boş denetimler gerçekleştirmesi gerekir. Bir yöntemi yeniden uygulayarak, tam olarak kullandığınız durumda geçerli değildir.
    Aşağı taraflar : ek kod yazmak, hatalar için daha fazla yüzey alanı anlamına gelir.
  • Kütüphane yöntemlerini kullanın : kendimle çelişmek için, dil kütüphaneleri sizden veya benden çok daha akıllı insanlar tarafından yazılır; daha iyi ve daha hızlı yaptılar. Gerçekten daha hızlı hale getiremezseniz kendiniz uygulamayın (yani: her zaman ölçün!)
  • Hile : bazı durumlarda probleminiz için kesin bir hesaplama olsa da, 'kesin' gerekmeyebilir, bazen bir yaklaşım 'yeterince iyi' ve anlaşmada çok daha hızlı olabilir. Kendinize sorun, cevabın% 1 oranında çıkması gerçekten önemli mi? % 5? % 10 bile?
    Aşağı taraflar : Şey ... cevap kesin olmayacak.

32
Ön hesaplama her zaman yardımcı olmaz ve bazen acıtabilir - arama tablonuz çok büyükse önbellek performansınızı öldürebilir.
Adam Rosenfield

37
Hile genellikle galibiyet olabilir. Çekirdekte 3x3 matris ile noktalı bir 3-vektör olan bir renk düzeltme sürecim vardı. CPU, çapraz terimlerin bir kısmını geride bırakan ve bunu yapmak için diğer tüm yollarla karşılaştırıldığında gerçek hızlı giden bir matrise sahipti, ancak sadece 4x4 matrisleri ve 4 şamandıralı vektörleri destekledi. Ekstra boş yuva etrafında taşınacak kodun değiştirilmesi ve hesaplamanın sabit noktadan kayan noktaya dönüştürülmesi, biraz daha az doğru ancak çok daha hızlı sonuç alınmasına izin verdi .
RBerteig

6
Hile, iç ürünlerin bazılarını dışarıda bırakan bir matris çarpımı kullanıyordu, bu da tek tek talimatların eşdeğer dizisinden bile daha hızlı tamamlanan tek bir CPU talimatı için mikrokodda uygulanmasını mümkün kıldı. Bu bir hile çünkü "doğru" cevap alamaz, sadece "yeterince doğru" bir cevap.
RBerteig

6
@RBerteig: "yeterince doğru", çoğu insanın benim deneyimimde kaçırdığı optimizasyon için bir fırsattır.
Martin Thompson

5
Her zaman herkesin sizden daha zeki olduğunu varsayamazsınız. Sonunda hepimiz profesyoneliz. Bununla birlikte, kullandığınız belirli bir kütüphanenin kalitesi nedeniyle ortamınıza ulaştığını ve ortamınıza ulaştığını varsayabilirsiniz, bu nedenle bu kütüphanenin yazımı çok kapsamlı olmalıdır, bunu sadece bu konuda uzmanlaşmış olmadığınız için yapamazsınız. ve aynı zamana yatırım yapmazsınız. Daha az akıllı olduğunuz için değil. Haydi.
v.oddou

164

Performansı daha fazla iyileştiremediğinizde - bunun yerine algılanan performansı iyileştirip iyileştiremeyeceğinize bakın .

FooCalc algoritmanızı daha hızlı hale getiremeyebilirsiniz, ancak genellikle uygulamanızı kullanıcıya daha duyarlı hale getirmenin yolları vardır.

Birkaç örnek:

  • kullanıcının ne isteyeceğini tahmin etmek ve o zamandan önce bunun üzerinde çalışmaya başlamak
  • sonuçları bir kerede değil, geldikçe görüntüleme
  • Doğru ilerleme ölçer

Bunlar programınızı daha hızlı hale getirmez, ancak kullanıcılarınızı sahip olduğunuz hızla daha mutlu edebilir.


27
Sonunda hızlanan bir ilerleme çubuğu, kesinlikle doğru olandan daha hızlı olarak algılanabilir. "İlerleme Çubuğunu Yeniden Düşünmek" (2007) Harrison, Amento, Kuznetsov ve Bell, bir grup kullanıcı üzerinde birden fazla çubuk türünü test eder ve ilerlemenin daha hızlı algılanabilmesi için işlemleri yeniden düzenlemenin bazı yollarını tartışır.
Emil Vikström

9
naxa, çoğu ilerleme çubuğu sahtedir çünkü bir akışın geniş çapta çok farklı basamaklarını tek bir yüzde olarak tahmin etmek zor veya bazen imkansızdır. Sadece% 99 oranında
takılan

138

Hayatımın çoğunu sadece bu yerde geçiriyorum. Geniş vuruşlar profil oluşturucunuzu çalıştırmak ve kaydetmesini sağlamaktır:

  • Önbellek özlüyor . Veri önbelleği, çoğu programdaki 1 numaralı durak kaynağıdır. Daha iyi konum için rahatsız edici veri yapılarını yeniden düzenleyerek önbellek isabet oranını artırın; boşa giden baytları (ve dolayısıyla boşa giden önbellek getirilerini) ortadan kaldırmak için yapıları ve sayısal türleri paketlemek; durakları azaltmak için mümkün olan her yerde verileri önceden getirin.
  • Yük isabet mağazaları . İşaretçi örtüşme ile ilgili derleyici varsayımları ve verinin bellek yoluyla bağlantısı kesilmiş kayıt kümeleri arasında taşındığı durumlar, bir yük işleminde tüm CPU boru hattının temizlenmesine neden olan belirli bir patolojik davranışa neden olabilir. Şamandıraların, vektörlerin ve ints'ların birbirlerine atıldığı yerleri bulun ve ortadan kaldırın. __restrictDerleyiciye diğer adlandırma konusunda söz vermek için bolca kullanın .
  • Mikrokodlu işlemler . Çoğu işlemcinin boru hattına bağlanamayan bazı işlemleri vardır, ancak bunun yerine ROM'da depolanan küçük bir altyordam çalıştırılır. PowerPC'deki örnekler, tamsayı çarpma, bölme ve değişkene göre kaydırmadır. Sorun, bu işlem yürütülürken tüm boru hattı ölü durur. Bu işlemlerin kullanımını ortadan kaldırmaya çalışın ya da en azından bunları oluşturucu boru hatlı operasyonlarına ayırın, böylece programınızın geri kalanı ne olursa olsun süperskalar gönderiden faydalanabilirsiniz.
  • Şube yanlış tahminleri . Bunlar boru hattını çok boşaltıyor. CPU'nun bir daldan sonra boruyu yeniden doldurmak için çok fazla zaman harcadığı durumları bulun ve daha sık tahmin etmesini sağlamak için varsa dal ipucu kullanın. Mümkün Ya da daha iyisi, koşullu-hamle ile dalları yerine özellikle kendi boru genellikle derin ve FCMP sonra durum bayrakları okuma kabini neden olabilir, çünkü kayan nokta işlemleri sonrasında.
  • Ardışık kayan nokta ops . Bu SIMD'yi yapın.

Ve yapmak istediğim bir şey daha var:

  • Derleyicinizi derleme listelerinin çıktısını alacak şekilde ayarlayın ve kodunuzdaki etkin nokta işlevleri için ne yaydığına bakın. "İyi bir derleyicinin sizin için otomatik olarak yapabilmesi gereken" tüm bu akıllı optimizasyonlar? Gerçek derleyiciniz bunları yapmaz. GCC'nin gerçekten WTF kodu verdiğini gördüm.

8
Çoğunlukla Intel VTune ve PIX kullanıyorum. C # 'a uyum sağlayabilecekleri hakkında bir fikir yok, ama gerçekten JIT soyutlama katmanına sahip olduğunuzda, bu optimizasyonların çoğu, önbellek yerini iyileştirmek ve belki de bazı şubelerden kaçınmak dışında, erişiminizin ötesinde.
Crashworks

6
Buna rağmen, JIT sonrası çıkışı kontrol etmek, JIT aşaması boyunca iyi optimize etmeyen herhangi bir yapı olup olmadığını anlamaya yardımcı olabilir ... çıkmaz çıksa bile soruşturma asla zarar veremez.
jerryjvl

5
Ben de dahil birçok insan gcc tarafından üretilen bu "wtf meclisi" ile ilgilenecektir. Sevgiler çok ilginç bir iş gibi geliyor :)
BlueRaja - Danny Pflughoeft

1
Examples on the PowerPC ...<- Yani, PowerPC'nin bazı uygulamaları. PowerPC bir CPU değil, bir ISA'dır.
Billy ONeal

1
@BillyONeal Modern x86 donanımında bile, imul boru hattını durdurabilir; bkz. "Intel® 64 ve IA-32 Mimarlar Optimizasyon Referans Kılavuzu" §13.3.2.3: "Tamsayı çarpma talimatı yürütmek için birkaç döngü gerektirir. Bir tamsayı çarpma talimatı ve başka bir uzun gecikme talimatı, Ancak, tamsayı çarpma talimatları, program sırasının gerekliliği nedeniyle diğer tek döngü tamsayı talimatlarının verilmesini engelleyecektir. " Bu nedenle, kelime hizalamalı dizi boyutları ve kullanmak genellikle daha iyidir lea.
Crashworks

78

Daha fazla donanım atın!


30
Sahada zaten mevcut olan donanımda çalışması beklenen bir yazılım varsa, daha fazla donanım her zaman bir seçenek değildir.
Doug T.

76
Tüketici yazılımı yapan birine çok yararlı bir cevap değil: Müşteri, "daha hızlı bir bilgisayar satın alın" dediğini duymak istemeyecek. Özellikle video oyun konsolu gibi bir şeyi hedeflemek için yazılım yazıyorsanız.
Crashworks

19
@ Çarpışmalar veya bu nedenle gömülü bir sistem. Son özellik nihayet geldiğinde ve ilk kart grubu zaten büküldüğünde, ilk etapta daha hızlı bir CPU kullanmanız gerektiğini keşfetme zamanı değil ...
RBerteig

71
Bir zamanlar büyük bir bellek sızıntısı olan bir programda hata ayıklamak zorunda kaldım - VM boyutu saatte yaklaşık 1Mb büyüdü. Bir meslektaşım tek yapmam gereken sabit bir hızda bellek eklemek olduğunu şaka yaptı . :)
j_random_hacker

9
Daha fazla donanım: ah evet vasat geliştiricinin yaşam çizgisi. Kaç kez duyduğumu bilmiyorum "başka bir makine ekle ve kapasiteyi iki katına çıkar!"
Olof Forshell

58

Diğer öneriler:

  • G / Ç'den Kaçının : Herhangi bir G / Ç (disk, ağ, bağlantı noktası vb.) Her zaman hesaplama yapan herhangi bir koddan çok daha yavaş olacaktır, bu nedenle kesinlikle ihtiyacınız olmayan herhangi bir G / Ç'den kurtulun.

  • G / Ç'yi öne taşı : Bir hesaplama için ihtiyacınız olacak tüm verileri önden yükleyin, böylece kritik bir algoritmanın çekirdeğinde tekrarlanan G / Ç beklemeleri olmaz (ve belki de sonuç olarak tekrarlanır) disk, tüm verileri tek bir isabetle yüklerken arama yapmaktan kaçınabilir).

  • Gecikme G / Ç : Hesaplama bitene kadar sonuçlarınızı yazmayın, veri yapısında saklayın ve daha sonra sıkı çalışma bittiğinde bir kerede dökün.

  • Dişli G / Ç : Yeterince cesur olanlar için, yüklemeyi paralel bir iş parçacığına taşıyarak 'I / O ön' veya 'Gecikme G / Ç'yi gerçek hesaplama ile birleştirin, böylece daha fazla veri yüklerken çalışabilirsiniz Zaten sahip olduğunuz verilerle ilgili bir hesaplamada veya bir sonraki veri grubunu hesaplarken, sonuçları aynı anda son gruptan yazabilirsiniz.


3
"IO'yu paralel bir iş parçacığına taşımanın" birçok platformda (örneğin Windows NT) eşzamansız IO olarak yapılması gerektiğini unutmayın.
Billy ONeal

2
G / Ç gerçekten kritik bir noktadır, çünkü yavaş ve büyük gecikmelere sahiptir ve bu tavsiyeyle daha hızlı olabilirsiniz, ancak yine de temelde kusurludur: Noktalar gecikme (gizli olması gerekir) ve sistem çağrısı ( G / Ç çağrılarının sayısını azaltarak azaltılması gerekir ). En iyi tavsiye: mmap()giriş için kullanın , uygun madvise()çağrılar yapın ve aio_write()büyük çıktı parçaları yazmak için kullanın (= birkaç MiB).
cmaster - eski haline monica

1
Bu son seçeneğin özellikle Java'da uygulanması oldukça kolaydır. Yazdığım uygulamalar için BÜYÜK performans artışı sağladı. Bir diğer önemli nokta (I / O'yu yukarı hareket ettirmekten daha fazlası) SIRA ve büyük blok I / O yapmaktır. Disk okuma süresi nedeniyle çok sayıda küçük okuma 1 büyük okumadan çok daha pahalıdır.
BobMcGee

Bir noktada, hesaplamadan önce tüm dosyaları geçici olarak bir RAM diskine taşıyarak ve daha sonra geri taşıyarak G / Ç'den kaçındım. Bu kirli, ancak G / Ç çağrılarını yapan mantığı kontrol etmediğiniz durumlarda yararlı olabilir.
MD

48

Performans sorunlarının birçoğu veritabanı sorunları içerdiğinden, sorguları ve saklı yordamları ayarlarken size bakmak için bazı özel şeyler vereceğim.

Çoğu veritabanında imleç kullanmaktan kaçının. Döngüden de kaçının. Çoğu zaman, veri erişimi kayıt işlemiyle kaydedilmemeli, ayar tabanlı olmalıdır. Bu, aynı anda 1.000.000 kayıt eklemek istediğinizde tek bir kayıt saklı yordamının yeniden kullanılmamasını içerir.

Asla select * kullanmayın, sadece gerçekten ihtiyacınız olan alanları döndürün. Birleştirme alanları tekrarlanacağından ve böylece hem sunucuda hem de ağda gereksiz yüke neden olacağından bu özellikle birleşimler için geçerlidir.

İlişkili alt sorguların kullanılmasından kaçının. (Mümkün olan durumlarda türetilmiş tablolara eklemeler dahil) birleşimleri kullanın (bunun Microsoft SQL Server için geçerli olduğunu biliyorum, ancak farklı bir arka uç kullanırken önerileri test edin).

Dizin, dizin, dizin. Veritabanınız için geçerliyse bu istatistikleri güncelleyin.

Sorguyu anlaşılır yapın . Yani benzer bir cümlenin ilk karakterinde joker karakter veya birleştirme işlevindeki bir fonksiyonda veya where deyiminin sol kısmı olarak dizinleri kullanmayı imkansız kılan şeylerden kaçının.

Doğru veri türlerini kullanın. Bir tarih alanında tarih matematiği yapmak, bir dize veri türünü bir tarih veri türüne dönüştürmek ve ardından hesaplamayı yapmak zorunda olmaktan daha hızlıdır.

Asla herhangi bir döngü yapmayın!

Çoğu veritabanının sorgu yürütme işleminin nasıl yapılacağını denetleme yolu vardır. Microsoft SQL Server'da buna yürütme planı denir. Sorunlu alanların nerede olduğunu görmek için önce bunları kontrol edin.

Sorgunun ne sıklıkta çalıştığını ve neyin optimize edilmesi gerektiğini belirlerken ne kadar süre çalışacağını düşünün. Bazen hafif bir değişiklikten günde milyonlarca kez çalışan bir sorguya, yalnızca ayda bir kez çalışan uzun bir sorgudan zaman kaybetmekten daha fazla performans kazanabilirsiniz.

Veritabanına ve veritabanından gerçekten neyin gönderildiğini bulmak için bir tür profiler aracı kullanın. Geçmişte bir kez hatırlıyorum nerede saklı yordam hızlı ve web sayfası bir kez yerine birçok kez sormak istediğini profilleme yoluyla öğrendim neden sayfanın yüklemek için bu kadar yavaş olduğunu anlayamadık.

Profiler ayrıca kimin kimi engellediğini bulmanıza da yardımcı olacaktır. Tek başına çalışırken hızlı bir şekilde yürütülen bazı sorgular, diğer sorguların kilitleri nedeniyle gerçekten yavaş olabilir.


29

Bugün en önemli sınırlayıcı faktör sınırlı bellek bant genişliği . Çoklu çekirdekler bunu daha da kötüleştiriyor çünkü bant genişliği çekirdekler arasında paylaşılıyor. Ayrıca, önbellek uygulamalarına ayrılmış sınırlı talaş alanı da çekirdekler ve dişler arasında bölünerek bu sorunu daha da kötüleştirir. Son olarak, farklı önbellekleri tutarlı tutmak için gereken çipler arası sinyalleşme, artan sayıda çekirdek ile de artar. Bu aynı zamanda bir ceza da ekler.

Bunlar yönetmeniz gereken etkilerdir. Bazen kodunuzu mikro yöneterek, bazen dikkatli bir şekilde düşünerek ve yeniden düzenleyerek.

Birçok yorum zaten önbellek dostu koddan bahsediyor. Bunun en az iki farklı lezzeti vardır:

  • Bellek getirme gecikmelerinden kaçının.
  • Daha düşük bellek veri yolu basıncı (bant genişliği).

İlk sorun, veri erişim kalıplarınızı daha düzenli hale getirmek ve donanım prefetcher'ın verimli çalışmasını sağlamakla ilgilidir. Veri nesnelerinizi belleğe yayan dinamik bellek ayırmadan kaçının. Bağlantılı listeler, karmalar ve ağaçlar yerine doğrusal kaplar kullanın.

İkinci sorun, verilerin yeniden kullanımının iyileştirilmesi ile ilgilidir. Algoritmalarınızı, kullanılabilir önbelleğe uyan verilerin alt kümeleri üzerinde çalışacak şekilde değiştirin ve bu verileri önbellekteyken mümkün olduğunca tekrar kullanın.

Verileri daha sıkı bir şekilde paketlemek ve tüm verileri sıcak döngülerdeki önbellek satırlarında kullandığınızdan emin olmak, bu diğer efektlerden kaçınmanıza yardımcı olur ve önbellekte daha yararlı verilerin yerleştirilmesine izin verir .


25
  • Hangi donanım üzerinde çalışıyorsunuz? Platforma özgü optimizasyonları (vektörleştirme gibi) kullanabilir misiniz?
  • Daha iyi bir derleyici alabilir misiniz? Örneğin, GCC'den Intel'e geçiş?
  • Algoritmanızı paralel çalıştırabilir misiniz?
  • Verileri yeniden düzenleyerek önbellek hatalarını azaltabilir misiniz?
  • Ekleri devre dışı bırakabilir misiniz?
  • Derleyiciniz ve platformunuz için mikro optimizasyon. "İf / else parametresinde en yaygın ifadeyi önce koy" tarzında

4
"GCC'den LLVM'ye geç" olmalı
Zifre

4
Algoritmanızı paralel çalıştırabilir misiniz? - tersi de geçerlidir
justin

4
Doğru, iplik miktarını azaltmak aynı derecede iyi bir optimizasyon olabilir
Johan Kotlinski

re: mikro optimizasyon: derleyicinin asm çıkışını kontrol ederseniz, genellikle daha iyi asm üretmek için kaynağı tutmak için kaynağı düzenleyebilirsiniz. Bkz Neden bu C ++ kod daha hızlı olduğunu benim elle yazılmış Collatz varsayım testi için montaj? modern x86'da derleyiciye yardım etme veya yenme hakkında daha fazla bilgi için.
Peter Cordes

17

Mike Dunlavey'in cevabını sevmeme rağmen, aslında destekleyici örnekle gerçekten harika bir cevap, bence çok basit bir şekilde ifade edilebilir:

Öncelikle en çok zaman alan şeyin ne olduğunu öğrenin ve nedenini anlayın.

Algoritmanızı nerede hassaslaştırmanız gerektiğini anlamanıza yardımcı olan zaman domuzlarının tanımlama sürecidir. Bu, zaten tamamen optimize edilmiş olması gereken bir soruna bulabildiğim, her şeyi kapsayan tek agnostik cevap. Ayrıca hız arayışınızda mimariden bağımsız olmak istediğinizi varsayalım.

Bu nedenle algoritma optimize edilebilirken, uygulanması mümkün olmayabilir. Tanımlama hangi parçanın hangisi olduğunu bilmenizi sağlar: algoritma veya uygulama. Bu yüzden, en çok zamanı hangisi seçerse, inceleme için birincil adayınızdır. Ancak, son birkaç% 'ı sıkıştırmak istediğinizi söylediğiniz için, daha önce incelediğiniz bölümleri daha az incelemek isteyebilirsiniz.

Son olarak, aynı çözümü ya da potansiyel olarak farklı algoritmaları uygulamak için farklı şekillerde performans rakamlarıyla ilgili biraz deneme yanılma, zaman kaybını ve zaman tasarrufunu tanımlamaya yardımcı olacak bilgiler getirebilir.

HPH, asoudmove.


16

Muhtemelen "Google perspektifini" düşünmelisiniz, yani uygulamanızın nasıl büyük ölçüde paralel ve eşzamanlı hale gelebileceğini belirlemelisiniz, bu da kaçınılmaz olarak aynı zamanda uygulamanızı farklı makineler ve ağlar arasında dağıtmaya bakmak anlamına gelir, böylece neredeyse doğrusal olarak ölçeklenebilir. attığınız donanım ile.

Öte yandan, Google millet, kullandıkları projelerde, araçlarda ve altyapıdaki bazı sorunları çözmek için çok sayıda insan gücü ve kaynak atmakla da bilinir; örneğin , özel bir mühendis ekibine sahip olarak gcc için tüm program optimizasyonu Google'a özgü kullanım senaryolarına hazırlamak için gcc dahili bilgilerini hacklemek.

Benzer şekilde, bir uygulamanın profilini oluşturmak artık program kodunu değil, aynı zamanda sistemin bakış açısından fazlalıkları ve optimizasyon potansiyelini tanımlamak için çevresindeki tüm sistemleri ve altyapıyı (düşünme ağları, anahtarlar, sunucu, RAID dizileri) profillemek anlamına gelir.


15
  • Satır içi rutinler (arama / geri dönüş ve parametre aktarmayı ortadan kaldırın)
  • Tablo aramalarıyla testleri / anahtarları kaldırmayı deneyin (daha hızlıysa)
  • Döngüleri (Duff'ın cihazı) sadece CPU önbelleğine sığacakları noktaya getirin
  • Önbelleğinizi patlatmamak için bellek erişimini yerelleştirin
  • Optimize edici bunu yapmadıysa ilgili hesaplamaları yerelleştirin
  • Optimize edici bunu yapmadıysa, döngü değişmezlerini ortadan kaldırın

2
IIRC Duff'ın cihazı çok nadiren daha hızlıdır. Sadece op çok kısa olduğunda (tek bir küçük matematik ifadesi gibi)
BCS

12
  • Verimli algoritmalar kullandığınız noktaya geldiğinizde, daha fazla hıza veya belleğe ihtiyacınız olan bir sorudur . Daha fazla hız için bellekte "ödeme" yapmak için önbellekleme kullanın veya bellek kapladığı alanı azaltmak için hesaplamalar kullanın.
  • Mümkünse (ve daha uygun maliyetli) donanımı sorun haline getirin - daha hızlı CPU, daha fazla bellek veya HD sorunu kodlamaya çalıştıktan sonra daha hızlı çözebilir.
  • Mümkünse paralelleştirme kullanın - kodun bir kısmını birden çok iş parçacığında çalıştırın.
  • İş için doğru aracı kullanın . bazı programlama dilleri yönetilen kod (Java / .NET gibi) kullanarak daha verimli kod oluşturur, ancak yerel programlama dilleri daha hızlı çalışan kod oluşturur.
  • Mikro optimizasyon . Yalnızca küçük kod parçalarını hızlandırmak için optimize edilmiş montaj kullanabilirsiniz, doğru yerlerde SSE / vektör optimizasyonlarını kullanmak performansı büyük ölçüde artırabilir.

12

Böl ve fethet

İşlenmekte olan veri kümesi çok büyükse, bunun parçaları üzerinde döngü yapın. Kodunuzu doğru yaptıysanız, uygulama kolay olmalıdır. Monolitik bir programınız varsa, şimdi daha iyi bilirsiniz.


9
Son cümleyi okurken duyduğum sineklik "şaplak" sesi için +1.
Bryan Boettcher

11

Her şeyden önce, önceki birkaç cevapta belirtildiği gibi, performansınızı neyin ısırdığını öğrenin - bellek veya işlemci veya ağ veya veritabanı veya başka bir şey. Buna bağlı olarak ...

  • ... hafızalıysa - "Bilgisayar Programlama Sanatı" serisinden Knuth'un uzun zaman önce yazdığı kitaplardan birini bulun. Büyük olasılıkla sıralama ve arama ile ilgili bir şeydir - hafızam yanlışsa, yavaş bant veri depolama ile nasıl başa çıkacağını öğrenmeniz gerekir. Zihinsel onun dönüşümü bellek / şerit önbellek / ana bellek için çift içine çift (ya da L1 / L2 önbellek çiftindeki) 'dir. Açıkladığı tüm hileleri inceleyin - sorununuzu çözen bir şey bulamazsanız, profesyonel bir araştırma yapmak için profesyonel bilgisayar bilimcisi kiralayın. Bellek sorununuz FFT ile şans eseri ise (radix-2 kelebekleri yaparken önbellek bit ters dizinlerde özlüyor) bir bilim adamı tutmayın - bunun yerine geçişleri siz ya kazan ya da çıkmaz ol. Bahsettinson yüzde birkaçına kadar sıkmak değil mi? E? Er birkaç gerçekten büyük olasılıkla kazanacak.

  • ... işlemci ise - montaj diline geçin. İşlemci belirtimini inceleyin - keneler , VLIW, SIMD. İşlev çağrıları büyük olasılıkla değiştirilebilir kene yiyicilerdir. Döngü dönüşümlerini öğrenin - boru hattı, açma. Çarpmalar ve bölümler bit kaydırmalarıyla değiştirilebilir / enterpolasyonlu olabilir (küçük tamsayılarla çarpmalar eklemelerle değiştirilebilir). Daha kısa veri içeren hileleri deneyin - eğer şanslıysanız 64 bitlik bir talimat, 32'de iki veya hatta 8 bitte 16 veya 8 ile değiştirilebilir olabilir. Daha uzun süre deneyinveriler - örneğin, float hesaplamalarınız belirli bir işlemcide iki kattan daha yavaş olabilir. Trigonometrik malzemeleriniz varsa, önceden hesaplanmış tablolarla savaşın; ayrıca, hassasiyet kaybı izin verilen sınırlar dahilindeyse, küçük değerli sinüsün bu değerle değiştirilebileceğini unutmayın.

  • ... ağ ise - veriyi sıkıştırmayı düşünün. XML aktarımını ikili ile değiştirin. Çalışma protokolleri. Veri kaybını bir şekilde halledebiliyorsanız, TCP yerine UDP'yi deneyin.

  • ... eğer veritabanı ise, herhangi bir veritabanı forumuna gidin ve tavsiye isteyin. Bellek içi veri ızgarası, sorgu planını optimize etme vb.

HTH :)


9

Önbelleğe almak! Neredeyse her şeyi daha hızlı hale getirmenin ucuz bir yolu (programcı çabasıyla), programınızın herhangi bir veri hareketi alanına bir önbellek soyutlama katmanı eklemektir. İster I / O ister sadece nesnelerin veya yapıların geçmesi / yaratılması. Genellikle fabrika sınıflarına ve okuyucu / yazıcılara önbellek eklemek kolaydır.

Bazen önbellek size çok fazla kazanç sağlamaz, ancak önbelleğe almayı eklemek ve ardından yardımcı olmadığı yerde devre dışı bırakmak için kolay bir yöntemdir. Bunu genellikle kodu mikro analiz etmek zorunda kalmadan büyük bir performans elde etmek için buldum.


8

Bunun daha önce farklı bir şekilde söylendiğini düşünüyorum. Ancak işlemci yoğun bir algoritma ile uğraşırken, en içteki döngüdeki her şeyi, her şey pahasına basitleştirmelisiniz.

Bu bazıları için açık gibi görünebilir, ancak çalıştığım dilden bağımsız olarak odaklanmaya çalıştığım bir şey. Örneğin, iç içe geçmiş döngülerle uğraşıyorsanız ve bazı kodları bir seviyeye çıkarma fırsatı bulursanız, bazı durumlarda kodunuzu büyük ölçüde hızlandırabilirsiniz. Başka bir örnek olarak, olabildiğince kayan nokta değişkenleri yerine tamsayılarla çalışmak ve mümkün olduğunda bölme yerine çarpma kullanmak gibi düşünülmesi gereken küçük şeyler vardır. Yine, bunlar en içsel döngü için dikkate alınması gereken şeyler.

Bazen matematik işlemlerinizi iç döngü içindeki bir tamsayı üzerinde gerçekleştirebilir ve daha sonra üzerinde çalışabileceğiniz bir kayan nokta değişkenine ölçeklendirebilirsiniz. Bu, başka bir bölümdeki hızı artırmak için bir bölümdeki hızı feda etmenin bir örneğidir, ancak bazı durumlarda ödeme buna değebilir.


8

Düşük bant genişliği ve uzun gecikmeli ağlar (örn. Uydu, uzaktan, offshore) üzerinden çalışan istemci / sunucu iş sistemlerini optimize etmek için biraz zaman harcadım ve oldukça tekrarlanabilir bir süreçle bazı dramatik performans iyileştirmeleri elde edebildim.

  • Tedbir : Ağın temel kapasitesini ve topolojisini anlayarak başlayın. İşletmedeki ilgili ağ insanlarıyla konuşmak ve tipik çalışma dönemlerinde her bir müşteri konumundan ağ gecikmesini (en azından) belirlemek için ping ve traceroute gibi temel araçları kullanın. Ardından, sorunlu belirtileri gösteren belirli son kullanıcı işlevlerinin doğru zaman ölçümlerini yapın. Tüm bu ölçümleri, konumları, tarihleri ​​ve saatleri ile birlikte kaydedin. İstemci uygulamanızda son kullanıcı "ağ performansı testi" işlevselliğini oluşturmayı ve ileri düzey kullanıcılarınızın iyileştirme sürecine katılmalarını sağlamayı düşünün; bu şekilde güçlendirmek , kötü performans gösteren bir sistem tarafından hayal kırıklığına uğramış kullanıcılarla uğraşırken büyük bir psikolojik etkiye sahip olabilir .

  • çözümlemek : Etkilenen işlemlerin yürütülmesi sırasında tam olarak hangi verilerin iletildiğini ve alındığını belirlemek için mevcut tüm günlük yöntemlerini kullanarak. İdeal olarak, uygulamanız hem istemci hem de sunucu tarafından iletilen ve alınan verileri yakalayabilir. Bunlar zaman damgalarını da içeriyorsa, daha da iyi. Yeterli günlük kaydı yoksa (örn. Kapalı sistem veya değişiklikleri üretim ortamına dağıtamama), bir ağ dinleyicisi kullanın ve ağ düzeyinde neler olduğunu gerçekten anladığınızdan emin olun.

  • Önbellek : Statik veya seyrek olarak değiştirilen verilerin tekrar tekrar iletildiği durumları arayın ve uygun bir önbellek stratejisini göz önünde bulundurun. Tipik örnekler, "iş listesi" değerlerini veya bazı iş uygulamalarında şaşırtıcı derecede büyük olabilecek diğer "referans varlıkları" içerir. Çoğu durumda, kullanıcılar, özellikle sık kullanılan kullanıcı arabirimi öğelerinin görüntülenmesinden önemli ölçüde zaman ayırabiliyorsa, nadiren güncellenen verileri güncellemek için uygulamayı yeniden başlatmaları veya yenilemeleri gerektiğini kabul edebilir. Önceden dağıtılan önbellek öğelerinin gerçek davranışını anladığınızdan emin olun - birçok yaygın önbellekleme yöntemi (örn. HTTP ETag) tutarlılığı sağlamak için hala bir ağ gidiş dönüşü gerektirir ve ağ gecikmesinin pahalı olduğu yerlerde, tüm bunlardan tamamen kaçınabilirsiniz. farklı bir önbellekleme yaklaşımı.

  • Paralel : Kesinlikle sıralı olarak mantıksal olarak verilmesi gerekmeyen sıralı işlemleri arayın ve paralel olarak yayınlamak için sistemi yeniden çalışın. Uçtan uca bir isteğin ~ 2s'lik doğal bir ağ gecikmesine sahip olduğu, tek bir işlem için sorun olmayan, ancak kullanıcı istemci uygulamasının kontrolünü yeniden ele geçirmeden önce 6 ardışık 2s gidiş-dönüş gerekli olduğunda bir durumla ilgilenmiştim. , büyük bir hayal kırıklığı kaynağı oldu. Bu işlemlerin aslında bağımsız olduğunu keşfetmek, paralel olarak yürütülmelerine izin vererek, son kullanıcı gecikmesini tek bir gidiş dönüş maliyetinin çok yakınına indirdi.

  • Birleştir : Sıralı isteklerin sırayla yürütülmesi gerektiğinde , bunları daha kapsamlı bir istekte birleştirmek için fırsatlar arayın. Tipik örnekler arasında yeni varlıkların oluşturulması ve ardından bu varlıkları diğer mevcut varlıklarla ilişkilendirme talepleri yer alır.

  • Sıkıştırma : Metinsel bir formu ikili bir formla değiştirerek veya gerçek sıkıştırma teknolojisini kullanarak yükün sıkıştırılmasından yararlanma fırsatları arayın. Birçok modern (yani on yıl içinde) teknoloji yığınları bunu neredeyse şeffaf bir şekilde destekler, bu yüzden yapılandırıldığından emin olun. Sıklıkla, sorunun bant genişliği yerine temelde gecikme olduğu, işlemin tek bir pakete sığmasına veya paket kaybından kaçınmasına ve dolayısıyla büyük bir boyuta sahip olmasından sonra ortaya çıktığı açıkça göründüğü durumlarda, sıkıştırmanın önemli etkisi beni şaşırttı. performans üzerindeki etkisi.

  • Tekrarla : Başlangıca geri dönün ve yapılan iyileştirmelerle işlemlerinizi (aynı konumlarda ve zamanlarda) yeniden ölçün, sonuçlarınızı kaydedin ve raporlayın. Tüm optimizasyonda olduğu gibi, bazı sorunlar şimdi baskın olan diğerlerini ortaya çıkararak çözülmüş olabilir.

Yukarıdaki adımlarda, uygulamaya ilişkin optimizasyon sürecine odaklanıyorum, ancak elbette temel ağın kendisinin de uygulamanızı desteklemek için en verimli şekilde yapılandırıldığından emin olmalısınız. Ağ uzmanlarını işletmeye dahil edin ve sorunu çözmek için kapasite geliştirmeleri, QoS, ağ sıkıştırma veya diğer teknikleri uygulayıp uygulayamayacaklarını belirleyin. Genellikle, uygulamanızın ihtiyaçlarını anlamazlar, bu nedenle onlarla görüşmek ve onlardan talep etmelerini isteyeceğiniz herhangi bir maliyet için iş durumunu yapmak için donanımlı olmanız (Analiz adımından sonra) önemlidir. . Hatalı ağ yapılandırmasının uygulama verilerinin bir karasal bağlantı yerine yavaş bir uydu bağlantısı üzerinden iletilmesine neden olduğu durumlarla karşılaştım, sadece ağ uzmanları tarafından "iyi bilinmeyen" bir TCP bağlantı noktası kullanması nedeniyle; açıkçası böyle bir sorunu düzeltmek, hiçbir yazılım kodu veya yapılandırma değişikliği gerekmeden performans üzerinde önemli bir etkiye sahip olabilir.


7

Bu soruya genel bir cevap vermek çok zor. Bu gerçekten sorun alanınıza ve teknik uygulamanıza bağlıdır. Dilde tarafsız olan genel bir teknik: Elde edilemeyen kod sıcak noktalarını tanımlayın ve montajcı kodunu elle optimize edin.


7

Son birkaç% çok CPU ve uygulama bağımlı bir şey ....

  • önbellek mimarileri farklıdır, bazı yongaların doğrudan haritalayabileceğiniz çip üzerinde RAM'i vardır, ARM'ler (bazen) bir vektör birimine sahiptir, SH4 kullanışlı bir matris opcode'dur. Bir GPU var mı - belki bir gölgelendirici gitmek için bir yoldur. TMS320'ler döngüler içindeki dallara karşı çok hassastır (bu nedenle ayrı döngüler ve mümkünse koşulları dışa taşıyın).

Liste uzayıp gidiyor ... Ama bu tür şeyler gerçekten son çare ...

X86 için derleyin ve doğru performans profili oluşturmak için koda Valgrind / Cachegrind komutunu çalıştırın . Veya Texas Instruments CCStudio'nun tatlı bir profili var. O zaman nereye odaklanacağınızı gerçekten bileceksiniz ...


7

Did you know that a CAT6 cable is capable of 10x better shielding off extrenal inteferences than a default Cat5e UTP cable?

Çevrimdışı olmayan herhangi bir projede, en iyi yazılım ve en iyi donanıma sahipken, veriminiz zayıfsa, o ince çizgi verileri sıkar ve milisaniye de olsa size gecikmeler verir ... ama son damlalardan bahsediyorsanız , gönderilen veya alınan herhangi bir paket için 7/24 kazanılan bazı damlalar.


7

Neredeyse önceki cevaplar kadar derin veya karmaşık değil, ama işte gidiyor: (bunlar daha başlangıç ​​/ orta seviye)

  • açık: kuru
  • döngüleri geriye doğru çalıştırın, böylece bir değişken yerine her zaman 0 ile karşılaştırırsınız
  • mümkün olduğunca bitsel operatörler kullanın
  • tekrarlayan kodu modüllere / fonksiyonlara bölmek
  • önbellek nesneleri
  • yerel değişkenlerin performans avantajı azdır
  • dize manipülasyonunu mümkün olduğunca sınırlayın

4
Geri döngü hakkında: evet, döngü sonu karşılaştırması daha hızlı olacaktır. Genellikle değişkeni belleğe endekslemek için kullanırsınız ve tersine erişmek sık sık önbellek gözden kaçırmaları nedeniyle ön üretken olabilir (ön getirme yok).
Andreas Reiff

1
AFAIK, çoğu durumda, herhangi bir makul iyileştirici, programcının açıkça tersine koşmasına gerek kalmadan döngülerle iyi sonuç verecektir. Optimize edici, döngünün kendisini tersine çevirir veya eşit derecede iyi başka bir yolu vardır. Maks. Vs'ye göre artan ve 0'a karşı azalan (kuşkusuz nispeten basit) döngüler için özdeş ASM çıktısı kaydettim. Tabii ki, Z80 günlerim geri dönüş döngüleri refleks olarak yazma alışkanlığım var, ancak yenilere bahsetmek genellikle bir kırmızı ringa balığı / erken optimizasyon, okunabilir kod ve daha önemli uygulamaların öğrenilmesi öncelikli olmalıdır.
underscore_d

Aksine, bir döngüyü geriye doğru çalıştırmak daha düşük seviyeli dillerde daha yavaş olacaktır, çünkü sıfıra kıyasla artı artı çıkarma arasında tek bir tam sayı karşılaştırmasına karşı bir savaşta, tek tam sayı karşılaştırması daha hızlıdır. Azaltmak yerine, bellekteki başlangıç ​​adresini ve bellekteki bitiş adresini gösteren bir işaretçiniz olabilir. Ardından, başlangıç ​​işaretçisini bitiş işaretçisine eşit olana kadar artırın. Bu, montaj kodundaki ekstra bellek ofseti işlemini ortadan kaldıracak ve böylece daha fazla performans gösterecektir.
Jack Giffin

5

Söylemesi imkansız. Kodun nasıl göründüğüne bağlıdır. Kodun zaten var olduğunu varsayabilirsek, basitçe ona bakabilir ve bundan nasıl optimize edeceğimizi anlayabiliriz.

Daha iyi önbellek konumu, döngü çözme, daha iyi talimat düzeyinde paralellik elde etmek için uzun bağımlılık zincirlerini ortadan kaldırmaya çalışın. Mümkün olduğunda dallar üzerinde koşullu hareketleri tercih edin. Mümkün olduğunda SIMD talimatlarını kullanın.

Kodunuzun ne yaptığını ve üzerinde çalıştığı donanımı anlayın. Ardından, kodunuzun performansını artırmak için ne yapmanız gerektiğini belirlemek oldukça basit hale gelir. Bu gerçekten aklıma gelen tek genel tavsiye.

Peki, bu ve "SO kodunu göster ve söz konusu kod parçası için optimizasyon önerisi isteyin".


5

Daha iyi bir donanım bir seçenek ise, kesinlikle bunun için gidin. Aksi takdirde

  • En iyi derleyici ve bağlayıcı seçeneklerini kullandığınızdan emin olun.
  • Hotspot rutini farklı kütüphanede sık arayana geliyorsa, onu arayanlar modülüne taşımayı veya klonlamayı düşünün. Bazı çağrı yükünü ortadan kaldırır ve önbellek isabetlerini geliştirebilir (AIX'nin strcpy () öğesini statik olarak ayrı olarak bağlı paylaşılan nesnelere nasıl bağladığı). Bu elbette önbellek isabetlerini de azaltabilir, bu yüzden bir önlem.
  • Etkin nokta yordamının özel bir sürümünü kullanma olasılığının olup olmadığına bakın. Dezavantajı korumak için birden fazla sürümdür.
  • Montajcıya bak. Daha iyi olabileceğini düşünüyorsanız, derleyicinin bunu neden çözmediğini ve derleyiciye nasıl yardımcı olabileceğinizi düşünün.
  • Şunu düşünün: Gerçekten en iyi algoritmayı mı kullanıyorsunuz? Girdi boyutunuz için en iyi algoritma mı?

Ben ilk par ekleyin . Derleyici seçenekleri tüm hata ayıklama bilgilerini kapatmayı unutmayın .
varnie

5

Google yolu bir seçenek "Önbellek .. Mümkün olduğunda diske dokunmayın"


5

İşte kullandığım bazı hızlı ve kirli optimizasyon teknikleri. Bunun bir 'ilk geçiş' optimizasyonu olduğunu düşünüyorum.

Zamanın nerede harcandığını öğrenin tam olarak ne olduğunu . IO dosyası mı? CPU zamanı mı? Ağ mı? Veritabanı mı? Bu darboğaz değilse IO için optimize etmek işe yaramaz.

Ortamınızı Tanıyın Tanıyın Nerede optimizasyon yapacağınızı bilmek genellikle geliştirme ortamına bağlıdır. Örneğin, VB6'da referans ile geçiş, değere göre geçmekten daha yavaştır, ancak C ve C ++ 'da referans olarak çok daha hızlıdır. C'de, bir dönüş kodu bir hata gösteriyorsa bir şey denemek ve farklı bir şey yapmak mantıklıdır, Dot Net'te ise, istisnaları yakalamak denemeden önce geçerli bir durumu kontrol etmekten çok daha yavaştır.

Dizinler Sık sorulan veritabanı alanlarında dizin oluşturun. Neredeyse her zaman hız için alan ticareti yapabilirsiniz.

Aramalardan kaçının Optimize edilecek döngünün içinde, herhangi bir arama yapmak zorunda kalmam. Döngünün dışındaki ofseti ve / veya dizini bulun ve içindeki verileri yeniden kullanın.

ES'yi , özellikle bir ağ bağlantısı üzerinden okuma veya yazma sayısını azaltacak şekilde tasarlamaya çalışın

Soyutlamaları Azalt Kodun üzerinde daha fazla soyutlama katmanı bulunması gerektiğinde, yavaşlar. Kritik döngünün içinde soyutlamaları azaltın (örn. Ekstra koddan kaçınan daha düşük seviye yöntemleri ortaya çıkarın)

Kullanıcı arabirimine sahip projeler için Spawn Threads , daha yavaş görevleri önceden gerçekleştirmek için yeni bir thread oluşturmak, uygulamanın daha duyarlı hissetmesini sağlar , ancak olmasa da.

Ön işlem Genel olarak hız için yer takas edebilirsiniz. Hesaplamalar veya başka yoğun işlemler varsa, kritik döngüye girmeden önce bazı bilgileri önceden hesaplayıp hesaplayamayacağınıza bakın.


5

Çok yüksek derecede paralel kayan nokta matematiğiniz varsa, özellikle de tek duyarlıklı-OpenCL veya (NVidia yongaları için) CUDA kullanarak bir grafik işlemcisine (varsa) yüklemeyi deneyin. GPU'lar gölgelendiricilerinde CPU'nunkinden çok daha büyük kayan nokta hesaplama gücüne sahiptir.


5

Diğerlerine dahil olduğunu görmedim beri bu cevabı ekleyerek.

Türler ve işaretler arasındaki örtük dönüşümü en aza indirin:

Zaten olsa bile bu, en azından C / C ++ için de geçerlidir düşünüyorum dönüşümden arınmış - bazen performans gerektiren işlevlerin, özellikle de döngülerdeki dönüşümlere dikkat etmenin etrafına derleyici uyarıları eklemeyi test etmek iyidir.

GCC Spesific: Kodunuzun etrafına ayrıntılı pragmalar ekleyerek bunu test edebilirsiniz,

#ifdef __GNUC__
#  pragma GCC diagnostic push
#  pragma GCC diagnostic error "-Wsign-conversion"
#  pragma GCC diagnostic error "-Wdouble-promotion"
#  pragma GCC diagnostic error "-Wsign-compare"
#  pragma GCC diagnostic error "-Wconversion"
#endif

/* your code */

#ifdef __GNUC__
#  pragma GCC diagnostic pop
#endif

Bunun gibi uyarıların neden olduğu dönüşümleri azaltarak yüzde birkaç hız kazanabileceğiniz durumlar gördüm.

Bazı durumlarda, yanlışlıkla yapılan dönüşümleri önlemek için dahil ettiğim katı uyarılara sahip bir başlığım var, ancak bu kod bir koddur. kazançlar.


İşte bu yüzden OCaml'de, sayısal türler arasında döküm xplicit olmalıdır.
Gaius

@Gaius adil noktası - ancak çoğu durumda dil değiştirmek gerçekçi bir seçim değildir. C / C ++ çok yaygın olarak kullanıldığından, derleyiciye özgü olsa bile onları daha katı hale getirmek için yararlıdır.
ideasman42

4

Bazen verilerinizin düzenini değiştirmek yardımcı olabilir. C dilinde, bir diziden veya yapılardan dizilerin yapısına veya tam tersine geçiş yapabilirsiniz.


4

İşletim sistemini ve çerçeveyi değiştirin.

Kulağa aşırı gelebilir ama şöyle düşünün: İşletim Sistemleri ve Çerçeveler pek çok şey yapmak için tasarlanmıştır. Başvurunuz yalnızca çok özel şeyler yapar. İşletim sisteminin uygulamanızın tam olarak neye ihtiyacı olduğunu yapabilmesini ve uygulamanızın çerçevenin (php, .net, java) nasıl çalıştığını anlamasını sağlayabiliyorsanız, donanımınızdan çok daha iyi olabilirsiniz.

Örneğin, Facebook bazılarını değiştirdi Linux'ta çekirdek düzeyi şeylerini değiştirdi, memcached'ın çalışma şeklini değiştirdi (örneğin, memcached proxy yazdılar ve tcp yerine udp kullandılar ).

Bunun bir başka örneği Window2008'dir. Win2K8'in sadece X uygulamalarını çalıştırmak için gereken temel işletim sistemini (ör. Web Uygulamaları, Sunucu Uygulamaları) yükleyebileceğiniz bir sürümü vardır. Bu, işletim sisteminin çalışan işlemlerde sahip olduğu ek yükü azaltır ve size daha iyi performans sağlar.

Tabii ki, her zaman ilk adım olarak daha fazla donanım atmalısınız ...


2
Bu, diğer tüm yaklaşımlar başarısız olduktan sonra veya belirli bir işletim sistemi veya Çerçeve özelliğinin belirgin şekilde azalmış performanstan sorumlu olması durumunda geçerli bir yaklaşım olurdu, ancak bunu kaldırmak için gereken uzmanlık ve kontrol düzeyi her proje için mevcut olmayabilir.
Ne11
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.