Подтвердить что ты не робот

GCC генерирует совершенно другой код, используя "-march = native" на аналогичных архитектурах

Я работаю над написанием теста OpenCL в C. В настоящее время он измеряет скользящую совокупную производительность как CL-устройства, так и системного процессора с использованием кода C. Затем результаты проверяются на точность.

Я написал собственный код, чтобы использовать GCC auto vectorizer, и он работает. Тем не менее, я заметил, что GCC имеет некоторое нечетное поведение с флагом "-march = native".

Это мой цикл:

#define BUFFER_SIZE_SQRT 4096
#define SQUARE(n) (n * n)

#define ROUNDS_PER_ITERATION 48

static float* cpu_result_matrix(const float* a, const float* b, const float* c)
{
    float* res = aligned_alloc(16, SQUARE(BUFFER_SIZE_SQRT) * sizeof(float));

    const unsigned buff_size = SQUARE(BUFFER_SIZE_SQRT);
    const unsigned round_cnt = ROUNDS_PER_ITERATION;

    float lres;
    for(unsigned i = 0; i < buff_size; i++)
    {
        lres = 0;
        for(unsigned j = 0; j < round_cnt; j++)
        {
            lres += a[i] * ((b[i] * c[i]) + b[i]);
            lres += b[i] * ((c[i] * a[i]) + c[i]);
            lres += c[i] * ((a[i] * b[i]) + a[i]);
        }

        res[i] = lres;
    }

    return res;
}

Когда я компилирую с "-march = native -Ofast" в системе Broadwell, я получаю хороший векторный код AVX.

.L19:
        vmovups ymm0, YMMWORD PTR [rcx+rdx]
        mov     eax, 48
        vmovups ymm2, YMMWORD PTR [rdi+rdx]
        vaddps  ymm1, ymm0, ymm5
        vmovups ymm3, YMMWORD PTR [rsi+rdx]
        vaddps  ymm4, ymm2, ymm5
        vmulps  ymm1, ymm1, ymm2
        vfmadd132ps     ymm4, ymm1, ymm0
        vaddps  ymm1, ymm3, ymm5
        vmulps  ymm0, ymm2, ymm0
        vmulps  ymm0, ymm0, ymm1
        vfmadd132ps     ymm4, ymm0, ymm3
        vmovaps ymm1, ymm4
        vxorps  xmm0, xmm0, xmm0
        .p2align 4,,10
        .p2align 3

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

.L19:
        mov     eax, 48
        movups  xmm0, XMMWORD PTR [rcx+rdx]
        movups  xmm2, XMMWORD PTR [r13+0+rdx]
        movaps  xmm4, xmm0
        movaps  xmm1, xmm2
        movups  xmm3, XMMWORD PTR [rsi+rdx]
        addps   xmm4, xmm5
        addps   xmm1, xmm5
        mulps   xmm4, xmm2
        mulps   xmm1, xmm0
        mulps   xmm0, xmm2
        addps   xmm1, xmm4
        movaps  xmm4, xmm1
        mulps   xmm4, xmm3
        addps   xmm3, xmm5
        mulps   xmm0, xmm3
        addps   xmm4, xmm0
        pxor    xmm0, xmm0
        movaps  xmm1, xmm4
        .p2align 4,,10
        .p2align 3

Я даже могу скомпилировать весь проект с помощью -march = broadwell и запустить его в системе Piledriver, и он работает с коэффициентом усиления на 100%.

Я компилирую с GCC 5.1.0, и "-ftree-vectorizer-verbose" больше не работает, поэтому поведение компилятора довольно непрозрачно. Я не нашел никакой информации о том, что флаг устарел, поэтому я не уверен, почему он больше не работает, и мне очень хотелось бы выяснить, что делает GCC.

Весь проект находится здесь: https://github.com/jakogut/clperf/tree/v0.1

4b9b3361

Ответ 1

AVX отключен, потому что все семейство AMD Bulldozer не справляется с 256-битными инструкциями AVX. Внутренне исполняемые модули имеют ширину всего 128 бит. Таким образом, 256-битные операции разделяются, тем самым не принося никакой выгоды более чем 128-битным.

Чтобы добавить оскорбление к травме, на Piledriver есть ошибка в 256-битном хранилище, которая уменьшает пропускную способность до около 1 каждые 17 циклов.


Ваш тестовый пример кажется аномалией. У вас нет 256-битных магазинов в этом критическом цикле, что позволяет избежать ошибки. Это (теоретически) оставляет SSE наравне с AVX для Piledriver.

Тай-брейк происходит от инструкций FMA3, которые поддерживает Piledriver. Вероятно, поэтому цикл Python быстрее ускоряется.

Одна вещь, которую вы можете попробовать: -mfma4 -mtune=bdver2 и посмотреть, что произойдет.

Ответ 2

Вывод "-march = native -Q -help = target" показывает, что флаги AVX и AVX2 по умолчанию не включены в архитектуре Piledriver (bdver2).

Бродуэлла:

  -mavx                                 [enabled]
  -mavx2                                [enabled]

Piledriver:

  -mavx                                 [disabled]
  -mavx2                                [disabled]