2015-07-09 36 views
6

SSE'de çok ince bir sorunla karşılaşıyorum. Bu durumda, SSE ile ışın izleyicimi optimize etmek istiyorum, böylece SSE ile performansın nasıl iyileştirileceğine dair temel bir his elde edebiliyorum.SSE boru hattı temizlemesi nasıl yapılır?

Bu çok işlevle başlamak istiyorum.

Vector3f Add(const Vector3f& v0 , Vector3f& v1); 

(Aslında ben basitlik için burada gösterilir eklenmesi, ilk Çapraz Çarpım optimize etmeye çalıştı ve bunu kendi ışın zerresinin darboğaz değil biliyorduk.) Burada

yapı tanımının bir parçasıdır :

struct Vector3f 
{ union { struct{ float x ; float y ; float z; float reserved; }; __m128 data; }; 

konudur SSE bu çok beyanı ile aynı hizada kayıt olacak, derleyici başka kullanımlar için olanlar sse kayıt tutacak kadar akıllı değildir. Aşağıdaki bildirimle, yıkamadan kaçınılır.

__m128 Add(__m128 v0_data, __m128 v1_data); 

Bu davada bu yolla gidebilir, ancak dört __m128 verileri tutan Matrix için çirkin tasarım olacaktır. Ve operatörünüzün Vector3f'in kendisinde ancak veri üzerinde çalışmasına izin veremezsiniz :(.

En rahatsız edici şey, daha üst düzey kodunuzu değiştirmek için her yerde değişmek zorunda olmanızdır. GGD kesinlikle büyük bir oyun motoru gibi büyük bir şey için hiçbir seçenek aracılığıyla çalıştığını önce, kod büyük miktarda değiştireceğiz.

SSE kızarma kayıt kaçınarak olmadan, gücünü bu yararsız yıkama komutu tarafından boşaltılır edilecektir SSE yararsız, sanırım vermektedir.

+0

Vector3f bellekte hizalanmış 16 bit olduğunu belirtmeyi unuttum. – JerryCao1985

+0

Ara sıra nezaket nezaketini unutmayın. –

+1

@ JerryCao1985 Bunu bir yorum olarak eklemek yerine, bunu düzenleyerek söz konusu kişiden doğrudan söz edebilirsiniz. – Borgleader

cevap

1

birlik burada kullanılacak kötü bir şey gibi görünüyor. sürece bir derleyici __m128 şey ile birleşik görür, bu sorunlar espri vardır Değerlerin ne zaman güncelleneceğini anlamak, aşırı bellek işlemlerine yol açıyor.

MSVC, bu durumda en kötü performans veren derleyici değildir. Sadece the code generated by GCC 5.1.0'u kontrol edin, makinemde MSVC2013 ( yazmaçların dökülmesine izin veren ) tarafından oluşturulan koddan 12 kat daha yavaş ve en uygun koddan 20+ kat daha yavaş çalışır.

Çoğu derleyici gerçekten verilere erişmek için x, y, z üye kullanmak yalnızca saçma şeyler yapmaya başlamak ilginçtir. Örneğin, MSVC2013, yalnızca hesaplama sonrasında skaler üyeler aracılığıyla okunduğunuzda kayıt yapar (bu üyelerin gerçekte olduğundan emin olmak isterim). Başlangıç ​​değerlerini, doğrudan üyelere yazmak yerine _mm_setr_ps ile ayarlarsanız, GCC'nin korkunç davranışı kaybolur.

Bu durumda sendikalardan kaçınmak daha iyidir. OP'nin de aynı karara varmış gibi görünüyor (bkz. current Vector3fv code). Tek bir koordinatın erişimini zorlaştırmak iyi bir “psikolojik” performans etkisine sahiptir: bir kişi skaler kod yazmadan önce iki kez düşünür.

float getX() const { return ((float*)&data)[0]; } 

Ben kaldırın: Kolayca (derleyici bir yol seçmek kılan) (derleyici bu talimatları oluşturmak yapar) ya özü/insert intrinsics ile belirleyiciler/alıcılar yazabilir veya basit olarak gösterici aritmetiği ile yapabilirsiniz Sendika ve sadece __m128 kullanın, oluşturulan kod tüm derleyicilerde daha iyi olur.Bununla birlikte, MSVC2013 hala gereksiz hareketlere sahiptir: her aritmetik işlem başına bir yararsız kayıt hareketi. Bu derleyici inlining algoritmasında bir verimsizlik olduğunu varsayalım. Bu hareketleri MSVC2013'te tüm işlevlerinizi __vectorcall olarak bildirerek kaldırabilirsiniz. Bu yeni çağrı kuralını kullanmanın, simd işlevlerinizin hiç bir şekilde belirtilmemiş olması durumunda kayıt dökülmesini engellemenize de izin verdiğini unutmayın.

İlgili konular