gcc'da -O3 en iyileştirme ile derlenmiş basit C kodunu inceleyerek vektörleştirmeyi öğrenmeye çalışıyorum. Daha spesifik olarak, derleyiciler ne kadar iyi ifade ederler? Daha karmaşık hesaplamayla gcc-O3 performansını doğrulamak için kişisel bir yolculuktur. Geleneksel bilgeliğin, derleyicilerin insanlardan daha iyi olduğu, ama asla böyle bir bilgelik almadığım anlamına geldiğini anlıyorum. En iyileştirilmiş C kodunda derleme kodu yedeklemesi
İlk basit testimde, gcc seçeneklerinden bazılarını oldukça garip ve oldukça dürüst bir şekilde, optimizasyon açısından oldukça ihmalkar buluyorum. Derleyici amaca yönelik bir şey olduğunu ve CPU'yla ilgili bir şey bildiğimi (bu durumda Intel i5-2557M) bilmiyorum. Ama bilgili kişilerden bazı onaylara ihtiyacım var.
My basit bir test kodu (kademeli) aşağıdaki gibidir:
.L6: ; loop starts here
movdqa xmm0, xmm1 ; copy packed integers in xmm1 to xmm0
.L3:
movdqa xmm1, xmm0 ; wait, what!? WHY!? this is redundant.
cvtdq2ps xmm0, xmm0 ; convert integers to float
add rax, 16 ; increment memory pointer for next iteration
mulps xmm0, xmm0 ; pack square all integers in xmm0
paddd xmm1, xmm2 ; pack increment all integers by 4
movaps XMMWORD PTR [rax-16], xmm0 ; store result
cmp rax, rdx ; test loop termination
jne .L6
tüm adımları anlamak aşağıdaki gibidir: dongu olduğu tekabül
int i;
float a[100];
for (i=0;i<100;i++) a[i]= (float) i*i;
Sonuçta ortaya çıkan grup kodu (kademeli) ve hesaplamalı olarak, hepsi mantıklı. Anlamıyorum ne olacağım değil xmm0XMM1 ile yüklendi sonra adım xmm0 ile XMM1 yüklemek için iteratif döngü içinde dahil etmek seçerek gcc olduğunu.
.L6
movdqa xmm0, xmm1 ; loop starts here
.L3
movdqa xmm1, xmm0 ; grrr!
Yalnız bu, optimize edicinin aklı olup olmadığı sorusunu sorguluyor. Açıkçası, ekstra MOVDQA verileri rahatsız etmiyor, ancak yüz değeri olarak,
gcc'un parçası üzerinde çok ihmalkar görünüyor. Daha önce montaj kodu (gösterilmemiştir) içerisinde
,
xmm0 ve
XMM2 döngüsünün başlangıcında, yani belli vektörleştirme için anlamlı bir değeri başlatılır, kodu ilk MOVDQA geçmek zorundadır. aşağıda gösterildiği gibi Ama neden
gcc basitçe yeniden düzenlemek gelmez.
.L3
movdqa xmm1, xmm0 ; initialize xmm1 PRIOR to loop
.L6
movdqa xmm0, xmm1 ; loop starts here
Hatta daha da iyisi, sadece başlatmak XMM1 yerine xmm0ve MOVDQA xmm0 adım tamamen XMM1, dökümü!
Ben CPU böyle gereksiz adımı falan atlamak kadar akıllı olduğuna inanmaya hazırım, ama nasıl bunu bile doğru bu basit kodunu alabilirsiniz eğer tam karmaşık kod optimize etmek gcc güvenebiliriz? Ya da birisi bana gcc-O3'un iyi şeyler olduğuna inanan bir ses açıklaması sağlayabilir mi?
@Down seçmenleri: lütfen nedenini yorumlayın. – Stefan
En iyileştirmeler açık duruma getirildi mi? Bazı optimizasyon seviyelerinde, gereksiz hareket işlemi ortadan kalkar. –
Kodunuzun derleyicilerden daha hızlı olduğundan emin misiniz? Onları zamanlamaya çalıştın mı? – Degustaf