Mengapa Penskalaan Multiplikasi Matriks-Vektor saya tidak?

15

Maaf untuk posting lama tapi saya ingin memasukkan semua yang saya pikir relevan pada langkah pertama.

Apa yang saya inginkan

Saya menerapkan versi paralel dari Metode Subruang Krylov untuk Matriks Padat.Terutama GMRES, QMR dan CG. Saya menyadari (setelah membuat profil) bahwa rutinitas DGEMV saya menyedihkan. Jadi saya memutuskan untuk berkonsentrasi pada hal itu dengan mengisolasinya. Saya telah mencoba menjalankannya pada mesin 12 inti tetapi hasilnya di bawah ini untuk Laptop 4 core Intel i3. Tidak ada banyak perbedaan dalam tren.

KMP_AFFINITY=VERBOSEOutput saya tersedia di sini .

Saya menulis kode kecil:

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

Saya percaya ini mensimulasikan perilaku CG untuk 50 iterasi.

Apa yang saya coba:

Terjemahan

Saya awalnya menulis kode di Fortran. Saya menerjemahkannya ke C, MATLAB dan Python (Numpy). Tak perlu dikatakan, MATLAB dan Python mengerikan.Anehnya, C lebih baik daripada FORTRAN dalam satu atau dua detik untuk nilai-nilai di atas. Secara konsisten.

Pembuatan profil

Saya memrofilkan kode saya untuk dijalankan dan berjalan selama beberapa 46.075detik. Inilah saat MKL_DYNAMIC disetel keFALSE dan semua core digunakan. Jika saya menggunakan MKL_DYNAMIC sebagai true, hanya (kurang-lebih) setengah dari jumlah core yang digunakan pada suatu titik waktu tertentu. Berikut ini beberapa detailnya:

Address Line    Assembly                CPU Time

0x5cb51c        mulpd %xmm9, %xmm14     36.591s

Proses yang paling memakan waktu adalah:

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   

Berikut beberapa foto:masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Kesimpulan:

Saya benar-benar pemula dalam membuat profil tetapi saya menyadari bahwa kecepatannya masih belum baik. Kode sekuensial (1 Core) selesai dalam 53 detik. Itu adalah kecepatan kurang dari 1,1!

Pertanyaan Sungguhan: Apa yang harus saya lakukan untuk meningkatkan kecepatan saya?

Hal-hal yang saya pikir mungkin bisa membantu tetapi saya tidak yakin:

  • Implementasi pthreads
  • Implementasi MPI (ScaLapack)
  • Penyesuaian Manual (Saya tidak tahu caranya. Mohon rekomendasikan sumber daya jika Anda menyarankan ini)

Jika ada yang membutuhkan lebih banyak (terutama mengenai memori) detail, beri tahu saya apa yang harus saya jalankan dan caranya. Saya tidak pernah mengingat memori sebelumnya.

Pemeriksaan resmi
sumber

Jawaban:

20

Matriks Anda berukuran 15.000 x 15.000, sehingga Anda memiliki 225 juta elemen dalam matriks. Ini membuat memori sekitar 2GB. Ini lebih dari ukuran cache prosesor Anda, sehingga harus dimuat sepenuhnya dari memori utama di setiap perkalian matriks, menghasilkan transfer data sekitar 100GB, ditambah apa yang Anda butuhkan untuk vektor sumber dan tujuan.

Bandwith memori maksimum i3 adalah sekitar 21 GB / s berdasarkan spesifikasi Intel, tetapi jika Anda melihat-lihat di web, Anda akan menemukan bahwa sebagian besar dari itu benar-benar tersedia dalam kenyataan. Jadi, paling tidak, Anda akan mengharapkan tolok ukur Anda bertahan 10 detik, dan pengukuran Anda yang sebenarnya selama 45 detik tidak begitu jauh dari sasaran itu.

Pada saat yang sama, Anda juga melakukan sekitar 10 miliar penggandaan dan penambahan floating point. Mempertimbangkan, katakanlah, 10 siklus clock untuk kombinasi, dan 3 clock rate GHz, Anda akan keluar pada ~ 30 detik. Tentu saja, mereka dapat berjalan bersamaan dengan banyak memori spekulatif jika cache cerdas.

Secara keseluruhan, saya katakan Anda tidak terlalu jauh dari sasaran. Apa yang Anda harapkan?

Wolfgang Bangerth
sumber
Apakah tidak ada cara untuk mendapatkan minimal 2-3 speedup?
Pemeriksaan
@Nunoxic - Anda mungkin ingin membandingkan kinerja memori pada sistem Anda menggunakan alat seperti SiSoftware Sandra. Analisis Wolfgangs terlihat tepat bagi saya, jika aplikasi Anda terikat bandwidth memori, parallelisation akan membantu sedikit jika sama sekali. Selain itu, lihat opsi penghematan daya apa pun yang Anda miliki, mereka mungkin mencekik kinerja memori. Juga, pertimbangkan mengganti memori Anda dengan memori berkualitas lebih tinggi, latensi CAS yang lebih rendah misalnya dapat membuat perbedaan besar pada waktu dinding Anda.
Mark Booth
4

Bagaimana Anda melakukan perkalian matriks-vektor? Sebuah loop ganda dengan tangan? Atau telepon ke BLAS? Jika Anda menggunakan MKL, saya akan sangat menyarankan menggunakan rutinitas BLAS dari versi berulir.

Karena penasaran, Anda mungkin juga ingin mengkompilasi versi ATLAS yang Anda setel sendiri dan melihat bagaimana hal itu terjadi pada masalah Anda.

Memperbarui

Mengikuti diskusi dalam komentar di bawah ini, ternyata Intel Core i3-330M Anda hanya memiliki dua inti "nyata". Dua core yang hilang ditiru dengan hyperthreading . Karena di core hyperthreaded baik bus memori dan unit floating-point dibagikan, Anda tidak akan mendapatkan percepatan apa pun jika salah satu dari keduanya merupakan faktor pembatas. Bahkan, menggunakan empat core bahkan mungkin akan memperlambat segalanya.

Hasil seperti apa yang Anda dapatkan pada "hanya" dua core?

Pedro
sumber
Saya sudah mencoba ATLA, GoTo dan Netlib BLAS. Semua lebih lemah dari MKL dalam kinerja. Apakah ini yang diharapkan atau saya melakukan sesuatu yang salah? Saya menyusun ATLAS sebagaimana disebutkan dalam buku pegangan. Selanjutnya, saya telah menempelkan kode (tepat) saya di sini . Itu memanggil BLAS MKL.
Pemeriksaan
Ok, dan untuk penskalaan, apakah Anda yakin bahwa dalam kasus dasar Anda, kode hanya berjalan pada satu CPU? Misalnya jika Anda membandingkannya, apakah histogram penggunaan CPU hanya menampilkan satu inti?
Pedro
Iya. CPU histogram menunjukkan 1 inti.
Pemeriksaan
Karena penasaran lagi, apa yang Anda dapatkan untuk dua atau tiga core? Apakah mesin Anda sebenarnya memiliki empat inti fisik, atau hanya dua inti saja hyperthreading ?
Pedro
Bagaimana saya mengetahui hal itu? Saya sudah memasukkan KMP_AFFINITY saya di main.
Pemeriksaan
0

Saya mendapat kesan bahwa pemesanan baris-utama adalah optimal untuk masalah ini sehubungan dengan waktu akses memori, penggunaan garis cache dan TLB meleset. Saya kira versi FORTRAN Anda menggunakan pemesanan kolom-utama sebagai gantinya, yang dapat menjelaskan mengapa ini lebih lambat daripada versi C secara konsisten.

Seperti yang sudah ditunjukkan sebelumnya, bandwidth memori Anda terbatas di sini. Apa yang mungkin salah adalah vektorbtidak disimpan dalam cache. Anda dapat menguji apakah Anda mengamati bandwidth memori yang sama (efektif) untuk size_N = 15000 daripada untuk size_N = 5000. Jika Anda melakukannya, ada peluang yang cukup bagus bahwa kodenya sudah optimal, dan bahwa bandwidth memori sistem Anda cukup sederhana. tidak terlalu bagus.

Anda juga dapat menguji kecepatan jika Anda hanya meringkas semua elemen dari matriks dalam satu lingkaran, bukan multiplikasi vektor matriks. (Anda mungkin ingin membuka gulungannya dengan faktor 4, karena penambahan non-asosiatif dapat mencegah kompiler melakukan optimasi ini untuk Anda.)

Thomas Klimpel
sumber