Satır içi derleme dili yerel C ++ kodundan daha yavaş mı?


183

Satır içi derleme dili ve C ++ kodu performansını karşılaştırmaya çalıştım, bu yüzden 100000 kez iki boyutlu 2000 dizileri ekleyen bir işlev yazdım. İşte kod:

#define TIMES 100000
void calcuC(int *x,int *y,int length)
{
    for(int i = 0; i < TIMES; i++)
    {
        for(int j = 0; j < length; j++)
            x[j] += y[j];
    }
}


void calcuAsm(int *x,int *y,int lengthOfArray)
{
    __asm
    {
        mov edi,TIMES
        start:
        mov esi,0
        mov ecx,lengthOfArray
        label:
        mov edx,x
        push edx
        mov eax,DWORD PTR [edx + esi*4]
        mov edx,y
        mov ebx,DWORD PTR [edx + esi*4]
        add eax,ebx
        pop edx
        mov [edx + esi*4],eax
        inc esi
        loop label
        dec edi
        cmp edi,0
        jnz start
    };
}

İşte main():

int main() {
    bool errorOccured = false;
    setbuf(stdout,NULL);
    int *xC,*xAsm,*yC,*yAsm;
    xC = new int[2000];
    xAsm = new int[2000];
    yC = new int[2000];
    yAsm = new int[2000];
    for(int i = 0; i < 2000; i++)
    {
        xC[i] = 0;
        xAsm[i] = 0;
        yC[i] = i;
        yAsm[i] = i;
    }
    time_t start = clock();
    calcuC(xC,yC,2000);

    //    calcuAsm(xAsm,yAsm,2000);
    //    for(int i = 0; i < 2000; i++)
    //    {
    //        if(xC[i] != xAsm[i])
    //        {
    //            cout<<"xC["<<i<<"]="<<xC[i]<<" "<<"xAsm["<<i<<"]="<<xAsm[i]<<endl;
    //            errorOccured = true;
    //            break;
    //        }
    //    }
    //    if(errorOccured)
    //        cout<<"Error occurs!"<<endl;
    //    else
    //        cout<<"Works fine!"<<endl;

    time_t end = clock();

    //    cout<<"time = "<<(float)(end - start) / CLOCKS_PER_SEC<<"\n";

    cout<<"time = "<<end - start<<endl;
    return 0;
}

Sonra zaman olarak görülebilen işlemci döngülerini almak için programı beş kez çalıştırıyorum. Her seferinde sadece yukarıda belirtilen işlevlerden birini çağırıyorum.

Ve işte sonuç geliyor.

Montaj sürümü fonksiyonu:

Debug   Release
---------------
732        668
733        680
659        672
667        675
684        694
Average:   677

C ++ sürümünün işlevi:

Debug     Release
-----------------
1068      168
 999      166
1072      231
1002      166
1114      183
Average:  182

Serbest bırakma modundaki C ++ kodu, montaj kodundan neredeyse 3.7 kat daha hızlıdır. Neden?

Yazdığım montaj kodunun GCC tarafından üretilen kod kadar etkili olmadığını düşünüyorum. Benim gibi ortak bir programcının kodunu bir derleyici tarafından üretilen rakibinden daha hızlı yazması zor.


29
Neredeyse. El ile kodlanmış montaj bazı durumlarda uygundur, ancak montaj versiyonunun gerçekten daha yüksek bir dil ile elde edilebilecek olandan daha hızlı olmasına dikkat edilmelidir.
Magnus Hoff

161
Derleyici tarafından oluşturulan kodu incelemeyi ve neden derleme sürümünüzden daha hızlı olduğunu anlamaya çalışmayı öğretici bulabilirsiniz.
Paul R

34
Evet, derleyici yazma konusunda senden daha iyi görünüyor. Modern derleyiciler gerçekten çok iyi.
David Heffernan

20
GCC'nin ürettiği meclise baktınız mı? Olası GCC, MMX talimatlarını kullandı. İşleviniz çok paralel - toplamı 1 / N olarak hesaplamak için N işlemciyi kullanabilirsiniz. Paralelleştirme umudu olmayan bir işlevi deneyin.
Chris

11
Hm, iyi bir derleyicinin bunu yapmasını
beklerdim

Yanıtlar:


261

Evet, çoğu zaman.

Her şeyden önce, düşük seviyeli bir dilin (bu durumda montaj) her zaman yüksek seviyeli dilden daha hızlı kod üreteceği (bu durumda C ++ ve C) yanlış varsayımdan başlarsınız. Bu doğru değil. C kodu her zaman Java kodundan daha mı hızlı? Hayır, çünkü başka bir değişken var: programcı. Kod ve mimari detay bilgisini yazma şekliniz performansı büyük ölçüde etkiler (bu durumda gördüğünüz gibi).

Her zaman el yapımı montaj kodunun derlenmiş koddan daha iyi olduğu bir örnek üretebilirsiniz, ancak genellikle kurgusal bir örnek veya 500.000+ satırlık C ++ kodunun gerçek bir programı olmayan tek bir rutindir ). Derleyiciler% 95 daha iyi montaj kodu üreteceklerini düşünüyorlar ve bazen, sadece bazı nadir zamanlarda, birkaç, kısa, çok kullanılan , performans açısından kritik rutinler için veya en sevdiğiniz üst düzey dilin özelliklerine erişmeniz gerektiğinde montaj kodu yazmanız gerekebilir. açığa vurmaz. Bu karmaşıklığa bir dokunuş ister misiniz? SO'daki bu harika cevabı buradan okuyun .

Neden bu?

Her şeyden önce, derleyiciler hayal bile edemeyeceğimiz optimizasyonlar yapabiliyorlar ( bu kısa listeye bakın ) ve saniyeler içinde yapacaklar ( günlere ihtiyacımız olduğunda ).

Montajda kod yazarken, iyi tanımlanmış çağrı arabirimi ile iyi tanımlanmış işlevler yapmanız gerekir. Ancak , kayıt tahsisi , sabit yayılım , ortak alt ifade ortadan kaldırılması , talimat çizelgeleme ve diğer karmaşık, açık olmayan optimizasyonlar gibi tüm program optimizasyonunu ve prosedürler arası optimizasyonu hesaba katabilirler ( örneğin, Polytope modeli ). On RISC mimarisi adamlar (örneğin çok zor talimat zamanlama bu yıllar önce endişesi durdu elle ayar ) ve modern CISC CPU'lar çok uzun olması boru hatlarını çok.

Bazı karmaşık mikrodenetleyiciler için sistem kütüphaneleri bile montaj yerine C dilinde yazılır, çünkü derleyicileri daha iyi (ve bakımı kolay) bir son kod üretir.

Derleyiciler bazen bazı MMX / SIMDx talimatlarını kendileri otomatik olarak kullanabilir ve bunları kullanmazsanız karşılaştıramazsınız (diğer cevaplar montaj kodunuzu zaten çok iyi inceledi). Sadece döngüler için bu bir olan döngü optimizasyonlar kısa liste neyin yaygın bir derleyici tarafından denetlenir (programınıza bir C # programı için karar verildi zaman kendiniz yapabileceğini düşünüyorsun?) Eğer montaj içinde bir şeyler yazmak, ben en azından bazı basit optimizasyonları göz önünde bulundurmanız gerektiğini düşünüyoruz . Diziler için okul kitabı örneği döngüyü açmaktır (boyutu derleme zamanında bilinir). Yap ve testini tekrar yap.

Bu günlerde montaj dilini başka bir nedenden dolayı kullanmak da çok nadir: farklı CPU'ların bolluğu . Hepsini desteklemek ister misin? Her birinin kendine özgü bir mikro mimarisi ve bazı özel talimat setleri vardır . Farklı sayıda fonksiyonel üniteye sahiptirler ve hepsini meşgul edecek montaj talimatları düzenlenmelidir . C'de yazarsanız, PGO kullanabilirsiniz, ancak montajda bu belirli mimari hakkında büyük bir bilgiye ihtiyacınız olacaktır (ve başka bir mimari için her şeyi yeniden düşünün ve yeniden yapın ). Küçük görevler için derleyici genellikle daha iyisini yapar ve karmaşık görevler için genellikle iş geri ödenmez (vederleyici olabilir iyisini ) neyse.

Oturursanız ve kodunuza bakarsanız, muhtemelen algoritmanızı yeniden tasarlamak için derlemeye çevirmekten (SO'daki bu harika yayını okuyun) daha fazla kazanacağınızı göreceksiniz , üst düzey optimizasyonlar var (ve derleyici ipuçları) derleme diline başvurmadan önce etkili bir şekilde başvurabilirsiniz. Muhtemelen intrinsics'i kullanarak aradığınız performans kazancına sahip olacağınızı ve derleyicinin hala optimizasyonlarının çoğunu gerçekleştirebileceğini belirtmek gerekir.

Tüm bunlar, 5 ~ 10 kat daha hızlı bir montaj kodu üretebildiğinizde bile, müşterilerinize zamanınızın bir haftasını ödemeyi mi yoksa 50 $ daha hızlı bir CPU almayı mı tercih ettiklerini sormalısınız . Çoğu zaman bizden (ve özellikle LOB uygulamalarında) aşırı optimizasyon gerekli değildir.


9
Tabii ki değil. Sanırım% 99 oranında insanların% 95'inden daha iyi. Bazen sadece maliyetli ( karmaşık matematik nedeniyle ) veya zaman harcaması (daha sonra tekrar maliyetli) olduğu için. Bazen optimizasyonları unuttuğumuz için ...
Adriano Repetti

62
@ ja72 - hayır, kod yazarken daha iyi değil . Kodu optimize etmek daha iyidir .
Mike Baranczak

14
Gerçekten düşünene kadar sezgiseldir. Aynı şekilde, VM tabanlı makineler, derleyicilerin yapacak bilgiye sahip olmadığı çalışma zamanı optimizasyonları yapmaya başlıyor.
Bill K

6
@ M28: Derleyiciler aynı talimatları kullanabilir. Elbette, ikili boyut açısından ödeme yapıyorlar (çünkü bu talimatlar desteklenmediği takdirde bir geri dönüş yolu sağlamak zorundalar). Ayrıca, çoğunlukla eklenecek olan "yeni talimatlar", hem VM'lerin hem de Derleyicilerin kullanımında oldukça korkunç olduğu SMID talimatlarıdır. VM'ler bu özelliği, başlangıçta kodu derlemek zorunda oldukları için öderler.
Billy ONeal

9
@BillK: PGO derleyiciler için de aynı şeyi yapıyor.
Billy ONeal

194

Montaj kodunuz yetersizdir ve geliştirilebilir:

  • İç döngünüzde bir kaydı ( EDX ) itiyor ve patlatıyorsunuz . Bu döngüden çıkarılmalıdır.
  • Dizi işaretleyicilerini döngünün her yinelemesinde yeniden yüklersiniz. Bu döngüden çıkarılmalıdır.
  • Çoğu modern CPU'da yavaşloop olduğu bilinen talimatı kullanıyorsunuz (muhtemelen eski bir montaj kitabı kullanmanın bir sonucu *)
  • Manuel döngü açma işleminden faydalanamazsınız.
  • Kullanılabilir SIMD talimatlarını kullanmazsınız.

Dolayısıyla, montajcı ile ilgili beceri setinizi büyük ölçüde geliştirmediğiniz sürece, performans için montajcı kodu yazmanız mantıklı değildir.

* Elbette loopeski bir montaj kitabından gerçekten talimat alıp almadığınızı bilmiyorum . Ancak neredeyse hiçbir zaman gerçek dünya kodunda göremezsiniz, çünkü her derleyici yayılmayacak kadar akıllıdır loop, sadece IMHO kötü ve modası geçmiş kitaplarda görürsünüz.


loopboyutu için optimize ederseniz derleyiciler hala yayılabilir (ve birçok "kullanımdan kaldırıldı" talimatları)
phuclv

1
@phuclv iyi evet, ama orijinal soru tam olarak hız değil, boyut hakkındaydı.
IGR94

60

Birleştirme işlemine başlamadan önce bile, daha yüksek bir düzeyde var olan kod dönüşümleri vardır.

static int const TIMES = 100000;

void calcuC(int *x, int *y, int length) {
  for (int i = 0; i < TIMES; i++) {
    for (int j = 0; j < length; j++) {
      x[j] += y[j];
    }
  }
}

Döngü Rotasyonu ile dönüştürülebilir :

static int const TIMES = 100000;

void calcuC(int *x, int *y, int length) {
    for (int j = 0; j < length; ++j) {
      for (int i = 0; i < TIMES; ++i) {
        x[j] += y[j];
      }
    }
}

bu da bellek yerleşimi kadar iyi.

Bu daha da optimize edilebilir, a += bX kez yapmak yapmaya eşdeğerdir, a += X * bböylece şunu elde ederiz:

static int const TIMES = 100000;

void calcuC(int *x, int *y, int length) {
    for (int j = 0; j < length; ++j) {
      x[j] += TIMES * y[j];
    }
}

ancak favori optimizerim (LLVM) bu dönüşümü gerçekleştirmiyor gibi görünüyor.

[değiştir] biz olsaydı dönüşüm yapılır bulundu restrictetmek eleme xve y. Gerçekten de bu kısıtlama olmadan x[j]ve y[j]aynı dönüşümü hatalı hale getiren aynı yere takma olabilir. [düzenlemeyi bitir]

Neyse, bu , ben, optimize edilmiş C versiyonunu düşünüyorum. Zaten çok daha basit. Buna dayanarak, ASM'deki çatlakım (Clang'ın üretmesine izin verdim, işe yaramazım):

calcuAsm:                               # @calcuAsm
.Ltmp0:
    .cfi_startproc
# BB#0:
    testl   %edx, %edx
    jle .LBB0_2
    .align  16, 0x90
.LBB0_1:                                # %.lr.ph
                                        # =>This Inner Loop Header: Depth=1
    imull   $100000, (%rsi), %eax   # imm = 0x186A0
    addl    %eax, (%rdi)
    addq    $4, %rsi
    addq    $4, %rdi
    decl    %edx
    jne .LBB0_1
.LBB0_2:                                # %._crit_edge
    ret
.Ltmp1:
    .size   calcuAsm, .Ltmp1-calcuAsm
.Ltmp2:
    .cfi_endproc

Korkarım ki tüm bu talimatların nereden geldiğini anlamıyorum, ancak her zaman eğlenebilir ve nasıl karşılaştırıldığını deneyebilirsiniz ... ama yine de kodda birleştirme yerine optimize edilmiş C sürümünü kullanırdım, çok daha taşınabilir.


Cevabınız için teşekkürler.Peki, "Derleyici ilkeleri" adlı sınıfı aldığımda, derleyicinin kodumuzu birçok yolla optimize edeceğini öğrendim biraz kafa karıştırıcı. Bu, kodumuzu manuel olarak optimize etmemiz gerektiği anlamına mı geliyor? Derleyiciden daha iyi bir iş yapabilir miyiz? Beni hep şaşırtan soru bu.
user957121

2
@ user957121: daha fazla bilgiye sahip olduğumuzda daha iyi optimize edebiliriz. Özellikle burada neyi derleyici engelleyen mümkündür örtüşme arasındaki xve y. Olduğundan, derleyici emin herkes için bu olamaz i,jiçinde [0, length)biz var x + i != y + j. Çakışma varsa, optimizasyon mümkün değildir. C dilirestrict , derleyiciye iki göstergenin takma ad kullanamayacağını söylemek anahtar kelimeyi , ancak diziler için çalışmaz, çünkü tam olarak takma ad olmasalar bile yine de üst üste gelebilirler.
Matthieu M.8

Geçerli GCC ve Clang otomatik vektörleştirir (atlarsanız çakışma olmadığını kontrol ettikten sonra __restrict). SSE2, x86-64 için temel teşkil eder ve karıştırma ile SSE2 aynı anda 2x 32 bit çarpma yapabilir (64 bit ürünler üretmek, dolayısıyla sonuçları tekrar bir araya getirmek için karıştırma). godbolt.org/z/r7F_uo . (SSE4.1 için gereklidir pmulld: paketli 32x32 => 32-bit çarpma). GCC, sabit tamsayı çarpanlarını shift / add'e (ve / veya çıkartmaya) dönüştürmek için düzgün bir hile yapar, bu da birkaç bit ayarlanmış çarpanlar için iyidir. Clang'ın ağır karıştırma kodu, Intel CPU'larındaki karışık çalma hızı üzerinde darboğaz oluşturacak.
Peter Cordes

41

Kısa cevap: evet.

Uzun cevap: evet, ne yaptığınızı gerçekten bilmiyorsanız ve bunu yapmak için bir nedeniniz yoksa.


3
ve sonra yalnızca bir şeyleri geliştirmek için Intel yongaları için vtune gibi bir montaj düzeyinde profil oluşturma aracı çalıştırdıysanız
Mark Mullin

1
Bu, teknik olarak soruyu cevaplar, ancak tamamen işe yaramaz. Benden bir -1.
Navin

2
Çok uzun cevap: "Evet, yeni (er) bir CPU kullanıldığında tüm kodunuzu değiştirmek istemiyorsanız. En iyi algoritmayı seçin, ancak derleyicinin optimizasyonu yapmasına izin verin"
Tommylee2k

35

Asm kodumu düzelttim:

  __asm
{   
    mov ebx,TIMES
 start:
    mov ecx,lengthOfArray
    mov esi,x
    shr ecx,1
    mov edi,y
label:
    movq mm0,QWORD PTR[esi]
    paddd mm0,QWORD PTR[edi]
    add edi,8
    movq QWORD PTR[esi],mm0
    add esi,8
    dec ecx 
    jnz label
    dec ebx
    jnz start
};

Sürüm sürümü için sonuçlar:

 Function of assembly version: 81
 Function of C++ version: 161

Serbest bırakma modundaki montaj kodu C ++ 'dan neredeyse 2 kat daha hızlıdır.


18
Şimdi MMX yerine SSE kullanmaya başlarsanız (kayıt adı xmm0yerine mm0), iki ;-)
Gunther Piez

8
Değiştim, montaj sürümü için 41 aldım. 4 kat daha hızlı :)
sasha

3
Ayrıca tüm xmm kayıtlarını kullanırsanız% 5'e kadar daha fazla alabilirsiniz
sasha

7
Şimdi sizi gerçekten düşündüğü zamanı düşünüyorsanız: montaj, yaklaşık 10 saat mi? C ++, birkaç dakika sanırım? Performans açısından kritik bir kod olmadığı sürece burada açık bir kazanan var.
Calimo

1
İyi bir derleyici zaten ile otomatik vektörleştirecektir paddd xmm( xve arasında çakışma olup yolmadığını kontrol ettikten sonra int *__restrict x). Örneğin gcc bunu yapar: godbolt.org/z/c2JG0- . Veya satır içine girdikten sonra main, üst üste binmeyi kontrol etmesine gerek yoktur çünkü tahsisi görebilir ve üst üste binmediklerini kanıtlayabilir. (Ve bazı x86-64 uygulamalarında da 16 baytlık bir hizalama varsayılır, bu da tek başına tanım için geçerli değildir.) Ve derlerseniz gcc -O3 -march=native, 256 bit veya 512 bit alabilirsiniz vectorization.
Peter Cordes

24

Bu, ellerim tarafından yazılmış montaj dilinin performansına güvenmemem gerektiği anlamına mı geliyor?

Evet, tam olarak anlamı budur ve her dil için doğrudur . X dilinde verimli kod yazmayı bilmiyorsanız, X'te verimli kod yazma yeteneğinize güvenmemelisiniz. Bu nedenle, verimli kod istiyorsanız, başka bir dil kullanmalısınız.

Meclis buna özellikle duyarlıdır, çünkü gördüğünüz şey elde ettiğiniz şeydir. CPU'nun yürütmesini istediğiniz belirli yönergeleri yazarsınız. Yüksek seviyeli dillerde, betweeen'de, kodunuzu dönüştürebilen ve birçok verimsizliği kaldırabilen bir derleyici vardır. Montajla, tek başınasınız.


2
Özellikle modern bir x86 işlemci için, her bir çekirdeğin içinde boru hatları, çoklu yürütme birimleri ve diğer hileların varlığı nedeniyle verimli montaj kodu yazmanın son derece zor olduğunu düşünüyorum. En yüksek yürütme hızını elde etmek için tüm bu kaynakların kullanımını dengeleyen bir kod yazmak, genellikle "geleneksel" montaj bilgeliğine göre "hızlı" olmaması gereken, mantıksız bir mantıkla kodla sonuçlanır. Ancak daha az karmaşık CPU'lar için, C derleyicisinin kod üretiminin önemli ölçüde iyileştirilebileceği tecrübem.
Olof Forshell

4
C derleyici kodu , modern bir x86 CPU'da bile genellikle daha iyi hale getirilebilir. Ancak, modern bir x86 CPU ile yapmak daha zor olan CPU'yu iyi anlamalısınız. Demek istediğim bu. Hedeflediğiniz donanımı anlamadıysanız, optimize edemezsiniz. Ve sonra derleyici muhtemelen daha iyi bir iş yapacak
jalf

1
Derleyiciyi gerçekten uçurmak istiyorsanız yaratıcı olmanız ve derleyicinin yapamayacağı şekilde optimize etmeniz gerekir. Bu, zaman / ödül için bir ödünleşimdir, bu nedenle C, bazıları için bir komut dosyası dili ve diğerleri için daha yüksek bir dil için ara koddur. Benim için montaj daha eğlenceli :). grc.com/smgassembly.htm
Hawken

22

Günümüzde montaj dilini kullanmanın tek nedeni, dil tarafından erişilemeyen bazı özellikleri kullanmaktır.

Bu .... için geçerlidir:

  • MMU gibi belirli donanım özelliklerine erişmesi gereken çekirdek programlama
  • Derleyiciniz tarafından desteklenmeyen çok özel vektör veya multimedya talimatlarını kullanan yüksek performanslı programlama.

Ancak şu anki derleyiciler oldukça zekidirler, iki ayrı ifadeyi d = a / b; r = a % b;bile, C'nin böyle bir operatörü olmasa bile, bölünmeyi ve varsa bir seferde kalan tek bir komutla hesaplayan tek bir komutla değiştirebilirler .


10
Bu ikisinin yanı sıra ASM için başka yerler de var. Yani, bignum kütüphanesi ASM'de bayraklara ve çarpma işleminin üst kısmına ve benzerlerine erişim nedeniyle C'den önemli ölçüde daha hızlı olacaktır. Bunları taşınabilir C'de de yapabilirsiniz, ancak çok yavaştırlar.
Mooing Ördek

@MooingDuck Bu, doğrudan dilde bulunmayan donanım donanım özelliklerine erişme olarak düşünülebilir ... Ancak , üst düzey kodunuzu el ile montaja çevirdiğiniz sürece , derleyici sizi yenecektir.
fortran

1
bu, ancak çekirdek programlama veya satıcıya özgü değildir. Hafif çalışma değişikliklerine rağmen, her iki kategoriye de kolayca girebilir. C eşlemesi olmayan işlemci talimatlarının performansını istediğinizde ASM'yi tahmin ediyorum.
Mooing Duck

1
@fortran Temel olarak sadece kodunuzu optimize etmezseniz derleyicinin optimize ettiği kod kadar hızlı olmayacağını söylüyorsunuz. Optimizasyon, en başta montajın yazılmasının nedenidir. Eğer çevirme demek istiyorsanız derleme optimize iyi değilse derleyici sizi yenmek için hiçbir neden yoktur. Yani derleyiciyi yenmek için derleyicinin yapamayacağı şekilde optimize etmek zorundasınız. Bu oldukça açıklayıcı. Derleme yazmanın tek nedeni, bir derleyici / yorumlayıcıdan daha iyi olmanızdır . Meclis yazmanın pratik nedeni hep buydu.
Hawken

1
Sadece söyleyerek: Clang, yerleşik işlevler aracılığıyla taşıma bayraklarına, 128 bit çarpma ve benzeri özelliklere erişebilir. Ve tüm bunları normal optimizasyon algoritmalarına entegre edebilir.
gnasher729

19

Modern bir derleyicinin kod optimizasyonunda inanılmaz bir iş çıkardığı doğrudur, ancak yine de montaj öğrenmeye devam etmenizi öneririm.

Öncelikle açıkça olan tüm onun tarafından korkutmak sonraki bir büyük, büyük artı olduğunu, - tıklayarak doğru yoldayız hız varsayımları doğrulamak amacıyla profil veya atmak , sizin için soruyorsunuz deneyimli insanlardan girişi ve insanoğlunun bildiği en büyük optimizasyon aracına sahip: bir beyin .

Deneyiminiz arttıkça, onu ne zaman ve nerede kullanacağınızı öğreneceksiniz (algoritmik düzeyde derin bir optimizasyon yaptıktan sonra genellikle kodunuzdaki en sıkı, en içteki döngüler).

İlham almak için Michael Abrash'in makalelerini aramanızı tavsiye ederim (ondan haber alamadıysanız , bir optimizasyon gurusu; Quake yazılım oluşturucusunun optimizasyonunda John Carmack ile bile işbirliği yaptı!)

"En hızlı kod diye bir şey yok" - Michael Abrash


2
Michael Abrash kitaplarından birinin grafik programlama kara kitabı olduğuna inanıyorum. Ancak meclisi kullanan tek kişi o değil, Chris Sawyer mecliste ilk iki roller coaster tycoon oyununu tek başına yazdı.
Hawken

14

Asm kodunu değiştirdim:

 __asm
{ 
    mov ebx,TIMES
 start:
    mov ecx,lengthOfArray
    mov esi,x
    shr ecx,2
    mov edi,y
label:
    mov eax,DWORD PTR [esi]
    add eax,DWORD PTR [edi]
    add edi,4   
    dec ecx 
    mov DWORD PTR [esi],eax
    add esi,4
    test ecx,ecx
    jnz label
    dec ebx
    test ebx,ebx
    jnz start
};

Sürüm sürümü için sonuçlar:

 Function of assembly version: 41
 Function of C++ version: 161

Serbest bırakma modundaki montaj kodu C ++ 'dan neredeyse 4 kat daha hızlıdır. IMHo, montaj kodunun hızı Programcıya bağlıdır


Evet, kodum gerçekten optimize edilmeli. Sizin için iyi çalışmalar ve teşekkürler!
user957121 9:12

5
Yalnızca işin dörtte yapmak çünkü dört kat daha hızlı olduğunu :-) shr ecx,2dizi uzunluk zaten verilmektedir, çünkü gereksiz olduğunu intbyte içinde değil. Yani temelde aynı hızı elde edersiniz. padddHarolds cevabını deneyebilirsiniz , bu gerçekten daha hızlı olacak.
Gunther Piez

13

çok ilginç bir konu!
Sasha'nın kodunda SSX tarafından MMX'i değiştirdim
İşte sonuçlarım:

Function of C++ version:      315
Function of assembly(simply): 312
Function of assembly  (MMX):  136
Function of assembly  (SSE):  62

SSE ile birleştirme kodu C ++ 'dan 5 kat daha hızlıdır


12

Çoğu üst düzey dil derleyicisi çok optimize edilmiştir ve ne yaptıklarını bilir. Sökme kodunu döküp yerel meclisinizle karşılaştırabilirsiniz. Derleyicinizin kullandığı güzel numaralar göreceğinize inanıyorum.

Sadece örneğin, artık doğru olduğundan emin değilim bile :):

Yapma:

mov eax,0

daha fazla döngü maliyeti

xor eax,eax

aynı şeyi yapar.

Derleyici tüm bu püf noktalarını bilir ve kullanır.


4
Hala doğru, bkz. Stackoverflow.com/questions/1396527/… . Kullanılan döngüler nedeniyle değil, daha az bellek kapladığı için.
Gunther Piez

10

Derleyici seni dövdü. Deneyeceğim, ama garanti vermeyeceğim. Ben TIMES tarafından "çarpma" daha alakalı bir performans testi yapmak için olduğunu varsayalım, bu yve x16-hizalanmış ve bu lengthsıfırın 4 olmayan bir katı olduğunu varsayalım .

  mov ecx,length
  lea esi,[y+4*ecx]
  lea edi,[x+4*ecx]
  neg ecx
loop:
  movdqa xmm0,[esi+4*ecx]
  paddd xmm0,[edi+4*ecx]
  movdqa [edi+4*ecx],xmm0
  add ecx,4
  jnz loop

Dediğim gibi, hiçbir garanti vermiyorum. Ama çok daha hızlı yapılabilirse şaşıracağım - buradaki darboğaz, her şey bir L1 vuruşu olsa bile bellek çıkışıdır.


Ben karmaşık adresleme kodunuzu yavaşlattığını düşünüyorum, eğer kodu değiştirmek mov ecx, length, lea ecx,[ecx*4], mov eax,16... add ecx,eaxve daha sonra sadece [esi + ecx] kullanın her yerde döngü çok hızlandırmak talimat başına 1 döngüsü durak önleyeceksiniz. (En son Skylake'iniz varsa, bu geçerli değildir). Reg, reg ekle, döngüyü daha sıkı yapar, bu da yardımcı olabilir veya olmayabilir.
Johan

@Johan bir durak olmamalı, sadece ekstra bir döngü gecikmesi, ama emin değilim ona zarar veremez .. Core2 için bu kodu bu sorunu yoktu yazdı. R + r ayrıca "karmaşık" btw değil mi?
harold

7

Montaj mi Sadece körü körüne, talimatla aynı algoritma, talimat uygulanması garantili derleyici neler yapabileceğini daha yavaş olması.

Çünkü derleyicinin yaptığı en küçük optimizasyon bile hiçbir optimizasyon olmadan katı kodunuzdan daha iyidir.

Tabii ki, derleyiciyi yenmek mümkündür, özellikle kodun küçük, yerelleştirilmiş bir parçasıysa, yaklaşık olarak kendim yapmak zorunda kaldım. 4x hızlanır, ancak bu durumda donanımın iyi bilgisine ve çok sayıda, görünüşte karşı sezgisel numaraya güvenmemiz gerekir.


3
Bunun dile ve derleyiciye bağlı olduğunu düşünüyorum. Çıktıları bir insan yazım düz montajı tarafından kolayca dövülebilecek son derece verimsiz bir C derleyicisini hayal edebiliyorum. GCC, çok fazla değil.
Casey Rodarmor

C / ++ derleyicileri böyle bir girişim ve sadece 3 büyük olanlar ile, yaptıkları işte oldukça iyi olma eğilimindedirler. Bazı durumlarda elle yazılmış montajın daha hızlı olması hala mümkündür (çok); birçok matematik kütüphanesi birden çok / geniş değerleri daha iyi işlemek için bir kenara bırakılır. Bu yüzden garanti biraz fazla güçlü olsa da, muhtemelen.
ssube

@peachykeen: Montajın genel olarak C ++ 'dan daha yavaş olacağı garanti edilmemişti. Ben bir C ++ kodu var ve körü körüne derleme satır montaj çevirmek durumunda "garanti" demekti. Cevabımın son paragrafını da okuyun :)
vsz

5

Bir derleyici olarak idam görevleri çok sabit bir boyutu olan bir döngü yerini alacaktı.

int a = 10;
for (int i = 0; i < 3; i += 1) {
    a = a + i;
}

üretecek

int a = 10;
a = a + 0;
a = a + 1;
a = a + 2;

ve sonunda "a = a + 0;" işe yaramaz, bu yüzden bu satırı kaldıracaktır. Umarım kafanızdaki bir şey şimdi yorum olarak bazı optimizasyon seçeneklerini eklemeye hazırdır. Tüm bu çok etkili optimizasyonlar derlenen dili daha hızlı hale getirecektir.


4
Ve adeğişken olmadığı sürece , derleyicinin int a = 13;en başından itibaren yapması için iyi bir şans var .
vsz


4

Bu örneği seviyorum, çünkü düşük seviyeli kod hakkında önemli bir ders gösteriyor. Evet, olabilir C kodu kadar hızlı olduğunu montaj yazın. Bu totolojik olarak doğrudur, ancak ille de hiçbir şey ifade etmez. Açıkçası biri yapabilir, aksi takdirde montajcı uygun optimizasyonları bilemez.

Aynı şekilde, dil soyutlama hiyerarşisinde yukarı çıkarken de aynı prensip geçerlidir. Evet, yapabilirsiniz kadar hızlı bir kirli hızlı ve-perl komut dosyası olarak ise C bir ayrıştırıcı yazmak ve birçok insan biliyor. Ancak bu, C'yi kullandığınız için kodunuzun hızlı olacağı anlamına gelmez. Çoğu durumda, üst düzey diller hiç düşünmediğiniz optimizasyonlar yapar.


3

Birçok durumda, bazı görevleri gerçekleştirmenin en uygun yolu, görevin gerçekleştirildiği bağlama bağlı olabilir. Eğer bir rutin montaj dilinde yazılmışsa, talimatlar dizisinin içeriğe göre değiştirilmesi genellikle mümkün olmayacaktır. Basit bir örnek olarak, aşağıdaki basit yöntemi göz önünde bulundurun:

inline void set_port_high(void)
{
  (*((volatile unsigned char*)0x40001204) = 0xFF);
}

Yukarıda verilen 32 bit ARM kodu için bir derleyici, büyük olasılıkla bunu aşağıdaki gibi işleyecektir:

ldr  r0,=0x40001204
mov  r1,#0
strb r1,[r0]
[a fourth word somewhere holding the constant 0x40001204]

ya da belki

ldr  r0,=0x40001000  ; Some assemblers like to round pointer loads to multiples of 4096
mov  r1,#0
strb r1,[r0+0x204]
[a fourth word somewhere holding the constant 0x40001000]

Bu, elle birleştirilmiş kodda biraz optimize edilebilir:

ldr  r0,=0x400011FF
strb r0,[r0+5]
[a third word somewhere holding the constant 0x400011FF]

veya

mvn  r0,#0xC0       ; Load with 0x3FFFFFFF
add  r0,r0,#0x1200  ; Add 0x1200, yielding 0x400011FF
strb r0,[r0+5]

Elle birleştirilen her iki yaklaşım da 16 yerine 12 bayt kod alanı gerektirir; ikincisi, bir "yükü" bir ARM7-TDMI üzerinde iki döngüyü daha hızlı yürüten bir "ekleme" ile değiştirir. Kod, r0'ın bilmediği / umursamadığı bir bağlamda yürütülecek olsaydı, montaj dili sürümleri derlenmiş sürümden biraz daha iyi olurdu. Öte yandan, derleyicinin bazı kayıtların [örn. R5], istenen adresin 0x40001204 [örneğin 0x40001000] 'in 2047 bayt içinde bir değer tutacağını bildiğini ve ayrıca başka bir kaydın [örneğin r7] gideceğini bildiğini varsayalım düşük bitleri 0xFF olan bir değeri tutmak için. Bu durumda, bir derleyici kodun C sürümünü basitçe:

strb r7,[r5+0x204]

Elle optimize edilmiş montaj kodundan bile çok daha kısa ve hızlı. Ayrıca, set_port_high öğesinin bağlamda oluştuğunu varsayalım:

int temp = function1();
set_port_high();
function2(temp); // Assume temp is not used after this

Gömülü bir sistemi kodlarken hiç mantıklı değil. Eğer set_port_highmontaj kodunda yazılır, derleyici (dönüş değeri tutan r0 hareket etmesi gerekir function1) başka bir yerde daha önce derleme kod yürütmesini ve (çünkü o zaman sonra r0 bu değer çekmeme function2, r0 ilk parametreyi bekliyoruz) bu nedenle "optimize edilmiş" montaj kodu beş talimat gerektirir. Derleyici, adresi veya depolanacak değeri tutan herhangi bir kayıt bilmiyor olsa bile, dört komutlu sürümü (kullanılabilir kayıtların kullanımına uyarlanabilir - r0 ve r1 olması gerekmez) "optimize edilmiş" montajı yener -dil sürümü. Derleyici, daha önce açıklandığı gibi r5 ve r7'deki gerekli adres ve verilere sahip function1olsaydı , bu kayıtları değiştirmez ve bu nedenleset_port_hightek bir strbtalimatla -"elle optimize edilmiş" montaj kodundan daha küçük ve daha hızlı dört talimat .

Elle optimize edilmiş montaj kodunun, programlayıcının kesin program akışını bildiği durumlarda bir derleyiciden daha iyi performans gösterebileceğini, ancak derleyicilerin bağlamı bilinmeden önce bir kod parçasının yazıldığı veya bir kaynak kod parçasının olabileceği durumlarda parladığını unutmayın. birden çok bağlamdan çağrıldığında [ set_port_highkoddaki elli farklı yerde kullanılırsa, derleyici bağımsız olarak onu en iyi nasıl genişleteceklerine karar verebilir].

Genel olarak, montaj dilinin, her bir kod parçasına çok sınırlı sayıda bağlamdan yaklaşılabildiği durumlarda en yüksek performans iyileştirmelerini sağlamaya uygun olduğunu ve bir parça parçanın olduğu yerlerde performansa zarar vermeye eğilimli olduğunu öneririm. koda birçok farklı bağlamdan yaklaşılabilir. İlginçtir (ve uygun olarak) montajın performans için en faydalı olduğu durumlar genellikle kodun en basit ve okunması kolay olanlardır. Derleme dil kodunun aşırı karışıklığa dönüşeceği yerler genellikle derlemede yazmanın en küçük performans avantajı sunacağı yerlerdir.

[Küçük not: montaj kodunun hiper optimize edilmiş gooey karışıklığı vermek için kullanılabileceği bazı yerler vardır; örneğin, ARM için yaptığım bir kod parçası, RAM'den bir kelime almak ve değerin üst altı bitine dayanarak yaklaşık on iki rutinden birini yürütmek zorundaydı (aynı rutete eşlenen birçok değer). Ben böyle bir şeye bu kodu optimize düşünüyorum:

ldrh  r0,[r1],#2! ; Fetch with post-increment
ldrb  r1,[r8,r0 asr #10]
sub   pc,r8,r1,asl #2

R8 kaydı her zaman ana dağıtım tablosunun adresini tutmuştur (kodun zamanının% 98'ini harcadığı döngü içinde, hiçbir şey bunu başka bir amaçla kullanmamıştır); 64 girişin tümü, ondan önceki 256 bayttaki adreslere atıfta bulunur. Birincil döngü çoğu durumda yaklaşık 60 döngü sert yürütme süresi sınırına sahip olduğundan, dokuz döngü getirme ve gönderme bu hedefe ulaşmak için çok etkili oldu. 256 32 bit adresli bir tablo kullanmak bir döngü daha hızlı olurdu, ancak 1KB çok değerli RAM [flash birden fazla bekleme durumu ekleyecekti] gobbled olurdu. 64 32-bit adresleri kullanmak, getirilen sözcükten bazı bitleri maskelemek için bir talimat eklemeyi gerektiriyordu ve hala kullandığım tablodan 192 bayt daha fazla gitmişti. 8-bit ofset tablosunu kullanarak çok kompakt ve hızlı kod verdiler, ama bir derleyicinin gelmesini beklediğim bir şey değil; Ben de bir derleyici tablo adresini tutmak için bir kayıt "tam zamanlı" adamak için beklemem.

Yukarıdaki kod, bağımsız bir sistem olarak çalışacak şekilde tasarlanmıştır; periyodik olarak C kodunu çağırabilir, ancak yalnızca belirli zamanlarda iletişim kurduğu donanımın her 16 ms'de bir kabaca bir milisaniye aralıklarla "boşta" duruma getirilebildiği zaman.


2

Son zamanlarda, yaptığım tüm hız optimizasyonları, beyin hasarlı yavaş kodu sadece makul kodla değiştiriyordu. Ancak işler hızın çok kritik olduğu ve bir şeyi hızlı hale getirmek için ciddi çaba harcadığım için, sonuç her zaman yinelemenin sorunla ilgili daha fazla fikir verdiği ve sorunu daha az işlemle çözmenin yollarını bulduğu yinelemeli bir süreçti. Son hız her zaman soruna ne kadar içgörü verdiğime bağlıydı. Herhangi bir aşamada montaj kodunu veya aşırı optimize edilmiş C kodunu kullansaydım, daha iyi bir çözüm bulma süreci acı çekerdi ve sonuç daha yavaş olurdu.


2

Daha derin bilgiye sahip montaj dilini doğru şekilde kullanmadığınız sürece C ++ daha hızlıdır.

ASM'de kod yazdığımda, CPU'nun mantıksal olarak mümkün olduğunda daha fazlasını paralel olarak yürütmesi için talimatları manuel olarak yeniden organize ediyorum. ASM'de kod yazarken zar zor RAM kullanıyorum: ASM'de 20000+ kod satırı olabilir ve bir kez push / pop kullanmadım.

Kendini değiştiren kodun olası bir cezası olmadan kodu ve davranışı kendiliğinden değiştirmek için potansiyel olarak opcode'un ortasına atlayabilirsiniz. Kayıtlara erişmek CPU'nun 1 işaretini (bazen .25 keneler alır) alır. RAM'e erişmek yüzlerce sürebilir.

Son ASM maceram için, bir zamanlar bir değişkeni depolamak için RAM kullanmadım (binlerce satır ASM için). ASM, C ++ 'dan muhtemelen düşünülemeyecek kadar hızlı olabilir. Ancak, aşağıdaki gibi birçok değişken faktöre bağlıdır:

1. I was writing my apps to run on the bare metal.
2. I was writing my own boot loader that was starting my programs in ASM so there was no OS management in the middle.

Verimlilik önemli olduğunu fark çünkü şimdi C # ve C ++ öğreniyorum !! Sadece boş zamanlarında saf ASM'yi kullanarak akla gelebilecek en hızlı programları yapmaya çalışabilirsiniz. Ancak bir şeyler üretmek için yüksek düzeyde bir dil kullanın.

Örneğin, kodladığım son program JS ve GLSL kullanıyordu ve hiç yavaşlamayan JS'den bahsetmişken bile hiçbir performans sorunu fark etmedim. Bunun nedeni, 3D için GPU'yu programlama kavramının komutları GPU'ya gönderen dilin hızını neredeyse alakasız hale getirmesidir.

Çıplak metal üzerindeki tek başına montajcının hızı reddedilemez. C ++ içinde daha da yavaş olabilir mi? - Bunun nedeni, bir derleyici ile derleyici kullanmadan derleme kodu yazmanız olabilir.

Kişisel konseyim, meclisi sevdiğim halde, engellemeniz durumunda asla meclis kodu yazmamaktır.


1

Buradaki tüm cevaplar bir yönü dışlıyor gibi görünüyor: bazen belirli bir amaca ulaşmak için kod yazmıyoruz, ama bunun tam eğlencesi için. Bunu yapmak için zaman harcamak ekonomik olmayabilir, ancak tartışmalı olarak en hızlı derleyici için optimize edilmiş kod snippet'ini manuel olarak haddelenmiş bir asm alternatifiyle hızdan daha iyi bir memnuniyet yoktur.


Derleyiciyi yenmek istediğinizde, işleviniz için asm çıkışını almak ve bunu yaptığınız bağımsız bir asm işlevine dönüştürmek genellikle daha kolaydır. Satır içi asm kullanmak , C ++ ve asm arasındaki arabirimi doğru şekilde almak ve en iyi kod için derlendiğini kontrol etmek için bir sürü ekstra çalışmadır. (Ama en azından sadece eğlence için yaparken, işlev başka bir şeye girdiğinde sabit yayılım gibi optimizasyonları yenmesi konusunda endişelenmenize gerek yok. Gcc.gnu.org/wiki/DontUseInlineAsm ).
Peter Cordes

Ayrıca derleyici eğlenmek için derleyiciyi yenme hakkında daha fazla bilgi için Collatz konjonktürü C ++ ve elle yazılmış asm Q&A'ya bakın :) Ve ayrıca derleyicinin daha iyi kod yapmasına yardımcı olmak için öğrendiğiniz şeyi nasıl kullanacağınıza dair öneriler.
Peter Cordes

@PeterCordes Yani söylediğiniz şey aynı fikirde.
madoki

1
Evet, asm eğlencelidir, ancak satır içi asm genellikle oyun oynamak için bile yanlış seçimdir. Bu teknik olarak satır içi bir sorudur, bu yüzden en azından cevabınızdaki bu noktayı ele almak iyi olacaktır. Ayrıca, bu gerçekten bir cevaptan çok bir yorumdur.
Peter Cordes

Tamam kabul. Eskiden sadece asm adamıydım ama bu 80'di.
madoki

-2

Bir c ++ derleyicisi, kuruluş düzeyinde optimizasyondan sonra, hedeflenen CPU'nun yerleşik işlevlerini kullanacak kod üretecektir. HLL, çeşitli nedenlerden dolayı montajcıyı asla geçemez veya gerçekleştirmez; 1.) HLL derlenecek ve Accessor kodu, sınır kontrolü ile hazırlanacak ve muhtemelen çöp toplama (daha önce OOP tavırlarında kapsamı ele alan) içinde oluşturulacaktır. HLL bu günlerde (daha yeni C ++ ve GO gibi diğerleri dahil) mükemmel bir iş çıkarıyor, ancak montajcıdan (yani kodunuzdan) daha iyi performans gösteriyorlarsa, CPU Belgelerine başvurmanız gerekir. aşağı op-kodu HLL ayrıntıları soyutlar ve bunları ortadan kaldırmaz başka uygulama bile ana işletim sistemi tarafından tanınan çalıştırmak olmaz.

Çoğu montajcı kodu (öncelikli olarak nesneler), daha az işlem gerektiren diğer yürütülebilir biçimlere dahil edilmek üzere "başsız" olarak çıkarılır, bu nedenle çok daha hızlı, ancak çok daha güvenli olmayacaktır; Eğer bir yürütülebilir dosya montajcı tarafından çıkarılırsa (NAsm, YAsm; vb.) HLL koduyla tamamen işlevsel olana kadar hala daha hızlı çalışır ve sonuçlar doğru şekilde tartılabilir.

HLL'den herhangi bir formatta bir montajcı tabanlı kod nesnesinin çağrılması, değişken / sabit veri türleri için global olarak tahsis edilen belleği kullanan bellek alanı çağrılarına ek olarak doğal olarak işlem yükü ekleyecektir (bu hem LLL hem de HLL için geçerlidir). Nihai çıktının CPU'yu nihayetinde donanıma (opcode) göre api ve abi olarak kullandığını ve hem montajcıların hem de "HLL derleyicilerinin" okunabilirlik (gramer) olmasıyla temelde / temelde aynı olduğunu unutmayın.

Merhaba dünya konsol uygulaması FAsm kullanarak montaj 1.5 KB (ve bu Windows FreeBSD ve Linux daha da küçük) ve GCC en iyi gününde atmak şey daha iyi; nedenleri nops'larla örtülü dolgu, erişim doğrulaması ve birkaçını kontrol etmek için sınır kontrolüdür. Gerçek hedef, temiz HLL kütüphaneleri ve bir cpu'yu "hardcore" bir şekilde hedefleyen ve çoğu bugün (nihayet) yapan optimize edilebilir bir derleyicidir. GCC, YAsm'dan daha iyi değildir - söz konusu geliştiricinin kodlama uygulamaları ve anlayışıdır ve "optimizasyon" acemi keşif ve geçici eğitim ve deneyimden sonra gelir.

Derleyiciler bir derleyici ile aynı op koddaki çıkış için bağlantı kurmalı ve bir araya getirilmelidir, çünkü bu kodlar bir CPU'nun hariç olacağı tek şeydir (CISC veya RISC [PIC de]). YAsm, erken NAsm üzerinde büyük ölçüde optimize edildi ve temizlendi, sonuçta bu montajcıdan tüm çıktıları hızlandırdı, ancak o zaman bile YAsm, NAsm gibi, geliştirici adına OS kitaplıklarını hedefleyen harici bağımlılıklara sahip yürütülebilir dosyalar üretebiliyor, böylece kilometre değişebilir. C ++ kapanışında, özellikle ticari sektörde yüzde 80+ için montajcıdan inanılmaz ve çok daha güvenli bir noktada ...


1
C ve C ++, siz istemediğiniz sürece sınır denetimi yapmaz ve kendiniz uygulamadığınız veya bir kitaplık kullanmadığınız sürece çöp toplama işlemi yoktur. Asıl soru, derleyicinin bir insandan daha iyi döngüler (ve global optimizasyonlar) yapıp yapmadığıdır. İnsan ne yaptığını gerçekten bilmediği ve üzerinde çok fazla zaman harcamadığı sürece genellikle evet .
Peter Cordes

1
NASM veya YASM'yi (harici kod yok) kullanarak statik yürütülebilir dosyalar yapabilirsiniz. Her ikisi de düz ikili biçimde çıktı alabilir, böylece gerçekten çalıştırmak istemezseniz ELF başlıklarını kendiniz bir araya getirebilirsiniz.ld , ancak dosya boyutu için gerçekten optimize etmeye çalışmadığınız sürece hiçbir fark yaratmaz (yalnızca metin bölümü). Linux için Gerçekten Teensy ELF Yürütülebilir Dosyaları Oluşturma hakkında Kasırga Öğreticisine bakın .
Peter Cordes

1
Belki de C # düşünüyorsunuz veya std::vectorhata ayıklama modunda derliyorsunuz. C ++ dizileri böyle değildir. Derleyiciler, derleme zamanında işleri kontrol edebilir, ancak ekstra sertleştirme seçeneklerini etkinleştirmezseniz, çalışma zamanı kontrolü yoktur. Örneğin, bir int array[]argümanın ilk 1024 öğesini arttıran bir işleve bakın . ASM çıktısında çalışma zamanı kontrolü yoktur: godbolt.org/g/w1HF5t . Tek gereken bir işaretçi rdi, boyut bilgisi yok. Hiçbir zaman 1024'ten küçük bir dizi ile çağırmadan tanımlanmamış davranışı önlemek programcıya kalmıştır.
Peter Cordes

1
Ne hakkında konuşuyorsanız, düz bir C ++ dizisi değildir (ile ayır new, elle sil delete, sınır kontrolü yok). Sen edebilirsiniz (çoğu yazılım gibi) boktan şişirilmiş asm / makineyi-kodu üretmek için C ++ kullanın, ancak bu programcı hatası değil, C ++ 'ın bu. Hatta allocayığın alanı bir dizi olarak ayırmak için kullanabilirsiniz .
Peter Cordes

1
Üzerinde bir örnek bağla gcc.godbolt.org ait g++ -O3düz bir dizi için kod sınırları denetimi üreten ya bahsettiğin başka ne yapıyor. C ++ şişirilmiş ikili dosyalar oluşturmayı çok daha kolaylaştırır (ve aslında performansı hedefliyorsanız dikkatli olmamalısınız ), ancak tam anlamıyla kaçınılmaz değildir. C ++ 'ın asm için nasıl derlendiğini anlarsanız, elle yazabileceğinizden biraz daha kötü olan kodu elde edebilirsiniz, ancak elle yönetebileceğinizden daha büyük bir ölçekte satır içi ve sabit yayılım ile.
Peter Cordes

-3

Derleyiciniz çok sayıda OO destek kodu üretirse montaj daha hızlı olabilir .

Düzenle:

Downvoters için: OP yazdı "C ++ odaklanmak ve montaj dili unutmak?" ve cevabımın yanındayım. Özellikle metotları kullanırken, OO'nun ürettiği kodu her zaman göz önünde bulundurmanız gerekir. Derleme dilini unutmamak, iyi performans gösteren yazılımlar yazmak için bir zorunluluk olduğuna inandığım OO kodunuzun oluşturduğu derlemeyi düzenli olarak gözden geçireceğiniz anlamına gelir.

Aslında, bu sadece OO için değil, tüm uyumlu kodlarla ilgilidir.


2
-1: Kullanılan herhangi bir OO özelliği görmüyorum. Argümanınız "derleyiciniz bir milyon NOP eklerse montaj da daha hızlı olabilir" ile aynıdır.
Sjoerd

Belirsizdim, bu aslında bir C sorusu. Bir C ++ derleyicisi için C kodu yazarsanız, C ++ kodu yazmazsınız ve herhangi bir OO öğesi alamazsınız. Gerçek C ++ ile yazmaya başladıktan sonra, OO şeyler kullanarak derleyicinin OO destek kodu üretmemesi için çok bilgili olmalısınız.
Olof Forshell

yani cevabınız soru hakkında değil mi? (Ayrıca, açıklamalar yorumda değil, cevaba gider. Yorumlar herhangi bir bildirim, bildirim veya geçmiş olmadan her zaman silinebilir.
Mooing Duck

1
OO "destek kodu" ile tam olarak ne demek istediğinizden emin değilim. Tabii ki, çok fazla RTTI ve benzeri kullanırsanız, derleyici bu özellikleri desteklemek için çok sayıda ek talimat oluşturmak zorunda kalacaktır - ancak RTTI kullanımını onaylamak için yeterince yüksek düzeyde olan herhangi bir sorun, montajda uygun şekilde yazılamayacak kadar karmaşıktır . Yapabileceğiniz şey, elbette, kritik olarak performansa göre optimize edilmiş saf prosedür koduna göndererek OO olarak sadece soyut dış arayüzü yazmaktır. Ancak, uygulamaya bağlı olarak, sanal kalıtım olmadan C, Fortran, CUDA veya basitçe C ++ burada montajdan daha iyi olabilir.
leftaroundabout

2
Hayır. En azından pek olası değil. C ++ 'da sıfır ek yük kuralı denilen bir şey vardır ve bu çoğu zaman geçerlidir. OO hakkında daha fazla bilgi edinin - sonunda kodunuzun okunabilirliğini geliştirdiğini, kod kalitesini artırdığını, kodlama hızını artırdığını, sağlamlığı artırdığını göreceksiniz. Ayrıca gömülü için - ama size daha fazla kontrol sağladığı için C ++ kullanın, gömülü + OO Java yolu size mal olacak.
Zane
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.