SIMD Intrinsics Tidak Begitu Menakutkan, Tapi Haruskah Kita Menggunakannya?

Apakah pemrograman tingkat rendah itu dosa atau kebajikan? Tergantung.

Saat memprogram untuk menggunakan pemrosesan vektor pada prosesor modern, idealnya saya akan menulis beberapa kode dalam bahasa favorit saya dan itu akan berjalan secepat mungkin "secara otomatis".

Kecuali jika Anda baru memulai pemrograman minggu lalu, saya rasa Anda tahu bahwa dunia tidak bekerja seperti itu. Performa terbaik hanya datang dengan usaha. Karena itu pertanyaan saya: seberapa rendah kita harus pergi?

Operasi vektor ditentukan

Operasi "vektor" adalah operasi matematika yang melakukan lebih dari satu operasi. Penjumlahan vektor mungkin menambahkan delapan pasang angka, bukan penjumlahan biasa, yang hanya menambahkan sepasang angka. Pertimbangkan meminta komputer untuk menjumlahkan dua angka. Kita dapat melakukannya dengan instruksi add reguler. Pertimbangkan meminta komputer untuk menambahkan delapan pasang angka satu sama lain (hitung C1 = A1 + B1, C2 = A2 + B2,… C8 = A8 + B8). Kita dapat melakukannya dengan instruksi penambahan vektor .

Instruksi vektor meliputi penjumlahan, pengurangan, perkalian, dan operasi lainnya.

 SIMD: paralelisme untuk vektor

Ilmuwan komputer memiliki nama yang bagus untuk instruksi vektor: SIMD, atau "Single Instruction Multiple Data." Jika kita menganggap instruksi penjumlahan reguler sebagai SISD (Single Instruction Single Data) di mana single berarti sepasang input data, maka penjumlahan vektor adalah SIMD di mana kelipatan bisa berarti delapan pasang input data.

Saya suka menyebut SIMD "paralelisme perangkat keras lainnya," karena "paralelisme" di komputer begitu sering dianggap berasal dari memiliki banyak inti. Jumlah inti terus meningkat. Jumlah inti empat adalah umum, 20 atau lebih umum pada prosesor untuk server, dan jumlah inti teratas Intel saat ini adalah 72 inti dalam satu prosesor Intel® Xeon Phi ™.

Ukuran instruksi vektor juga meningkat. Instruksi vektor awal, seperti SSE, dilakukan hingga empat operasi sekaligus. Lebar vektor teratas Intel saat ini, dalam AVX-512, melakukan hingga 16 operasi sekaligus.

 Seberapa rendah kita harus pergi?

Dengan begitu banyak kinerja yang dipertaruhkan, berapa banyak pekerjaan yang harus kita lakukan untuk memanfaatkan kinerja ini?

 Jawabannya banyak, dan inilah alasannya: Empat core dapat memberikan kecepatan maksimal 4X untuk kita. AVX (setengah ukuran AVX-512, tetapi jauh lebih umum) dapat memberi kita kecepatan maksimal 8X. Jika digabungkan, mereka bisa mendapatkan hingga 32X. Melakukan keduanya sangat masuk akal.

Berikut daftar sederhana saya tentang cara mencoba mengeksploitasi instruksi vektor (dalam urutan kita harus mencoba menerapkannya):

 1.     Pertama, panggil perpustakaan yang melakukan pekerjaan (yang terakhir dalam vektorisasi implisit). Contoh pustaka semacam itu adalah Intel® Math Kernel Library (Intel® MKL). Semua pekerjaan untuk menggunakan instruksi vektor dilakukan oleh orang lain. Keterbatasannya jelas: Kita harus menemukan perpustakaan yang melakukan apa yang kita butuhkan.

2.     Kedua, gunakan vektorisasi implisit. Tetap abstrak dan tulis sendiri menggunakan templat atau kompiler untuk membantu. Banyak kompiler memiliki sakelar dan opsi vektorisasi. Kompiler cenderung menjadi cara yang paling portabel dan stabil untuk digunakan. Ada banyak template untuk vektorisasi, tetapi tidak ada yang melihat penggunaan yang cukup dari waktu ke waktu untuk menjadi pemenang yang jelas (entri terbaru adalah Intel® SIMD Data Layout Templates [Intel® SDLT]).

3.     Ketiga, gunakan vektorisasi eksplisit. Ini telah menjadi sangat populer dalam beberapa tahun terakhir, dan mencoba untuk memecahkan masalah tetap abstrak tetapi memaksa kompilator untuk menggunakan instruksi vektor ketika ia tidak akan menggunakannya. Dukungan untuk SIMD di OpenMP adalah contoh kuncinya di sini, di mana permintaan vektorisasi untuk compiler diberikan dengan sangat eksplisit. Ekstensi non-standar ada di banyak kompiler, seringkali dalam bentuk opsi atau "pragma". Jika Anda mengambil rute ini, OpenMP adalah cara yang harus ditempuh jika Anda menggunakan C, C ++, atau Fortran.

4.     Akhirnya, rendah diri dan kotor. Gunakan intrinsik SIMD. Ini seperti bahasa assembly, tetapi ditulis di dalam program C / C ++ Anda. Intrinsik SIMD sebenarnya terlihat seperti pemanggilan fungsi, tetapi umumnya menghasilkan instruksi tunggal (instruksi operasi vektor, juga dikenal sebagai instruksi SIMD).

Intrinsik SIMD tidak jahat; namun, mereka adalah pilihan terakhir. Tiga pilihan pertama selalu lebih dapat dipertahankan untuk masa depan saat berhasil. Namun, ketika tiga yang pertama gagal memenuhi kebutuhan kita, kita harus mencoba menggunakan intrinsik SIMD.

 Jika Anda ingin mulai menggunakan intrinsik SIMD, Anda akan memiliki pengalaman serius jika Anda terbiasa dengan pemrograman bahasa assembly. Hal ini terutama karena Anda akan lebih mudah membaca dokumentasi yang menjelaskan pengoperasian, termasuk "Panduan Intrinsik" online yang sangat baik dari Intel. Jika Anda benar-benar baru dalam hal ini, saya menemukan blog baru-baru ini ("SSE: mind the gap!") Yang dengan lembut memperkenalkan intrinsik. Saya juga suka "Mengolah Angka dengan AVX dan AVX2".

 Jika perpustakaan atau kompiler dapat melakukan apa yang Anda butuhkan, intrinsik SIMD bukanlah pilihan terbaik. Namun, mereka memiliki tempatnya dan tidak sulit digunakan setelah Anda terbiasa. Cobalah. Manfaat kinerja bisa luar biasa. Saya telah melihat intrinsik SIMD digunakan oleh programmer pintar untuk kode yang tidak mungkin dihasilkan oleh kompiler.

Bahkan jika kita mencoba intrinsik SIMD, dan akhirnya membiarkan perpustakaan atau kompilator melakukan pekerjaannya, apa yang kita pelajari dapat sangat berharga dalam memahami penggunaan terbaik perpustakaan atau kompilator untuk vektorisasi. Dan itu mungkin alasan terbaik untuk mencoba intrinsik SIMD saat kita membutuhkan sesuatu untuk menggunakan instruksi vektor.

Klik di sini untuk mengunduh uji coba gratis 30 hari Intel Parallel Studio XE Anda