Matris-Vektör Çarpma Ölçeklemem neden olmasın?


15

Uzun yazı için özür dilerim ama ilk adımda alakalı olduğunu düşündüğüm her şeyi dahil etmek istedim.

İstediğim

Yoğun Matrisler için Krylov Altuzay Yöntemlerinin paralel bir versiyonunu kullanıyorum .Temelde GMRES, QMR ve CG. (Profillemeden sonra) DGEMV rutinimin acıklı olduğunu fark ettim. Bu yüzden izole ederek buna konsantre olmaya karar verdim. 12 çekirdekli bir makinede çalıştırmayı denedim, ancak aşağıdaki sonuçlar 4 çekirdekli Intel i3 Dizüstü Bilgisayar için. Trendde çok fazla fark yok.

Çıktıma buradanKMP_AFFINITY=VERBOSE ulaşılabilir .

Küçük bir kod yazdım:

size_N = 15000
A = randomly_generated_dense_matrix(size_N,size_N); %Condition Number is not bad
b = randomly_generated_dense_vector(size_N);
for it=1:n_times %n_times I kept at 50 
 x = Matrix_Vector_Multi(A,b);
end

Bunun 50 yineleme için CG'nin davranışını simüle ettiğine inanıyorum.

Ne denedim:

Tercüme

Başlangıçta kodu Fortran'da yazmıştım. C, MATLAB ve Python'a (Numpy) çevirdim. Söylemeye gerek yok, MATLAB ve Python korkunçtu. Şaşırtıcı bir şekilde, C, yukarıdaki değerler için bir veya iki saniye FORTRAN'dan daha iyiydi. Sürekli.

profil oluşturma

Kodumu çalıştırmak için profilli ve 46.075saniyeler içinde koştu . Bu, MKL_DYNAMIC olarak ayarlandığındaFALSE ve tüm çekirdekler kullanıldığında oldu. MKL_DYNAMIC'i doğru olarak kullansaydım, çekirdek sayısının sadece (yaklaşık) yarısı herhangi bir zamanda kullanılırdı. İşte birkaç ayrıntı:

Address Line    Assembly                CPU Time

0x5cb51c        mulpd %xmm9, %xmm14     36.591s

En çok zaman alan süreç şu şekildedir:

Call Stack                          LAX16_N4_Loop_M16gas_1
CPU Time by Utilization             157.926s
CPU Time:Total by Utilization       94.1%
Overhead Time                       0us
Overhead Time:Total                 0.0%    
Module                              libmkl_mc3.so   

İşte birkaç resim:resim açıklamasını buraya girin resim açıklamasını buraya girin

Sonuç:

Profil oluşturmaya gerçek bir başlangıç ​​yapıyorum, ancak hızlanmanın hala iyi olmadığını anlıyorum. Sıralı (1 Çekirdek) kod 53 saniye içinde biter . Bu, 1.1'den daha düşük bir hız!

Gerçek Soru: Hızımı artırmak için ne yapmalıyım?

Sanırım yardımcı olabilecek şeyler ama emin olamıyorum:

  • Pthreads uygulaması
  • MPI (ScaLapack) uygulaması
  • Manuel Ayarlama (Nasıl yapılacağını bilmiyorum. Bunu önerirseniz lütfen bir kaynak önerin)

Daha fazla ayrıntıya (özellikle bellekle ilgili) ihtiyacınız varsa, lütfen neyi ve nasıl çalışmam gerektiğini bana bildirin. Daha önce hiç hatırlamamıştım.

Yanıtlar:


20

Matrisiniz 15.000 x 15.000 boyutundadır, bu nedenle matriste 225M elemanınız vardır. Bu yaklaşık 2GB bellek sağlar. Bu, işlemcinizin önbellek boyutundan çok daha fazlasıdır, bu nedenle her matris çarpımında tamamen ana bellekten yüklenmesi gerekir, bu da yaklaşık 100GB veri aktarımı, ayrıca kaynak ve hedef vektörler için ihtiyacınız olanı yapar.

İ3'ün maksimum bellek bant genişliği, Intel özelliklerine göre yaklaşık 21 GB / s'dir, ancak web'e bakarsanız, bunun en fazla yarısının gerçekte gerçekten kullanılabilir olduğunu göreceksiniz. Böylece, en azından, karşılaştırmanızın 10 saniye sürmesini beklersiniz ve gerçek 45 saniyelik ölçümünüz o işaretten çok uzakta değildir.

Aynı zamanda, yaklaşık 10 milyar kayan nokta çarpıyor ve ekliyor. Örneğin, kombinasyon için 10 saat döngüsü ve 3 GHz saat hızı göz önüne alındığında, ~ 30 saniyede çıkacaksınız. Elbette, önbellek akıllıysa spekülatif bellek yükleriyle aynı anda çalışabilirler.

Sonuçta, çok uzakta olmadığını söyleyebilirim. Ne beklerdiniz?


En az 2-3 hız kazanmanın bir yolu yok mu?
tahkikat

@Nunoxic - SiSoftware Sandra gibi bir araç kullanarak sisteminizdeki bellek performansını karşılaştırmak isteyebilirsiniz. Wolfgangs analizi bana gözüküyor, eğer uygulamanız bellek bant genişliğine bağlıysa, paralellik hiç yardımcı olmaz. Ayrıca, sahip olabileceğiniz güç tasarrufu seçeneklerine bakın, bunlar bellek performansını daraltıyor olabilir. Ayrıca, belleğinizi daha kaliteli bellekle değiştirmeyi düşünün, örneğin daha düşük bir CAS gecikmesi duvar sürenizde büyük bir fark yaratabilir.
Mark Booth

4

Matris-vektör çarpanını nasıl yapıyorsunuz? Elle çift döngü mü? Yoksa BLAS'ı mı arıyorsunuz? MKL kullanıyorsanız, dişli sürümün BLAS rutinlerini kullanmanızı şiddetle tavsiye ederim.

Meraktan, kendi ayarlanmış ATLAS sürümünüzü derlemek ve bunun sorununuzda nasıl olduğunu görmek isteyebilirsiniz .

Güncelleme

Aşağıdaki yorumlardaki tartışmanın ardından, Intel Core i3-330M'nizin yalnızca iki "gerçek" çekirdeği olduğu ortaya çıkıyor. İki eksik çekirdek hiper iş parçacığıyla taklit edilir . Hiper iş parçacıklı çekirdeklerde hem bellek veri yolu hem de kayan nokta birimleri paylaşıldığından, ikisinden herhangi biri sınırlayıcı bir faktörse hız kazanmazsınız. Aslında, dört çekirdek kullanmak muhtemelen işleri yavaşlatır.

"Sadece" iki çekirdek üzerinde ne tür sonuçlar elde edersiniz?


ATLA, GoTo ve Netlib BLAS'ı denedim. Performans açısından hepsi MKL'den daha zayıf. Bu bekleniyor mu yoksa yanlış bir şey mi yapıyorum? ATLAS'ı el kitabında belirtildiği gibi derledim. Ayrıca, (tam) kodumu buraya yapıştırdım . MKL'nin BLAS'ı çağırıyor.
tahkikat

Tamam ve ölçeklendirme için, temel durumunuzda kodun yalnızca tek bir CPU'da çalıştığından emin misiniz? Örneğin, kıyaslama yaparsanız, CPU kullanım histogramında yalnızca tek bir çekirdek mi gösterilir?
Pedro

Evet. CPU histogramı 1 çekirdek gösterir.
tahkikat

Yine meraktan, iki veya üç çekirdek için ne elde edersiniz? Makinenizin aslında dört fiziksel çekirdeği mi yoksa hiper iş parçacıklı iki çekirdeği mi var?
Pedro

Bunu nasıl bulabilirim? Ben ana KMP_AFFINITY ana dahil.
tahkikat

0

Ben bellek erişim süreleri, önbellek satırları kullanımı ve TLB özledim açısından bu sorun için satır-büyük sipariş en uygun izlenim var. Sanırım FORTRAN sürümünüzün neden C sürümünden sürekli daha yavaş olduğunu açıklayabilen sütun-büyük sipariş kullandı.

Daha önce de belirtildiği gibi, burada sınırlı bellek bant genişliğiniz var. Ne yanlış gidebilir ki vektörbönbellekte tutulmaz. Size_N = 15000 için size_N = 15000 için aynı (etkin) bellek bant genişliğini gözlemleyip gözlemlemediğinizi test edebilirsiniz. Bunu yaparsanız, kodun zaten optimum olması ve sisteminizin bellek bant genişliğinin basit olması mümkündür. o kadar da harika değil.

Matrisin tüm öğelerini matris vektör çarpımı yerine tek bir döngüde toplarsanız, hızı da test edebilirsiniz. (Döngüyü bir faktör 4 ile açmak isteyebilirsiniz, çünkü eklemenin ilişkilendirilmemesi derleyicinin bu optimizasyonu sizin için yapmasını engelleyebilir.)

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.