Проблемы с производительностью CPU/Intel OpenCL, вопросы реализации

У меня есть некоторые вопросы, висящие в воздухе без ответа в течение нескольких дней. Вопросы возникли из-за того, что у меня есть OpenMP и OpenCL-реализации одной и той же проблемы. OpenCL отлично работает на GPU, но на 50% меньше производительности при работе на процессоре (по сравнению с реализацией OpenMP). A post уже имеет дело с разницей между OpenMP и OpenCL, но это не отвечает на мои вопросы. На данный момент я сталкиваюсь с этими вопросами:

1) Действительно ли важно иметь " векторное ядро ​​" (с точки зрения Intel Offline Compiler)?

Существует подобный пост, но я думаю, что мой вопрос более общий.

Как я понимаю: векторизованное ядро ​​не обязательно означает, что в скомпилированном двоичном файле нет команды vector/SIMD. Я проверил ассемблерные коды моих ядер, и есть куча инструкций SIMD. Векторное ядро ​​означает, что с помощью инструкций SIMD вы можете выполнять 4 (SSE) или 8 (AVX) OpenCL "логических" потоков в одном потоке процессора. Это может быть достигнуто только в том случае, если ВСЕ ваши данные последовательно хранятся в памяти. Но у кого есть такие отлично отсортированные данные?

Итак, мой вопрос: действительно ли важно, чтобы ваше ядро ​​ "векторизовало" в этом смысле?

Конечно, это дает повышение производительности, но если большая часть вычислительных массивов в ядре выполняется векторными инструкциями, вы можете приблизиться к "оптимальной" производительности. Я думаю, что ответ на мой вопрос заключается в пропускной способности памяти. Вероятно, векторные регистры лучше подходят для эффективного доступа к памяти. В этом случае аргументы ядра (указатели) должны быть векторизованы.

2) Если я выделить данные в локальной памяти на ЦП, где это будет выделено? OpenCL показывает кеш L1 как локальную память, но, очевидно, это не тот же тип памяти, что и в локальной памяти GPU. Если он хранится в ОЗУ/глобальной памяти, тогда нет смысла копировать в него данные. Если бы он был в кеше, какой-то другой процесс мог бы вывести его из строя... так что это тоже не имеет смысла.

3) Как "логические" потоки OpenCL сопоставляются с реальными потоками программного обеспечения/аппаратного обеспечения Intel (Intel HTT)? Поскольку, если у меня есть короткие ядра и ядра раздвоены, как в TBB (Блоки Thread Building) или OpenMP, тогда преобладают служебные данные fork.

4) Что такое поток fork накладные расходы? Появляются ли новые потоки процессора для любых "логических" потоков OpenCL или потоки CPU, раздвоенные один раз и повторно используемые для более "логических" потоков OpenCL?

Надеюсь, что я не единственный, кто интересуется этими крошечными вещами, и некоторые из вас могут теперь немного решить эти проблемы. Заранее благодарю вас!


UPDATE

3) В настоящее время служебные данные OpenCL более значимы, чем OpenMP, поэтому для эффективного выполнения во время выполнения требуются тяжелые ядра. В Intel OpenCL рабочая группа сопоставляется с потоком TBB, поэтому 1 виртуальное ядро ​​процессора выполняет целую рабочую группу (или блок потоков). Рабочая группа реализована с 3-мя вложенными циклами, где, если это возможно, векторизован внутренний цикл. Поэтому вы могли бы представить себе что-то вроде:

#pragam omp parallel for
for(wg=0; wg < get_num_groups(2)*get_num_groups(1)*get_num_groups(0); wg++) {

  for(k=0; k<get_local_size(2); k++) {
    for(j=0; j<get_local_size(1); j++) {
      #pragma simd
      for(i=0; i<get_local_size(0); i++) {
        ... work-load...
      }
    }
  }
}

Если внутренняя часть цикла может быть векторизована, она выполняет шаги SIMD:

for(i=0; i<get_local_size(0); i+=SIMD) {

4) Каждый поток TBB разворачивается один раз во время выполнения OpenCL, и они повторно используются. Каждый поток TBB привязан к виртуальному ядру, т.е. во время вычисления нет миграции нитей.

Я также принимаю ответ @natchouf-s.

Ответ 1

У меня может быть несколько намеков на ваши вопросы. В моем маленьком опыте хорошая реализация OpenCL, настроенная для CPU, не может превзойти хорошую реализацию OpenMP. Если это так, вы, вероятно, можете улучшить код OpenMP, чтобы побить OpenCL.

1) Очень важно иметь векторизованные ядра. Он связан с вашим вопросом номер 3 и 4. Если у вас есть ядро, которое обрабатывает 4 или 8 входных значений, у вас будет намного меньше рабочих элементов (потоков) и, следовательно, намного меньше накладных расходов. Я рекомендую использовать векторные инструкции и данные, предоставленные OpenCL (например, float4, float8, float16) вместо того, чтобы полагаться на автоинъекцию. Не стесняйтесь использовать float16 (или double16): это будет отображаться в 4 sse или 2 avx-векторах и будет делить на 16 количество требуемых рабочих элементов (что хорошо для CPU, но не всегда для GPU: я использую 2 разных ядра для CPU и GPU).

2) Локальная память на CPU - это ОЗУ. Не используйте его на ядре процессора.

3 и 4) Я действительно не знаю, это будет зависеть от реализации, но для меня важны накладные расходы fork.

Ответ 2

для вопроса 3:

Интеграция логических потоков OpenCL в Intel в один аппаратный поток. и размер группы может варьироваться от 4, 8 до 16. Логическая карта потока OpenCL на одну SIMD-полосу исполнительного блока. один исполнительный блок имеет два SIMD-двигателя с шириной 4. более подробную информацию см. в следующем документе. https://software.intel.com/sites/default/files/Faster-Better-Pixels-on-the-Go-and-in-the-Cloud-with-OpenCL-on-Intel-Architecture.pdf