Про AVX и ISPC

Разработчики Intel SPMD Program Compiler, который в этом блоге уже несколько раз поминался, выпустили версию 1.0.9 в которой

=== v1.0.9 === (26 September 2011)

The binary release of v1.0.9 is the first that supports AVX code generation. Two targets are provided: "avx", which runs with a programCount of 8, and "avx-x2" which runs 16 program instances simultaneously.

Честь им за это и хвала, мои попытки (не слишком настойчивые) самостоятельно собрать ISPC с LLVM3 так и не увенчались успехом, то какие-то ошибки в LLVM-овских H-файлах, то не линкуется, не больно то и хотелось.

Так как предыдущие тесты никуда не делись, я их переделал с новым ISPC, как с SSE4, так и с AVX.

Программа, естественно, та же самая: гамма-преобразование в духе sRGB, с линейным участком в начале и степенным в конце. Повторю ее тут еще раз:

export void srgb_ispc(uniform float in[], reference uniform float out[])
    {
       for(uniform int i = 0; i < DATA_SIZE; i+=programCount)
       {
            float val = in[i+programIndex];
            bool b = val <=0.0031308;
            if(all(b))
               out[i+programIndex] = 12.92*val;
            else if(!any(b))
               out[i+programIndex] = (1.055)*pow(val,1.0/2.4)-0.055;
            else
               out[i+programIndex] = b? 12.92*val:(1.055)*pow(val,1.0/2.4)-0.055;  
       }
    }
Получаем:
  1. --target=sse4x2: 706 Mb/sec для стандартной математики и 712 Mb/sec для --math-lib=fast (отличается длиной полинома у pow()). Стало помедленнее, чем в версии 1.0 (где было 730 с fast math), в причинах я не стал разбираться.
  2. --target=avx: 914 Mb/sec и 984 Mb/sec для --math-lib=default/fast.
  3. --target=avx-x2: 1242 Mb/sec и 1246 Mb/sec
Для сравнения, интеловский C++ компилятор с включенной векторизацией цикла: 530Mb/sec для SSE4 и 720 для AVX (весь пар тоже уходит в возведение в степень, 4-way и 8-way SVML).

И вообще, мне порождаемый ISPC код скорее нравится. Конечно, тамошняя математика инлайнится и поэтому громоздка, но для чтения глазом можно --math-lib=svml сказать.

Конечно, нужно пользоваться векторными предикатами (all(), any()), без них получается существенно скучнее. Вот такой вот 1-liner:

export void srgb_ispc(uniform float in[], reference uniform float out[])
{
   for(uniform int i = 0; i < DATA_SIZE; i+=programCount)
   {
        float val = in[i+programIndex];        
        out[i+programIndex] = val <=0.0031308? 12.92*val:(1.055)*pow(val,1.0/2.4)-0.055;
   }
}
Дает:
  1. --target=avx-x2: 955/961 Mb/sec для default/fast математики.
  2. --target=avx: 836/846 Mb/sec для default/fast математики.
Тоже побыстрее С++-компилятора, но раз уж пошли использовать внешний тул, так выигрыш в 1.73 раза поприятнее будет, чем в 1.33 и предикаты полезны.

Итого: Хороший, годный тул. Многопоточная тамошняя модель меня пока не возбудила, а как SIMD-компилятор - вполне. И гораздо более широко применимо, чем векторные расширения т.к. нормально работает со скалярами.