Kedengarannya Anda menginginkan cara untuk mengevaluasi seberapa terikat FPU kode Anda, atau seberapa efektif Anda menggunakan FPU, daripada menghitung jumlah flop sesuai dengan definisi anachronistic yang sama dari "flop". Dengan kata lain, Anda menginginkan metrik yang mencapai puncak yang sama jika setiap unit floating point berjalan dengan kapasitas penuh setiap siklus. Mari kita lihat Intel Sandy Bridge untuk melihat bagaimana hal ini bisa terjadi.
Operasi floating point yang didukung perangkat keras
Chip ini mendukung instruksi AVX , jadi register sepanjang 32 byte (memegang 4 ganda). Arsitektur superscalar memungkinkan instruksi untuk tumpang tindih, dengan sebagian besar instruksi aritmatika mengambil beberapa siklus untuk menyelesaikan, meskipun instruksi baru mungkin dapat dimulai pada siklus berikutnya. Semantik ini biasanya disingkat dengan menulis latency / invers throughput, nilai 5/2 akan berarti bahwa instruksi membutuhkan 5 siklus untuk menyelesaikan, tetapi Anda dapat memulai instruksi baru setiap siklus lainnya (dengan asumsi bahwa operan tersedia, sehingga tidak ada data ketergantungan dan tidak menunggu ingatan).
Ada tiga unit aritmatika floating point per inti, tetapi yang ketiga tidak relevan dengan diskusi kita, kita akan memanggil dua unit A dan M yang relevan karena fungsi utamanya adalah penjumlahan dan perkalian. Instruksi contoh (lihat tabel Agner Fog )
vaddpd
: penambahan dikemas, menempati unit A untuk 1 siklus, latensi / keluaran terbalik adalah 3/1
vmulpd
: perkalian paket, unit M, 5/1
vmaxpd
: dikemas pilih maksimum berpasangan, unit A, 3/1
vdivpd
: paket split, unit M (dan beberapa A), 21/20 hingga 45/44 tergantung pada input
vsqrtpd
: dikemas akar kuadrat, beberapa A dan M, 21/21 hingga 43/43 tergantung pada input
vrsqrtps
: dikemas akar kuadrat resiprokal resiprokal rendah untuk input presisi tunggal (8 floats
)
Semantik yang tepat untuk apa yang bisa tumpang tindih vdivpd
dan vsqrtpd
tampaknya halus dan AFAIK, tidak didokumentasikan di mana pun. Dalam sebagian besar penggunaan, saya pikir ada sedikit kemungkinan untuk tumpang tindih, meskipun kata-kata dalam manual menunjukkan bahwa beberapa utas mungkin menawarkan lebih banyak kemungkinan untuk tumpang tindih dalam instruksi ini. Kita dapat menekan jepit puncak jika kita memulai vaddpd
dan vmulpd
pada setiap siklus, dengan total 8 jepit per siklus. Multiply matrix-matrix padat ( dgemm
) dapat mendekati puncak ini.
Ketika menghitung jepit untuk instruksi khusus, saya akan melihat berapa banyak FPU ditempati. Misalkan untuk argumen bahwa dalam rentang input Anda, vdivpd
ambil rata-rata 24 siklus untuk menyelesaikan, unit yang sepenuhnya menempati M, tetapi penambahan dapat (jika tersedia) dieksekusi secara bersamaan selama setengah siklus. FPU mampu melakukan 24 penggandaan paket dan 24 penambahan paket selama siklus tersebut (diselingi dengan sempurna vaddpd
dan vmulpd
), tetapi dengan a vdivpd
, yang terbaik yang bisa kita lakukan adalah 12 tambahan tambahan yang dikemas. Jika kita mengira bahwa cara terbaik untuk melakukan pembagian adalah dengan menggunakan perangkat keras (wajar), kita dapat menghitung vdivpd
36 "jepit" yang dikemas, yang menunjukkan bahwa kita harus menghitung setiap skalar yang dibagi sebagai 36 "jepit".
Dengan root kuadrat resiprokal, kadang-kadang mungkin untuk mengalahkan perangkat keras, terutama jika akurasi penuh tidak diperlukan, atau jika rentang inputnya sempit. Seperti disebutkan di atas, vrsqrtps
instruksinya sangat murah, jadi (jika dalam presisi tunggal) Anda dapat melakukan satu vrsqrtps
diikuti oleh satu atau dua iterasi Newton untuk membersihkan. Iterasi Newton ini adil
y *= (3 - x*y*y)*0.5;
Jika banyak dari operasi ini perlu dilakukan, ini bisa secara signifikan lebih cepat daripada evaluasi naif y = 1/sqrt(x)
. Sebelum ketersediaan perangkat keras perkiraan akar kuadrat resiprokal, beberapa kode peka kinerja menggunakan operasi integer terkenal untuk menemukan tebakan awal untuk iterasi Newton.
Fungsi matematika yang disediakan perpustakaan
Kita bisa menerapkan heuristik yang mirip dengan fungsi matematika yang disediakan perpustakaan. Anda dapat membuat profil untuk menentukan jumlah instruksi SSE, tetapi seperti yang telah kita bahas, itu bukan keseluruhan cerita dan sebuah program yang menghabiskan seluruh waktunya mengevaluasi fungsi-fungsi khusus mungkin tidak tampak mendekati puncak, yang mungkin benar, tetapi tidak berguna untuk memberi tahu Anda bahwa semua waktu dihabiskan di luar kendali Anda di FPU.
Saya sarankan menggunakan perpustakaan vektor matematika yang baik sebagai baseline (misalnya Intel VML, bagian dari MKL). Ukur jumlah siklus untuk setiap panggilan dan kalikan dengan jepit puncak yang dapat dicapai atas jumlah siklus itu. Jadi, jika eksponensial yang dikemas membutuhkan 50 siklus untuk mengevaluasi, hitunglah 100 kali lipat lebar register. Sayangnya, pustaka vektor matematika kadang-kadang sulit untuk dipanggil dan tidak memiliki semua fungsi khusus, sehingga Anda mungkin akhirnya melakukan skalar matematika, dalam hal ini Anda akan menghitung eksponensial skalar hipotetis kami sebagai 100 jepit (walaupun mungkin masih membutuhkan 50 siklus, jadi Anda hanya akan mendapatkan 25% dari "puncak" jika semua waktu dihabiskan untuk mengevaluasi eksponensial ini).
Seperti yang disebutkan orang lain, Anda dapat menghitung siklus dan penghitung acara perangkat keras menggunakan PAPI atau berbagai antarmuka. Untuk penghitungan siklus sederhana, Anda dapat membaca penghitung siklus secara langsung menggunakan rdtsc
instruksi dengan potongan rakitan inline.