पर फास्ट पॉपकाउंट मैं इंटेल ज़ीऑन® फी® पर अल्ट्रा फास्ट पॉपकाउंट लागू कर रहा हूं, क्योंकि यह विभिन्न जैव सूचना विज्ञान सॉफ्टवेयर का प्रदर्शन हॉटस्पॉट है।इंटेल ज़ीऑन फाई
मैं कोड के पांच टुकड़े को क्रियान्वित किया है,
#if defined(__MIC__)
#include <zmmintrin.h>
__attribute__((align(64))) static const uint32_t POPCOUNT_4bit[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
__attribute__((align(64))) static const uint32_t MASK_4bit[16] = {0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF};
inline uint64_t vpu_popcount1(uint64_t* buf, size_t n) {
register size_t result = 0;
size_t i;
register const __m512i popcnt = _mm512_load_epi32((void*)POPCOUNT_4bit);
register const __m512i mask = _mm512_load_epi32((void*)MASK_4bit);
register __m512i total;
register __m512i shuf;
#pragma unroll(8)
for (i = 0; i < n; i+=8) {
shuf = _mm512_load_epi32(&buf[i]);
_mm_prefetch((const char *)&buf[i+256], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+64], _MM_HINT_T0); // vprefetch0
total = _mm512_setzero_epi32();
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(shuf, mask), popcnt), total);
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(_mm512_srli_epi32(shuf, 4), mask), popcnt), total);
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(_mm512_srli_epi32(shuf, 8), mask), popcnt), total);
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(_mm512_srli_epi32(shuf, 12), mask), popcnt), total);
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(_mm512_srli_epi32(shuf, 16), mask), popcnt), total);
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(_mm512_srli_epi32(shuf, 20), mask), popcnt), total);
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(_mm512_srli_epi32(shuf, 24), mask), popcnt), total);
total = _mm512_add_epi32(_mm512_permutevar_epi32(_mm512_and_epi32(_mm512_srli_epi32(shuf, 28), mask), popcnt), total);
/* Reduce add, which is analogous to SSSE3's PSADBW instruction,
is not implementated as a single instruction in VPUv1, thus
emulated by multiple instructions*/
result += _mm512_reduce_add_epi32(total);
}
return result;
}
__attribute__((align(64))) static const unsigned magic[] = {\
0x55555555, 0x55555555, 0x55555555, 0x55555555,\
0x55555555, 0x55555555, 0x55555555, 0x55555555,\
0x55555555, 0x55555555, 0x55555555, 0x55555555,\
0x55555555, 0x55555555, 0x55555555, 0x55555555,\
0x33333333, 0x33333333, 0x33333333, 0x33333333,\
0x33333333, 0x33333333, 0x33333333, 0x33333333,\
0x33333333, 0x33333333, 0x33333333, 0x33333333,\
0x33333333, 0x33333333, 0x33333333, 0x33333333,\
0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F,\
0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F,\
0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F,\
0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F,\
0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF,\
0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF,\
0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF,\
0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF,\
0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF,\
0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF,\
0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF,\
0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF,\
0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,\
0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,\
0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,\
0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF
};
inline uint64_t vpu_popcount2(uint64_t* buf, size_t n) {
register size_t result = 0;
size_t i;
register const __m512i B0 = _mm512_load_epi32((void*)(magic+0));
register const __m512i B1 = _mm512_load_epi32((void*)(magic+16));
register const __m512i B2 = _mm512_load_epi32((void*)(magic+32));
register const __m512i B3 = _mm512_load_epi32((void*)(magic+48));
register const __m512i B4 = _mm512_load_epi32((void*)(magic+64));
register __m512i total;
register __m512i shuf;
#pragma unroll(8)
for (i = 0; i < n; i+=8) {
shuf = _mm512_load_epi32(&buf[i]);
_mm_prefetch((const char *)&buf[i+512], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+64], _MM_HINT_T0); // vprefetch0
total = _mm512_sub_epi32(shuf, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf,1)));
total = _mm512_add_epi32(_mm512_and_epi32(B1, total), _mm512_and_epi32(B1,_mm512_srli_epi32(total,2)));
total = _mm512_and_epi32(B2, _mm512_add_epi32(total, _mm512_srli_epi32(total,4)));
total = _mm512_and_epi32(B3, _mm512_add_epi32(total, _mm512_srli_epi32(total,8)));
total = _mm512_and_epi32(B4, _mm512_add_epi32(total, _mm512_srli_epi32(total,16)));
/* Reduce add, which is analogous to SSSE3's PSADBW instruction,
is not implementated as a single instruction in VPUv1, thus
emulated by multiple instructions*/
result += _mm512_reduce_add_epi32(total);
}
return result;
}
inline uint64_t vpu_popcount3(uint64_t* buf, size_t n) {
register size_t result = 0;
size_t i;
register const __m512i B0 = _mm512_load_epi32((void*)(magic+0));
register const __m512i B1 = _mm512_load_epi32((void*)(magic+16));
register const __m512i B2 = _mm512_load_epi32((void*)(magic+32));
register const __m512i B3 = _mm512_load_epi32((void*)(magic+48));
register const __m512i B4 = _mm512_load_epi32((void*)(magic+64));
register __m512i total;
register __m512i shuf;
#pragma unroll(4)
for (i = 0; i < n; i+=16) {
shuf = _mm512_load_epi32(&buf[i]);
result += _mm_countbits_64(buf[i+8]);
_mm_prefetch((const char *)&buf[i+512], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+576], _MM_HINT_T1); // vprefetch1
result += _mm_countbits_64(buf[i+9]);
_mm_prefetch((const char *)&buf[i+64], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[i+128], _MM_HINT_T0); // vprefetch0
total = _mm512_sub_epi32(shuf, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf,1)));
result += _mm_countbits_64(buf[i+10]);
total = _mm512_add_epi32(_mm512_and_epi32(B1, total), _mm512_and_epi32(B1,_mm512_srli_epi32(total,2)));
result += _mm_countbits_64(buf[i+11]);
total = _mm512_and_epi32(B2, _mm512_add_epi32(total, _mm512_srli_epi32(total,4)));
result += _mm_countbits_64(buf[i+12]);
total = _mm512_and_epi32(B3, _mm512_add_epi32(total, _mm512_srli_epi32(total,8)));
result += _mm_countbits_64(buf[i+13]);
total = _mm512_and_epi32(B4, _mm512_add_epi32(total, _mm512_srli_epi32(total,16)));
result += _mm_countbits_64(buf[i+14]);
/* Reduce add, which is analogous to SSSE3's PSADBW instruction,
is not implementated as a single instruction in VPUv1, thus
emulated by multiple instructions*/
result += _mm512_reduce_add_epi32(total);
result += _mm_countbits_64(buf[i+15]);
}
return result;
}
/* Using VPU or SSE's machine intrinsic, CPUs not supporting SIMD
* will use compiler's implementation, the speed of which depends */
static inline size_t scalar_popcountu(unsigned *buf, size_t n) {
register size_t cnt = 0;
size_t i;
#pragma vector always
#pragma unroll(8)
for (i = 0; i < n; i++) {
cnt += _mm_countbits_32(buf[i]);
_mm_prefetch((const char *)&buf[i+512], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+64], _MM_HINT_T0); // vprefetch0
}
return cnt;
}
static inline size_t scalar_popcountlu(uint64_t *buf, size_t n) {
register size_t cnt = 0;
size_t i;
#pragma vector always
#pragma unroll(8)
for (i = 0; i < n; i++) {
cnt += _mm_countbits_64(buf[i]);
_mm_prefetch((const char *)&buf[i+512], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+64], _MM_HINT_T0); // vprefetch0
}
return cnt;
}
#endif
OpenMP समर्थन के साथ कोड के ऊपर एक चादर से https://www.dropbox.com/sh/b3sfqps19wa2oi4/iFQ9wQ1NTg
कोड डाउनलोड किया जा सकता इंटेल C/C++ संकलक XE 13 का उपयोग कर संकलित किया गया था का उपयोग करते हुए आदेश:
icc -debug inline-debug-info -O3 -mmic -fno-alias -ansi-alias -opt-streaming-stores always -ipo popcnt-mmic.cpp -o popcnt-mmic -vec-report=2 -openmp
कोड के साथ "122 धागे" और "संतुलित" निर्यात का उपयोग कर धागा आत्मीयता सह-प्रोसेसर (61 कोर) पर मूल रूप से चलाता है:
export OMP_NUM_THREADS=122;export KMP_AFFINITY=balanced
मैं जिऑन फी SE10p, बी 1 स्टेपिंग, CentOS6.4 परीक्षण का उपयोग कर रहा junks के 28 मेगाबाइट पर (रैंड द्वारा भरा()) और 10000 समय के लिए पुनरावृति, प्रदर्शन इस प्रकार हैं:
Buffer allocated at: 0x7f456b000000
OpenMP scalar_popcountu 4310169 us; cnt = 28439328
OpenMP scalar_popcountlu 1421139 us; cnt = 28439328
OpenMP vpu_popcount 1489992 us; cnt = 28439328
OpenMP vpu_popcount2 1109530 us; cnt = 28439328
OpenMP vpu_popcount3 951122 us; cnt = 28439328
"scalar_popcountu" और "scalar_popcountlu" क्रमशः "_mm_countbits_32" और "_mm_countbits_64" इंट्रिनिक्स का उपयोग करते हैं, जो स्केलर "पॉपकंट" निर्देश का उपयोग करते हैं। "#pragma वेक्टर हमेशा" को सेट करने के लिए संकलक को भार और योग को 16 हस्ताक्षरित इनट्स या 8 हस्ताक्षरित लंबे समय तक सदिश करने के लिए कहा जाता है, हालांकि पॉपकाउंट स्वयं भी एक स्केलर निर्देश है।
vpu_popcount1 का कार्यान्वयन एसएसएसई 3 पॉपकाउंट कार्यान्वयन http://wm.ite.pl/articles/sse-popcount.html के समान है। हालांकि, 1) ज़ीऑन फाई पूर्णांक पर पैक बाइट ऑपरेशंस का समर्थन नहीं करता है (न्यूनतम डबल शब्द, उर्फ 32-बिट) और 2) यह "पूर्ण अंतर के पैक किए गए योग" निर्देश को लागू नहीं करता है (जैसे एसएसएसई 3 में _mm_sad_epu8) कमी जोड़ने "vpermf32x4", "vpaddd" और "movslq" के चार समूहों के संयोजन द्वारा किया गया था। इस प्रकार कार्यान्वयन ने मूल एसएसएसई 3 संस्करण की तुलना में अधिक निर्देश दिए।
vpu_popcount2 का कार्यान्वयन एसएसई 2 पॉपकाउंट कार्यान्वयन के समान है (कोई "हैकर डिलाइट" का संदर्भ ले सकता है)। कार्यान्वयन vpu_popcount1 से कम निर्देश उत्पन्न करता है और लगभग 30% तेज़ है। हालांकि, कड़ी मेहनत "कम करें" अभी भी टाला नहीं जा सकता है।
vpu_popcount3 का कार्यान्वयन बहुत ज़ीओन फी विशिष्ट है। वेक्टर और स्केलर ऑपरेशंस के मिश्रण के साथ, यह vpu_popcount2 से लगभग 15% तेज है (वेक्टर ऑपरेशंस के बीच स्केलर ऑपरेशंस का अंतर मेरे कार्यान्वयन में अवकाश है, कोई संकलक द्वारा उत्पन्न असेंबली कोड के अनुसार स्केलर परिचालन को पुनर्व्यवस्थित कर सकता है, लेकिन अपेक्षित सुधार जहां तक मेरा संबंध है, सीमित है)। सुधार अवलोकन पर आधारित है कि 1) ज़ीओन फाई इन-ऑर्डर शेड्यूलिंग है, 2) दो स्केलर निर्देश या "1 वेक्टर + 1 स्केलर" निर्देश प्रति घड़ी चक्र जारी किए जा सकते हैं। रजिस्टर फ़ाइल संतृप्ति से बचने के लिए मैंने 8 से 4 तक अनलोल घटा दिया है।
स्मृति से एल 2 8 लूप से स्पष्ट प्रीफेच अग्रिम में और प्रत्येक समारोह में एल 2 से एल 1 1 लूप से अग्रिम में एल 1 हिट अनुपात 0.38 से 0.9 9 4 तक बढ़ गया है।
अनलोल प्रदर्शन में लगभग 15% की वृद्धि करता है। यह काउंटर अंतर्ज्ञानी है क्योंकि ज़ीओन फाई इन-ऑर्डर शेड्यूलिंग है। लेकिन अनलॉक आईसीसी कंपाइलर जितना संभव हो उतना संकलित समय शेड्यूलिंग करने में सक्षम बनाता है।
क्या हमारे पास प्रदर्शन को बढ़ावा देने के लिए और भी तकनीकी हैं?ब्रायन Nickerson से तेजी से कोड
दो टुकड़ा,
OpenMP vpu_popcount2 1110737 us; cnt = 28439328
OpenMP vpu_popcount3 951459 us; cnt = 28439328
OpenMP vpu_popcount3_r 815126 us; cnt = 28439328
OpenMP vpu_popcount5 746852 us; cnt = 28439328
vpu_popcount3_revised:
inline uint64_t vpu_popcount3_revised(uint64_t* buf, size_t n) {
_mm_prefetch((const char *)&buf[0], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[8], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[16], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[24], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[32], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[40], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[48], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[56], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[64], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[72], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[80], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[88], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[96], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[104], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[112], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[120], _MM_HINT_T1); // vprefetch1
register size_t result;
size_t i;
register const __m512i B0 = _mm512_load_epi32((void*)(magic+0));
register const __m512i B1 = _mm512_load_epi32((void*)(magic+16));
register const __m512i B2 = _mm512_load_epi32((void*)(magic+32));
register const __m512i B3 = _mm512_load_epi32((void*)(magic+48));
register const __m512i B4 = _mm512_load_epi32((void*)(magic+64));
register __m512i total0;
register __m512i total1;
register __m512i shuf0;
register __m512i shuf1;
register __m512i result0;
register __m512i result1;
result0 = _mm512_setzero_epi32();
result1 = _mm512_setzero_epi32();
for (i = 0; i < n; i+=16) {
shuf0 = _mm512_load_epi32(&buf[i ]);
shuf1 = _mm512_load_epi32(&buf[i+8]);
_mm_prefetch((const char *)&buf[i+128], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+136], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+16], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[i+24], _MM_HINT_T0); // vprefetch0
total0 = _mm512_sub_epi32(shuf0, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf0,1)));
total1 = _mm512_sub_epi32(shuf1, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf1,1)));
total0 = _mm512_add_epi32(_mm512_and_epi32(B1, total0), _mm512_and_epi32(B1,_mm512_srli_epi32(total0,2)));
total1 = _mm512_add_epi32(_mm512_and_epi32(B1, total1), _mm512_and_epi32(B1,_mm512_srli_epi32(total1,2)));
total0 = _mm512_and_epi32(B2, _mm512_add_epi32(total0, _mm512_srli_epi32(total0,4)));
total1 = _mm512_and_epi32(B2, _mm512_add_epi32(total1, _mm512_srli_epi32(total1,4)));
total0 = _mm512_and_epi32(B3, _mm512_add_epi32(total0, _mm512_srli_epi32(total0,8)));
total1 = _mm512_and_epi32(B3, _mm512_add_epi32(total1, _mm512_srli_epi32(total1,8)));
total0 = _mm512_and_epi32(B4, _mm512_add_epi32(total0, _mm512_srli_epi32(total0,16)));
total1 = _mm512_and_epi32(B4, _mm512_add_epi32(total1, _mm512_srli_epi32(total1,16)));
result0 = _mm512_add_epi32(result0,total0);
result1 = _mm512_add_epi32(result1,total1);
}
result0 = _mm512_add_epi32(result0,result1);
result = _mm512_reduce_add_epi32(result0);
return result;
}
vpu_popcount5:
inline uint64_t vpu_popcount5(uint64_t* buf, size_t n) {
_mm_prefetch((const char *)&buf[0], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[8], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[16], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[24], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[32], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[40], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[48], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[56], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[64], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[72], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[80], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[88], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[96], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[104], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[112], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[120], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[128], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[136], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[144], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[152], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[160], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[168], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[176], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[184], _MM_HINT_T1); // vprefetch1
register size_t result;
size_t i;
register const __m512i B0 = _mm512_load_epi32((void*)(magic+0));
register const __m512i B1 = _mm512_load_epi32((void*)(magic+16));
register const __m512i B2 = _mm512_load_epi32((void*)(magic+32));
register const __m512i B3 = _mm512_load_epi32((void*)(magic+48));
register const __m512i B4 = _mm512_load_epi32((void*)(magic+64));
register const __m512i B6 = _mm512_load_epi32((void*)(magic+80));
register __m512i total0;
register __m512i total1;
register __m512i total2;
register __m512i total3;
register __m512i shuf0;
register __m512i shuf1;
register __m512i shuf2;
register __m512i shuf3;
register __m512i result0;
register __m512i result1;
result0 = _mm512_setzero_epi32();
result1 = _mm512_setzero_epi32();
for (i = 0; i < n; i+=32) {
shuf0 = _mm512_load_epi32(&buf[i ]);
shuf1 = _mm512_load_epi32(&buf[i+ 8]);
shuf2 = _mm512_load_epi32(&buf[i+16]);
shuf3 = _mm512_load_epi32(&buf[i+24]);
_mm_prefetch((const char *)&buf[i+192], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+200], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+208], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+216], _MM_HINT_T1); // vprefetch1
_mm_prefetch((const char *)&buf[i+32], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[i+40], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[i+48], _MM_HINT_T0); // vprefetch0
_mm_prefetch((const char *)&buf[i+56], _MM_HINT_T0); // vprefetch0
total0 = _mm512_sub_epi32(shuf0, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf0,1))); // max value in nn is 10
total1 = _mm512_sub_epi32(shuf1, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf1,1)));
total2 = _mm512_sub_epi32(shuf2, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf2,1)));
total3 = _mm512_sub_epi32(shuf3, _mm512_and_epi32(B0, _mm512_srli_epi32(shuf3,1)));
total0 = _mm512_add_epi32(_mm512_and_epi32(B1, total0), _mm512_and_epi32(B1,_mm512_srli_epi32(total0,2))); // max value in nnnn is 0100
total1 = _mm512_add_epi32(_mm512_and_epi32(B1, total1), _mm512_and_epi32(B1,_mm512_srli_epi32(total1,2)));
total2 = _mm512_add_epi32(_mm512_and_epi32(B1, total2), _mm512_and_epi32(B1,_mm512_srli_epi32(total2,2)));
total3 = _mm512_add_epi32(_mm512_and_epi32(B1, total3), _mm512_and_epi32(B1,_mm512_srli_epi32(total3,2)));
total0 = _mm512_and_epi32(B2, _mm512_add_epi32(total0, _mm512_srli_epi32(total0,4))); // max value in 0000nnnn is 00001000
total1 = _mm512_and_epi32(B2, _mm512_add_epi32(total1, _mm512_srli_epi32(total1,4)));
total2 = _mm512_and_epi32(B2, _mm512_add_epi32(total2, _mm512_srli_epi32(total2,4)));
total3 = _mm512_and_epi32(B2, _mm512_add_epi32(total3, _mm512_srli_epi32(total3,4)));
total0 = _mm512_add_epi32(total0, total1); // max value in 000nnnnn is 00010000
total1 = _mm512_add_epi32(total2, total3);
total0 = _mm512_add_epi32(total0, _mm512_srli_epi32(total0,8)); // max value in xxxxxxxx00nnnnnn is 00100000
total1 = _mm512_add_epi32(total1, _mm512_srli_epi32(total1,8));
total0 = _mm512_and_epi32(B6, _mm512_add_epi32(total0, _mm512_srli_epi32(total0,16))); // max value in each element is 01000000, i.e. 64
total1 = _mm512_and_epi32(B6, _mm512_add_epi32(total1, _mm512_srli_epi32(total1,16)));
result0 = _mm512_add_epi32(result0,total0);
result1 = _mm512_add_epi32(result1,total1);
}
result0 = _mm512_add_epi32(result0,result1);
result = _mm512_reduce_add_epi32(result0);
return result;
}
मुझे लगता है कि इस सवाल का नहीं बल्कि बाद से अपने कोड पहले से ही काम करने के लिए लगता है पर [कोड समीक्षा] (http://codereview.stackexchange.com/) होना चाहिए। – Morwenn
बहुत ही रोचक सवाल - मुझे आशा है कि आप समुदाय में सक्रिय रहेंगे। मैं उस तकनीक पर सोच रहा था जिसका उपयोग आपने कैश हिट रेट को मापने के लिए किया था। चीयर्स! – BlueStrat
@ ब्लूस्ट्रैट, मैं कैश हिट दर प्राप्त करने के लिए इंटेल के vTune का उपयोग करता हूं। – Aquaskyline