Режим разгрузки фи Xeon, как использовать преимущества параллелизма потоков и векторизации

Я делаю некоторые тесты производительности на Xeon Phi с использованием Cilk Plus с разгрузкой.

В простой программе векторного добавления у меня есть 2 способа сделать это:

  1. использование cilk_for для разделения задач на разные потоки в Xeon phi:

    __declspec(target(mic)) void vector_add(double *A,double *B,double *C,
    int  vector_size)
    {
    _Cilk_for(int i=0;i<vector_size;i++)
    {
    C[i] +=  A[i] + B[i];
    }
    }
    double *A,*B,*C;
    //allocating and initializing  A, B ,C using malloc.....
    #pragma offload target(mic:0) \
    in(B:length(vector_size)) \
    in(A:length(vector_size)) \
    in(C:length(vector_size)) \
    in(vector_size )
    {
    vector_add(A,B,C,vector_size);
    }
    
  2. Используя векторную аннотацию:

    double *A,*B,*C;
    //allocating and initializing  A, B ,C using malloc.....
    #pragma offload target(mic:0) \
    in(B:length(vector_size)) \
    in(A:length(vector_size)) \
    in(C:length(vector_size))
    //in(vector_size )
    //signal(offload0)
    {
    C[0:vector_size] = A[0:vector_size]+B[0:vector_size];
    }
    

Мой тест показывает, что первый способ в ~ 10 раз быстрее, чем второй на xeon phi. Та же самая история происходит, когда я не разгружаю и запускаю его на хост-процессоре Xeon E5.

Сначала я хочу знать, правильно ли мое понимание:

Первый способ использует только параллелизм потоков (60 ядер * по 4 потока в каждом) в XEON phi. Но никакая векторная операция не будет выполнена.

Второй способ использует векторизацию только потому, что этот код будет выполняться только в одном потоке с использованием инструкций SIMD (IMCI).

Во-вторых, я хотел бы знать, как правильно написать это так, чтобы он одновременно разделял задачи на разные потоки и использовал векторные инструкции на Xeon phi?

Заранее спасибо.

0

Решение

На самом деле, если вы посмотрите на отчеты по оптимизации, которые создает компилятор (-opt-report), или на вывод VTune, если он у вас есть, вы можете быть удивлены. Ваш второй пример, как вы и предполагали, только векторизован. Тем не менее, ваш первый пример также может векторизовать в дополнение к распараллеливанию. Помните, что _Cilk_for не раздает отдельные итерации, а порции итераций, которые в некоторых случаях могут быть векторизованы.

Для лучшего контроля вы можете попробовать поэкспериментировать с вложенными циклами, чтобы явно разделить параллельные и векторные циклы, или поиграться с размером зерна, чтобы изменить объем работы, над которой должен работать поток в любой момент времени, или несколько разных прагм.

Для совета по оптимизации специально для сопроцессора Intel Xeon Phi, я хотел бы указать людям на https://software.intel.com/en-us/articles/programming-and-compiling-for-intel-many-integrated-core-architecture, но я думаю, что вы могли бы найти что-то слишком простое Тем не менее, если вы хотите копаться в ….

1

Другие решения