Що чекає мій графічний процесор?


11

Я пишу програму OpenCL для використання з моїм графічним процесором AMD Radeon HD 7800 серії. Відповідно до посібника з програмування OpenCL AMD , це покоління GPU має дві апаратні черги, які можуть працювати асинхронно.

5.5.6 Черга команд

Для Південних островів і пізніших пристроїв підтримуються щонайменше дві апаратні черги обчислень. Це дозволяє додатку збільшити пропускну здатність невеликих відправлень з двома чергами команд для асинхронного подання та, можливо, виконання. Черги для обчислення апаратних засобів вибираються в такому порядку: перша черга = парні черги команд OCL, друга черга = непарні черги OCL.

Для цього я створив дві окремі черги команд OpenCL для подачі даних в GPU. Приблизно програма, що працює на потоці хоста, виглядає приблизно так:

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);

З kNumQueues = 1цим додатком в значній мірі працює за призначенням: він збирає всю роботу в єдину чергу команд, яка потім працює до завершення, і GPU весь час зайнятий. Я можу це побачити, дивлячись на висновок профлектора CodeXL:

введіть тут опис зображення

Однак, коли я встановлюю kNumQueues = 2, я очікую, що трапиться те саме, але робота рівномірно розділиться на дві черги. Якщо що-небудь, я очікую, що кожна черга матиме ті ж характеристики окремо, як і одна черга: що вона почне працювати послідовно, поки все не буде зроблено. Однак, використовуючи дві черги, я бачу, що не вся робота розбита на дві апаратні черги:

введіть тут опис зображення

На початку роботи GPU черги примудряються запускати деякі ядра асинхронно, хоча, здається, ніколи повністю не займають апаратні черги (якщо моє розуміння не помиляється). Під кінець роботи графічного процесора здається, що черги послідовно додають роботу лише до однієї з апаратних черг, але є навіть випадки, коли ядра не виконуються. Що дає? Чи є у мене якісь принципові нерозуміння того, як повинен вестись час виконання?

У мене є кілька теорій, чому це відбувається:

  1. Перемежовані clCreateBufferвиклики змушують GPU виділяти ресурси пристрою із спільного пулу пам'яті синхронно, який зупиняє виконання окремих ядер.

  2. Основна реалізація OpenCL не відображає логічні черги на фізичні черги, а лише вирішує, де розмістити об'єкти під час виконання.

  3. Оскільки я використовую об’єкти GL, GPU потрібно синхронізувати доступ до спеціально виділеної пам'яті під час запису.

Чи правда якесь із цих припущень? Хтось знає, що може спричинити зачеплення GPU у сценарії з двома чергами? Будь-яке розуміння буде вдячне!


Я не можу знайти там, де написано, що в посібнику з програмування є дві апаратні черги. Чи можете ви опублікувати цитату з документа? Згадайте, в якій главі сказано, що є дві черги? Чи кількість апаратних черг можна запитувати під час виконання за допомогою OpenCL?
Андреас

Я оновив свою публікацію. Це говорить про можливе виконання, але якщо він може зробити декілька, чому він не може зробити їх усі? Також час виконання OpenCL не має поняття апаратної черги, тому ви можете не запитувати.
Мокоша

Відповіді:


2

Загалом, обчислювальні черги не обов'язково означають, що тепер ви можете робити 2x відправлення паралельно. Єдина черга, яка повністю насичує обчислювальні одиниці, матиме кращу пропускну здатність. Кілька черг корисні, якщо одна черга споживає менше ресурсів (спільна пам'ять або регістри), то вторинні черги можуть потім перетинатися на одному обчислювальному блоці.

Для візуалізації в режимі реального часу це особливо стосується таких речей, як тіньовий рендерінг, який дуже легкий для обчислення / шейдерів, але важкий для апаратних засобів фіксованої функції, тим самим звільняючи планувальник графічного процесора для запуску вторинної асинхронізації черги.

Це також знайдено в примітках до випуску. Не знаю, чи це те саме питання, але може бути просто те, що CodeXL не є великим. Я б очікував, що він може мати не найкращий інструментарій, для якого відправляються рейси.

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

Для програми, яка виконує одночасну асинхронну передачу даних та виконання ядра, часова шкала, показана у вікні сеансу Трасування додатків, не буде показувати, що ці операції перекриваються. Це пояснюється тим, що водій та апаратне забезпечення змушують ці операції синхронізуватися під час профілювання. (333981)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.