Trong mã của tôi, tôi phải xử lý "unmasking" của gói websocket, mà về cơ bản có nghĩa là XOR'ing dữ liệu chưa được sắp xếp có độ dài tùy ý. Nhờ có SO (Websocket data unmasking/multi byte xor) Tôi đã tìm ra cách (hy vọng) tăng tốc độ này bằng cách sử dụng phần mở rộng SSE2/AVX2, nhưng nhìn vào nó bây giờ, có vẻ như với tôi rằng việc xử lý dữ liệu không được ký hiệu của tôi hoàn toàn phụ tối ưu. Có cách nào để tối ưu hóa mã của tôi hay ít nhất là làm cho nó đơn giản hơn với cùng một hiệu suất, hay là mã của tôi đã hoạt động tốt nhất?tối ưu hóa SSE2/AVX2 XOR
Đây là phần quan trọng của mã (đối với câu hỏi tôi giả định rằng dữ liệu sẽ luôn đủ ít nhất để chạy chu trình AVX2 một lần, nhưng đồng thời phần lớn nó sẽ chỉ chạy một vài lần) :
// circular shift left for uint32
int cshiftl_u32(uint32_t num, uint8_t shift) {
return (num << shift) | (num >> (32 - shift));
}
// circular shift right for uint32
int cshiftr_u32(uint32_t num, uint8_t shift) {
return (num >> shift) | (num << (32 - shift));
}
void optimized_xor_32(uint32_t mask, uint8_t *ds, uint8_t *de) {
if (ds == de) return; // zero data len -> nothing to do
uint8_t maskOffset = 0;
// process single bytes till 4 byte alignment (<= 3)
for (; ds < de && ((uint64_t)ds & (uint64_t)3); ds++) {
*ds ^= *((uint8_t *)(&mask) + maskOffset);
maskOffset = (maskOffset + 1) & (uint8_t)3;
}
if (ds == de) return; // done, return
if (maskOffset != 0) { // circular left-shift mask around so it works for other instructions
mask = cshiftl_u32(mask, maskOffset);
maskOffset = 0;
}
// process 4 byte block till 8 byte alignment (<= 1)
uint8_t *de32 = (uint8_t *)((uint64_t)de & ~((uint64_t)31));
if (ds < de32 && ((uint64_t)de & (uint64_t)7)) {
*(uint32_t *)ds ^= mask; // mask is uint32_t
if (++ds == de) return;
}
// process 8 byte block till 16 byte alignment (<= 1)
uint64_t mask64 = mask | (mask << 4);
uint8_t *de64 = (uint8_t *)((uint64_t)de & ~((uint64_t)63));
if (ds < de64 && ((uint64_t)ds & (uint64_t)15)) {
*(uint64_t *)ds ^= mask64;
if (++ds == de) return; // done, return
}
// process 16 byte block till 32 byte alignment (<= 1) (if supported)
#ifdef CPU_SSE2
__m128i v128, v128_mask;
v128_mask = _mm_set1_epi32(mask);
uint8_t *de128 = (uint8_t *)((uint64_t)de & ~((uint64_t)127));
if (ds < de128 && ((uint64_t)ds & (uint64_t)31)) {
v128 = _mm_load_si128((__m128i *)ds);
v128 = _mm_xor_si128(v128, v128_mask);
_mm_store_si128((__m128i *)ds, v128);
if (++ds == de) return; // done, return
}
#endif
#ifdef CPU_AVX2 // process 32 byte blocks (if supported -> haswell upwards)
__m256i v256, v256_mask;
v256_mask = _mm256_set1_epi32(mask);
uint8_t *de256 = (uint8_t *)((uint64_t)de & ~((uint64_t)255));
for (; ds < de256; ds+=32) {
v256 = _mm256_load_si256((__m256i *)ds);
v256 = _mm256_xor_si256(v256, v256_mask);
_mm256_store_si256((__m256i *)ds, v256);
}
if (ds == de) return; // done, return
#endif
#ifdef CPU_SSE2 // process remaining 16 byte blocks (if supported)
for (; ds < de128; ds+=16) {
v128 = _mm_load_si128((__m128i *)ds);
v128 = _mm_xor_si128(v128, v128_mask);
_mm_store_si128((__m128i *)ds, v128);
}
if (ds == de) return; // done, return
#endif
// process remaining 8 byte blocks
// this should always be supported, so remaining can be assumed to be executed <= 1 times
for (; ds < de64; ds += 8) {
*(uint64_t *)ds ^= mask64;
}
if (ds == de) return; // done, return
// process remaining 4 byte blocks (<= 1)
if (ds < de32) {
*(uint32_t *)ds ^= mask;
if (++ds == de) return; // done, return
}
// process remaining bytes (<= 3)
for (; ds < de; ds ++) {
*ds ^= *((uint8_t *)(&mask) + maskOffset);
maskOffset = (maskOffset + 1) & (uint8_t)3;
}
}
Tái bút
Bạn đã thử định thời gian mã của mình chưa? (Ngoài ra, bạn có thể muốn quấn bitwise '&' trong điều kiện của bạn bằng dấu ngoặc đơn) –
Thời gian sẽ không thực sự hữu ích, vì tôi chỉ có thể đưa ra giả định về dữ liệu tôi sẽ nhận được như đầu vào, nhưng sẽ không nhận được bất kỳ đầu vào cho một vài tháng tới. Ngoài ra, tôi chỉ nhận được một số tuyệt đối với thời gian, điều này thực sự không giúp tôi vì vấn đề của tôi không tìm ra mã này cần bao lâu để thực thi với đầu vào xy, nhưng cách làm cho nó nhanh hơn, ví dụ: Tôi không có ý tưởng gì để thay đổi. Tái bút: Được bọc bitwise & để hiểu dễ dàng hơn, thx cho gợi ý! – griffin
Tôi nghĩ bạn sẽ thấy rằng các quầy phụ thuộc dữ liệu lớn hơn lợi ích được căn chỉnh/không được căn chỉnh. Nếu bạn có thể hủy vòng lặp của mình gấp 2 lần, bạn sẽ thấy sự cải thiện đáng kể. – BitBank