Разоблачение данных веб-сокета / многобайтовый xor
Спецификация websocket определяет демаскирование данных как
j = i MOD 4
transformed-octet-i = original-octet-i XOR masking-key-octet-j
где маска имеет длину 4 байта, и на каждый байт следует применять маску.
Есть ли способ сделать это более эффективно, чем просто зациклить байты?
Сервер, на котором выполняется код, можно считать процессором Haswell, ОС - Linux с ядром> 3.2, поэтому SSE и т. Д. Все присутствуют. Кодирование сделано на C, но я могу также сделать asm, если это необходимо.
Я попытался найти решение самостоятельно, но не смог выяснить, была ли соответствующая инструкция в какой-либо из дюжин SSE1-5/AVE/(какое бы расширение не было потеряно из-за многих лет)
Большое спасибо!
Редактировать: после перечитывания спецификации пару раз кажется, что на самом деле это только XOR'ы байтов данных с байтами маски, что я могу сделать 8 байтов за раз до последних нескольких байтов. Вопрос все еще остается открытым, так как я думаю, что, возможно, еще есть способ оптимизировать это с помощью SSE или тому подобного (возможно, обрабатывать хотя бы 16 байтов за раз, позволяя процессу выполнять цикл for? ...)
1 ответ
Да, вы можете XOR 16 байтов в одной инструкции, используя SSE2, или 32 байта за раз с AVX2 (Haswell и позже).
SSE2:
#include <emmintrin.h> // SSE2 instrinsics
__m128i v, v_mask;
uint8_t *buff; // buffer - must be 16 byte aligned
for (int i = 0; i < N; i += 16) // note that N must be multiple of 16
{
v = _mm_load_si128(&buff[i]); // load 16 bytes
v = _mm_xor_si128(v, v_mask); // XOR with mask
v = _mm_store_si128(&buff[i], v); // store 16 masked bytes
}
AVX2:
#include <immintrin.h> // AVX2 intrinsics
__m256i w, w_mask;
uint8_t *buff; // buffer - must be 16 byte aligned,
// and preferably 32 byte aligned
for (int i = 0; i < N; i += 32) // note that N must be multiple of 32
{
w = _mm256_load_si256(&buff[i]); // load 32 bytes
w = _mm256_xor_si256(w, w_mask); // XOR with mask
w = _mm256_store_si256(&buff[i], w); // store 32 masked bytes
}