Boost.Compute atau komputasi paralel GPU / CPU. Bagian 1

pengantar



Halo, Habr!



Menurut standar saya, saya telah menulis kode C ++ sejak lama, tetapi hingga saat itu saya belum menemukan tugas-tugas yang berkaitan dengan komputasi paralel. Saya belum melihat satu artikel pun tentang pustaka Boost.Compute, jadi artikel ini akan membahasnya.

Semua bagian





Kandungan



  • Apa itu boost.compute
  • Masalah saat menghubungkan boost.compute ke proyek
  • Pengantar boost.compute
  • Kelas komputasi dasar
  • Mulai
  • Kesimpulan


Apa itu boost.compute



Library c ++ ini menyediakan antarmuka tingkat tinggi yang sederhana untuk berinteraksi dengan perangkat komputasi CPU dan GPU multi-core. Pustaka ini pertama kali ditambahkan untuk meningkatkan di versi 1.61.0 dan masih didukung.



Masalah saat menghubungkan boost.compute ke proyek



Jadi, saya mengalami beberapa masalah saat menggunakan pustaka ini. Salah satunya adalah bahwa perpustakaan tidak berfungsi tanpa OpenCL. Kompilator memberikan kesalahan berikut:



gambar



Setelah menghubungkan semuanya harus dikompilasi dengan benar.



Dengan mengorbankan pustaka dorongan, itu dapat diunduh dan dihubungkan ke proyek Visual Studio menggunakan manajer paket NuGet.



Pengantar boost.compute



Setelah menginstal semua komponen yang diperlukan, Anda dapat melihat potongan kode sederhana. Untuk operasi yang benar, cukup dengan mengaktifkan modul komputasi dengan cara ini:



#include <boost/compute.hpp>
using namespace boost;


Perlu dicatat bahwa kontainer stl biasa tidak cocok untuk digunakan dalam algoritme ruang nama komputasi. Sebaliknya, ada wadah yang dibuat khusus yang tidak bertentangan dengan yang standar. Kode sampel:



std::vector<float> std_vector(10);
compute::vector<float> compute_vector(std_vector.begin(), std_vector.end(), queue); 
//       ,     .


Anda dapat menggunakan fungsi copy () untuk mengonversi kembali ke std :: vector:



compute::copy(compute_vector.begin(), compute_vector.end(), std_vector.begin(), queue);


Kelas komputasi dasar



Pustaka ini mencakup tiga kelas tambahan, yang cukup untuk memulai dengan penghitungan pada kartu video dan / atau prosesor:



  • compute :: device (akan menentukan perangkat mana yang akan kita gunakan)
  • compute :: context (objek kelas ini menyimpan sumber daya OpenCL, termasuk buffer memori dan objek lain)
  • compute :: command_queue (menyediakan antarmuka untuk berinteraksi dengan perangkat komputasi)


Anda dapat mendeklarasikan semuanya seperti ini:



auto device = compute::system::default_device(); //     
auto context = compute::context::context(device); //   
auto queue = compute::command_queue(context, device); //   


Meskipun hanya menggunakan baris pertama kode di atas, Anda dapat memastikan bahwa semuanya berfungsi sebagaimana mestinya dengan menjalankan kode berikut:



std::cout << device.name() << std::endl; 


Jadi, kami mendapatkan nama perangkat tempat kami akan melakukan penghitungan. Hasil (Anda mungkin memiliki sesuatu yang berbeda):



gambar



Mulai



Mari kita lihat fungsi trasform () dan reduce () dengan contoh:



std::vector<float> host_vec = {1, 4, 9};

compute::vector<float> com_vec(host_vec.begin(), host_vec.end(), queue);
//           
//  copy()

compute::vector<float> buff_result(host_vec.size(), context);
transform(com_vec.begin(), com_vec.end(), buff_result.begin(), compute::sqrt<float>(), queue);

std::vector<float> transform_result(host_vec.size());
compute::copy(buff_result.begin(), buff_result.end(), transform_result.begin(), queue);
	
cout << "Transforming result: ";
for (size_t i = 0; i < transform_result.size(); i++)
{
	cout << transform_result[i] << " ";
}
cout << endl;

float reduce_result;
compute::reduce(com_vec.begin(), com_vec.end(), &reduce_result, compute::plus<float>(),queue);

cout << "Reducing result: " << reduce_result << endl;


Ketika Anda menjalankan kode di atas, Anda akan melihat hasil berikut:



gambar



Saya memilih dua metode ini karena mereka menunjukkan dengan baik pekerjaan primitif dengan komputasi paralel tanpa semuanya berlebihan.



Jadi, fungsi transform () digunakan untuk mengubah array data (atau dua array, jika kita meneruskannya) dengan menerapkan satu fungsi ke semua nilai.



transform(com_vec.begin(), 
   com_vec.end(), 
   buff_result.begin(), 
   compute::sqrt<float>(), 
   queue);


Mari kita lanjutkan ke parsing argumen, dengan dua argumen pertama kita melewatkan vektor data input, dengan argumen ketiga kita meneruskan pointer ke awal vektor tempat kita akan menulis hasilnya, dengan argumen berikutnya kita menunjukkan apa yang perlu kita lakukan. Dalam contoh di atas, kami menggunakan salah satu fungsi pemrosesan vektor standar, yaitu mengekstrak akar kuadrat. Tentu saja, Anda dapat menulis fungsi khusus, boost memberi kami dua cara lengkap, tetapi ini sudah menjadi bahan untuk bagian selanjutnya (jika ada sama sekali). Nah, sebagai argumen terakhir, kami meneruskan objek dari kelas compute :: command_queue, yang saya bicarakan di atas.



Fungsi selanjutnya adalah reduce (), semuanya menjadi sedikit lebih menarik di sini. Metode ini mengembalikan hasil penerapan argumen keempat ke semua elemen vektor.



compute::reduce(com_vec.begin(), 
   com_vec.end(), 
   &reduce_result, 
   compute::plus<float>(),
   queue);


Sekarang saya akan menjelaskan dengan sebuah contoh, kode di atas dapat dibandingkan dengan persamaan berikut:

1+4+9

Dalam kasus kami, kami mendapatkan jumlah dari semua elemen dalam array.



Kesimpulan



Nah itu saja, saya rasa ini cukup untuk melakukan operasi sederhana pada data besar. Sekarang Anda dapat menggunakan fungsionalitas primitif dari pustaka boost.compute, dan Anda juga dapat mencegah beberapa kesalahan saat bekerja dengan pustaka ini.



Saya akan senang menerima umpan balik yang positif. Terima kasih atas waktu Anda.



Semoga beruntung untuk semuanya!



All Articles