Pertanyaan Bagaimana saya bisa menjalankan tugas pada CPU dan perangkat GPU secara bersamaan?


Saya memiliki kode ini yang diprofilkan, dioptimalkan dan efisien cache karena saya mungkin mendapatkannya dengan tingkat pengetahuan saya. Ini berjalan pada CPU secara konseptual seperti ini:

#pragma omp parallel for schedule(dynamic)
  for (int i = 0; i < numberOfTasks; ++i)
  {
    result[i] = RunTask(i); // result is some array where I store the result of RunTask.
  }

Kebetulan itu terjadi RunTask() pada dasarnya adalah satu set operasi aljabar linier yang beroperasi berulang kali pada dataset yang sama dan sangat besar setiap waktu, jadi cocok untuk dijalankan pada GPU. Jadi saya ingin mencapai yang berikut:

  1. Offload beberapa tugas ke GPU
  2. Sementara GPU sibuk, proses sisa tugas pada CPU
  3. Untuk operasi tingkat CPU, jagalah super-duper saya RunTask() berfungsi tanpa harus memodifikasinya agar sesuai restrict(amp). Saya tentu saja bisa merancang sebuah restrict(amp) lambda compliant untuk tugas-tugas GPU.

Awalnya saya berpikir untuk melakukan hal-hal berikut:

// assume we know exactly how much time the GPU/CPU needs per task, and this is the 
// most time-efficient combination:
int numberOfTasks = 1000;
int ampTasks = 800;

// RunTasksAMP(start,end) sends a restrict(amp) kernel to the GPU, and stores the result in the
// returned array_view on the GPU
Concurrency::array_view<ResulType, 1> concurrencyResult = RunTasksAMP(0,ampTasks);

// perform the rest of the tasks on the CPU while we wait
#pragma omp parallel for schedule(dynamic)
  for (int i = ampTasks; i < numberOfTasks; ++i)
  {
    result[i] = RunTask(i); // this is a thread-safe
  }

// do something to wait for the parallel_for_each in RunTasksAMP to finish.
concurrencyResult.synchronize();
//... now load the concurrencyResult array into the first elements of "result"

Tapi aku ragu kamu bisa melakukan sesuatu seperti ini karena

Panggilan ke parallel_for_each berperilaku seolah-olah sinkron

(http://msdn.microsoft.com/en-us/library/hh305254.aspx)

Jadi, apakah mungkin untuk mencapai 1-3 permintaan saya, atau apakah saya harus membuang nomor 3? Meski begitu, bagaimana saya akan menerapkannya?


5
2017-11-05 22:44


asal


Jawaban:


Lihat jawaban saya untuk akan array_view.synchronize_asynch menunggu penyelesaian parallel_for_each? untuk penjelasan mengapa parallel_for_each dapat dianggap sebagai operasi antrian atau penjadwalan daripada yang sinkron. Ini menjelaskan mengapa kode Anda harus memenuhi persyaratan Anda 1 & 2. Ini juga harus memenuhi persyaratan 3, meskipun Anda mungkin ingin mempertimbangkan untuk memiliki satu fungsi yang restrict(cpu, amp) karena ini akan memberi Anda lebih sedikit kode untuk dipelihara.

Namun Anda mungkin ingin mempertimbangkan beberapa implikasi kinerja dari pendekatan Anda.

Pertama, itu parallel_for_each hanya antrian bekerja, salinan data dari host dan memori GPU menggunakan sumber daya host (asumsi GPU Anda diskrit dan / atau tidak mendukung salinan langsung). Jika pekerjaan Anda di host menjenuhkan semua sumber daya yang diperlukan untuk menjaga GPU bekerja maka Anda benar-benar dapat memperlambat perhitungan GPU Anda.

Kedua, untuk banyak perhitungan yang data paralel dan setuju untuk berjalan di GPU mereka jauh lebih cepat sehingga tambahan biaya tambahan untuk mencoba bekerja pada CPU tidak menghasilkan keseluruhan kecepatan. Overhead termasuk item satu (di atas) dan overhead tambahan pekerjaan koordinasi pada host (penjadwalan thread, menggabungkan hasil, dll.).

Akhirnya implementasi Anda di atas tidak memperhitungkan variabilitas apa pun dalam waktu yang dibutuhkan untuk menjalankan tugas di GPU dan CPU. Ini mengasumsikan bahwa 800 tugas AMP akan memakan waktu selama 200 tugas cpu. Ini mungkin benar pada beberapa perangkat keras tetapi tidak pada perangkat lain. Jika satu set tugas lebih lama dari yang diharapkan maka aplikasi Anda akan memblokir dan menunggu set tugas yang lebih lambat untuk menyelesaikan. Anda dapat menghindari ini menggunakan pola master / pekerja untuk menarik tugas dari antrean hingga tidak ada lagi tugas yang tersedia. Pendekatan ini berarti bahwa dalam kasus terburuk aplikasi Anda harus menunggu tugas akhir selesai, bukan blok tugas. Menggunakan pendekatan master / pekerja juga berarti bahwa aplikasi Anda akan berjalan dengan efisiensi yang sama terlepas dari kinerja CPU / GPU relatif.

Buku saya Membahas contoh penjadwalan bekerja di beberapa GPU menggunakan master / pekerja (n-body) dan antrian paralel (kartunizer). Anda dapat mengunduh kode sumber dari CodePlex. Perhatikan bahwa ini sengaja tidak mencakup kerja berbagi pada CPU dan GPU untuk alasan yang diuraikan di atas berdasarkan diskusi dengan tim produk C ++ AMP.


4
2017-11-11 16:07