Apa yang GPU saya tunggu?

11

Saya menulis program OpenCL untuk digunakan dengan GPU AMD Radeon HD 7800 series saya. Menurut panduan pemrograman OpenCL AMD , generasi GPU ini memiliki dua antrian perangkat keras yang dapat beroperasi secara tidak sinkron.

5.5.6 Perintah Antrian

Untuk Kepulauan Selatan dan yang lebih baru, perangkat mendukung setidaknya dua antrian penghitungan perangkat keras. Itu memungkinkan aplikasi untuk meningkatkan throughput kiriman kecil dengan dua antrian perintah untuk pengiriman asinkron dan kemungkinan eksekusi. Antrian penghitungan perangkat keras dipilih dalam urutan berikut: antrian pertama = bahkan antrian perintah OCL, antrian kedua = antrian OCL ganjil.

Untuk melakukan ini, saya telah membuat dua antrian perintah OpenCL terpisah untuk memasukkan data ke GPU. Secara kasar, program yang berjalan di utas host terlihat seperti ini:

static const int kNumQueues = 2;
cl_command_queue default_queue;
cl_command_queue work_queue[kNumQueues];

static const int N = 256;
cl_mem gl_buffers[N];
cl_event finish_events[N];

clEnqueueAcquireGLObjects(default_queue, gl_buffers, N);

int queue_idx = 0;
for (int i = 0; i < N; ++i) {
  cl_command_queue queue = work_queue[queue_idx];

  cl_mem src = clCreateBuffer(CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ...);

  // Enqueue a few kernels
  cl_mem tmp1 = clCreateBuffer(CL_READ_WRITE);
  clEnqueueNDRangeKernel(kernel1, queue, src, tmp1);

  clEnqueueNDRangeKernel(kernel2, queue, tmp1, tmp1);

  cl_mem tmp2 = clCreateBuffer(CL_READ_WRITE);
  clEnqueueNDRangeKernel(kernel2, queue, tmp1, tmp2);

  clEnqueueNDRangeKernel(kernel3, queue, tmp2, gl_buffer[i], finish_events + i);

  queue_idx = (queue_idx + 1) % kNumQueues;
}

clEnqueueReleaseGLObjects(default_queue, gl_buffers, N);
clWaitForEvents(N, finish_events);

Dengan kNumQueues = 1, aplikasi ini cukup berfungsi sebagaimana mestinya: aplikasi ini mengumpulkan semua pekerjaan menjadi satu antrian perintah yang kemudian berjalan hingga selesai dengan GPU yang cukup sibuk sepanjang waktu. Saya dapat melihat ini dengan melihat output dari profiler CodeXL:

masukkan deskripsi gambar di sini

Namun, ketika saya mengatur kNumQueues = 2, saya berharap hal yang sama terjadi tetapi dengan pekerjaan terbagi rata dalam dua antrian. Jika ada, saya berharap setiap antrian memiliki karakteristik yang sama secara individual dengan antrian satu: bahwa antrian mulai bekerja secara berurutan sampai semuanya selesai. Namun, ketika menggunakan dua antrian, saya dapat melihat bahwa tidak semua pekerjaan dibagi di antara dua antrian perangkat keras:

masukkan deskripsi gambar di sini

Pada awal pekerjaan GPU, antrian berhasil menjalankan beberapa kernel secara serempak, meskipun sepertinya tidak pernah sepenuhnya menempati antrian perangkat keras (kecuali pemahaman saya salah). Menjelang akhir kerja GPU, sepertinya antrian menambahkan pekerjaan secara berurutan hanya ke salah satu antrian perangkat keras, tetapi bahkan ada saat-saat ketika kernel tidak berjalan. Apa yang menyebabkannya? Apakah saya memiliki beberapa kesalahpahaman mendasar tentang bagaimana seharusnya runtime berperilaku?

Saya punya beberapa teori mengapa ini terjadi:

  1. clCreateBufferPanggilan yang diselingi memaksa GPU untuk mengalokasikan sumber daya perangkat dari kumpulan memori bersama secara sinkron yang menghentikan eksekusi kernel individual.

  2. Implementasi OpenCL yang mendasarinya tidak memetakan antrian logis ke antrian fisik, dan hanya memutuskan tempat untuk meletakkan objek saat runtime.

  3. Karena saya menggunakan objek GL, GPU perlu menyinkronkan akses ke memori yang dialokasikan secara khusus selama penulisan.

Adakah asumsi-asumsi ini yang benar? Adakah yang tahu apa yang menyebabkan GPU menunggu dalam skenario dua-antrian? Setiap dan semua wawasan akan sangat dihargai!

Mokosha
sumber
Saya tidak dapat menemukan di mana dikatakan ada dua antrian perangkat keras dalam panduan pemrograman. Bisakah Anda memposting kutipan dari dokumen? Sebutkan bab mana yang mengatakan ada dua antrian? Apakah jumlah antrian perangkat keras dapat ditanyakan dalam runtime menggunakan OpenCL?
Andreas
Saya telah memperbarui posting saya. Memang dikatakan eksekusi yang mungkin , tetapi jika bisa melakukan beberapa mengapa tidak bisa melakukan semuanya? Juga runtime OpenCL tidak memiliki gagasan tentang antrian perangkat keras, jadi itu bukan sesuatu yang dapat Anda query.
Mokosha

Jawaban:

2

Hitung antrian secara umum tidak berarti Anda sekarang dapat melakukan pengiriman 2x secara paralel. Satu antrian yang sepenuhnya memenuhi unit komputasi akan memiliki throughput yang lebih baik. Beberapa antrian berguna jika satu antrian menghabiskan lebih sedikit sumber daya (memori bersama atau register), maka antrian sekunder kemudian dapat tumpang tindih pada unit komputasi yang sama.

Untuk rendering real-time ini terutama terjadi dengan hal-hal seperti rendering bayangan yang sangat ringan pada komputasi / shader tetapi berat pada perangkat keras fungsi tetap, sehingga membebaskan scheduler GPU untuk menjalankan async antrian sekunder.

Juga menemukan ini di catatan rilis. Tidak tahu apakah ini masalah yang sama, tetapi mungkin CodeXL tidak bagus. Saya berharap bahwa itu mungkin tidak memiliki instrumentasi terbaik yang pengirimannya dalam penerbangan.

https://developer.amd.com/wordpress/media/2013/02/AMD_CodeXL_Release_Notes.pdf

Untuk aplikasi yang melakukan transfer data asinkron dan eksekusi kernel secara simultan, garis waktu yang ditunjukkan dalam tampilan sesi Jejak Aplikasi tidak akan menunjukkan operasi ini tumpang tindih. Ini karena driver dan perangkat keras memaksa operasi ini agar sinkron saat membuat profil. (333981)

Calvin
sumber