пятница, 23 мая 2014 г.

Векторизация в компиляторе Эльбруса

Наткнулся на старый пост про автовекторизацию. Если в кратце, то автор жаловался на то, что компиляторы не могут ничего сделать даже на простейших примерах. Я просто не мог не проверить как те простейшие примеры отработают на Эльбрусе :)
Итак, у нас есть Эльбрус-2С+:

$ cat /proc/cpuinfo
processor       : 0
vendor_id       : E2K MACHINE
cpu family      : 4
model           : 20255552
model name      : Elbrus-e2k-e2c+
revision        : 1
cpu MHz         : 496.580
L1 cache size   : 64 KB
L1 cache line length    : 32 bytes
L2 cache size   : 1024 KB
L2 cache line length    : 64 bytes
...


Есть компилятор Эльбруса:

$ gcc -v
lcc:1.18.07:Oct-19-2013:e2k-2c+-linux


Да, на Эльбрусах команда gcc вызывает нативный компилятор :) Сделано для упрощения портирования софта. Нет, у нас не используется gcc.

Берём первый пример:

#include <stdio.h>
int main(int argc, char* argv[])
{
    short a[256] __attribute__ ((aligned(16)));
    short b[256] __attribute__ ((aligned(16)));
    for(int i=0;i<256;i++) {
        a[i] = i & 1;
        b[i] = i & 3;
    }
    int mn = 100500;
    for(int n=0;n<10000000;n++) {
        int sum = 0, j=0;
        for(int y=0;y<16;y++)
            for(int x=0;x<16;x++) {
                short v = a[j] - b[j];
                sum += v*v;
                j++;
            }
        mn = mn < sum ? mn : sum;
    }
    printf("%d\n", mn);
    return 0;
}


И сразу результаты:

$ gcc madd.cpp -o madd.out
$ time ./madd.out
512

real    1m22.307s
user    1m21.990s
sys     0m0.040s


$ gcc madd.cpp -O3 -fno-vect -o madd_no_vect.out
$ time ./madd_no_vect.out
512

real    0m6.315s
user    0m6.280s
sys     0m0.010s

$ gcc madd.cpp -O3 -o madd_vect.out
$ time ./madd_vect.out
512

real    0m1.731s
user    0m1.700s
sys     0m0.020s


Разница между режимами компиляции впечатляющая. В моём g++-4.8.2 на машине Core i5 неоптимизированная версия исполняется 11.475 сек., оптимизированные 1.663 сек. и 1.662 сек. соответственно.

Во-первых разница во времени показывает на сколько важен для Эльбрусов хороший компилятор. А как Вы уже догадались он чертовски хорош ;) Собственно, результаты говорят сами за себя. Векторизация отлично отработала и дала ускорение более чем в три раза (по сравнению с -O3 без векторизации).

Второй пример:

#include <stdio.h>
int main(int argc, char* argv[])
{
    short a[256] __attribute__ ((aligned(16)));
    short b[256] __attribute__ ((aligned(16)));
    for(int i=0;i<256;i++) {
        a[i] = i & 1;
        b[i] = i & 3;
    }
    int mn = 100500;
    for(int n=0;n<10000000;n++) {
        int sum = 0;//, j=0;
        for(int j=0;j<256;j++) {
                short v = a[j] - b[j];
                sum += v*v;
            }
        mn = mn < sum ? mn : sum;
    }
    printf("%d\n", mn);
    return 0;
}


Выдал такие результаты:

$ gcc madd_oneloop.cpp -o madd_oneloop.out
-bash-4.2$ time ./madd_oneloop.out
512

real    1m18.312s
user    1m18.080s
sys     0m0.020s

$ gcc madd_oneloop.cpp -O3 -fno-vect -o madd_oneloop_no_vect.out
$ time ./madd_oneloop_no_vect.out
512

real    0m1.001s
user    0m0.970s
sys     0m0.020s

$ gcc madd_oneloop.cpp -O3 -o madd_oneloop_vect.out
$ time ./madd_oneloop_vect.out
512

real    0m1.000s
user    0m0.980s
sys     0m0.010s


Что интересно, векторизация в нём реально применилась, но код и без неё неплохо соптимизировался.

Даже не знаю какие выводы из всего этого можно сдлать. Просто для сведения - компилятор Эльбруса имеет крутую векторизацию.

PS. На самом деле по таким синтетическим примерам судить о компиляторе нельзя, т.к. в реальной жизни всё гораздо сложнее. Чтобы проверить компилятор нужны как минимум специальные бенчмарки, и то это тоже не всегда показатель.

2 комментария:

  1. Ответы
    1. Да, вполне собирается, есть в пакетном менеджере дистрибутива Эльбрус.

      Удалить