4 Stimmen

Gibt es SIMD-Befehle zur Beschleunigung der Prüfsummenberechnung?

Ich werde eine sehr einfache Prüfsummenfunktion programmieren müssen, etwa so:

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

Das ist trivial. Wie soll ich das nun optimieren? Zunächst sollte ich wahrscheinlich einige std::for_each mit einem Lambda oder etwas in der Art verwenden:

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

Als Nächstes könnte ich mehrere Threads/Kerne verwenden, um Chunks zu summieren und dann die Ergebnisse zu addieren. Ich werde es nicht aufschreiben, und ich fürchte, die Kosten für die Erstellung von Threads (oder bekommen sie von einem Pool sowieso), dann schneiden Sie das Array, dann alles, usw. zu versenden, wäre nicht sehr gut, wenn man bedenkt, dass ich meist Prüfsummen für kleine Arrays berechnen würde, meist 10-100 Byte, selten bis zu 1000.

Aber was ich wirklich will, ist etwas auf niedrigerer Ebene, einige SIMD-Zeug, das Bytes auf 128b-Register summieren würde, oder vielleicht summieren Bytes unabhängig zwischen zwei Registern ohne den Übertrag, oder beides.

Gibt es so etwas da draußen?

Hinweis: Dies ist tatsächlich eine verfrühte Optimierung, aber es macht Spaß, also was soll's?

Bearbeiten: Ich brauche noch eine Möglichkeit, alle Bytes in einem SSE-Register zu summieren, etwas Besseres als

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];

2voto

Ben Voigt Punkte 268424

Ja, es gibt solche Anweisungen im MMX-Befehlssatz, "Packed ADD" genannt:

  • _mm_add_pi8 in Visual C++
  • __builtin_ia32_paddb in gcc

Und im SSE2-Befehlssatz:

EDIT: Ein schnellerer Weg, die Teilsummen zu addieren:

__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);

-1voto

totowtwo Punkte 2072

Sehen Sie sich _mm_add_ps an. Gleichzeitiges Hinzufügen eines zusammenhängenden 128-Bit-Blocks. Sie müssen Ihr Array mit Nullen auffüllen oder die letzten paar nicht SIMD-Stil verarbeiten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X