Существуют ли инструкции SIMD для ускорения вычислений контрольной суммы? - PullRequest
4 голосов
/ 13 июля 2011

Мне нужно написать очень простую функцию контрольной суммы, например:

char sum(const char * data, const int len)
{
    char sum(0);
    for (const char * end=data+len ; data<end ; ++data)
        sum += *data;
    return sum;
}

Это тривиально.Теперь, как я должен оптимизировать это?Во-первых, я, вероятно, должен использовать некоторый std :: for_each с лямбдой или что-то в этом роде:

char sum2(const char * data, const int len)
{
    char sum(0);
    std::for_each(data, data+len, [&sum](char b){sum+=b;});
    return sum;
}

Затем я мог бы использовать несколько потоков / ядер для суммирования кусков, а затем добавить результаты.Я не буду записывать это, и я боюсь, что затраты на создание потоков (или получение их из пула в любом случае), затем нарезку массива, затем отправку всего и т. Д. Не будут очень хорошими, учитывая, что я в основном будувычислять контрольные суммы для маленьких массивов, в основном 10-100 байт, редко до 1000.

Но что я действительно хочу, так это что-то более низкого уровня, некоторые SIMD-вещи, которые суммируют байты в регистрах 128b, или, возможно, суммируют байты независимомежду двумя регистрами без переноса или обоими.

Есть ли там что-нибудь подобное?

Примечание: это действительно преждевременная оптимизация, но это весело, так что, черт возьми?

Редактировать: Мне все еще нужен способ суммировать все байты в регистре SSE, что-то лучше, чем

char ptr[16];
_mm_storeu_si128((__m128i*)ptr, sum);
checksum += ptr[0] + ptr[1] + ptr[2]  + ptr[3]  + ptr[4]  + ptr[5]  + ptr[6]  + ptr[7]
          + ptr[8] + ptr[9] + ptr[10] + ptr[11] + ptr[12] + ptr[13] + ptr[14] + ptr[15];

Ответы [ 2 ]

2 голосов
/ 13 июля 2011

Да, в наборе команд MMX есть такие инструкции, которые называются «Упакованные ADD»:

  • _mm_add_pi8 в Visual C ++
  • __builtin_ia32_paddb в gcc

И в наборе команд SSE2:

РЕДАКТИРОВАТЬ: более быстрый способ добавить частичные суммы:

__m128i sums;

sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 1));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 2));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 4));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 8));
checksum += _mm_cvtsi128_si32(sums);
0 голосов
/ 13 июля 2011

Посмотрите на _mm_add_ps. Одновременное добавление 128-битного непрерывного блока. Вам нужно будет обнулить массив или обработать последние несколько не SIMD-стиля.

...