Провел на поминавшемся вчера ISPC еще один тест, на применимость ровно в том месте, куда он лучше всего приспособлен.
Есть такое ужасное место в обработке изображений (уже поминавшееся в этом блоге): преобразование из линейной гаммы в sRGB-гамму или в Lab. Там в формуле сначала линейный участок, а потом степенной. Вот как это выглядит, если делать в лоб для плавающей точки:
void linear2srgb(float *in, float *out)
{
for(int i = 0; i< DATA_SIZE; i++)
out[i] = ((in[i]<=0.0031308f)? 12.92f*in[i] : (1+0.055f)*powf(in[i],1/2.4f)-0.055f);
}
Ну, понятно, для (целочисленных) 8-16-битных данных составляют лукап-таблицу, а дальше фигачат по ней, а вот для большей битности таблица получается изрядно большой. Вычислять эту штуку в лоб мешают две вещи:
- ветвление на каждое входное данное;
- возведение в степень, которое тоже очень медленное: на SSE/AVX такой функции нет, на FP87 есть, но безобразно медленная.
К примеру, при обработке плавающих данных LCMS (преобразование в Lab, преобразование по матричному профилю в sRGB) процентов 90 времени уходит именно на вышепоказанную операцию (правда в LCMS это место еще сделано потрясающе неудачно с точки зрения производительности).
Как я уже писал, правильное решение заключается в замене вышепоказанной функции чем-то приличным, скажем для кубических сплайнов с таблицей в 4к строк максимальная ошибка по всему диапазону не превышает 10-6, что для всех применений достаточно, при скорости порядка 1.2-1.5Gb/sec на одно процессорное ядро. Но одна строчка кода превращается в несколько десятков, таблицу коэффициентов сплайнов надо еще построить, что мучительно.
Посмотрим, что можно сделать с помощью ISPC и можно ли вообще что-то.