рддреЗрдЬ рдЧрддрд┐ рд╕реЗ рдЪрд▓рдиреЗ рдпрд╛ рд╕рд┐рдордб рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП

рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдПрдХ рд╡рд░реНрдЧ рд╣реИ рдЬреЛ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдХреЗ рддреНрд╡рд░рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдореЗрдВ рддреЗрдЬреА рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдЗрд╕ рд▓рдЧрднрдЧ рдЧрддрд┐рд░реЛрдз рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдкреНрд░реЛрд╕реЗрд╕рд░ рдбреЗрд╡рд▓рдкрд░реНрд╕ рд╣рдорд╛рд░реА рд╕рд╣рд╛рдпрддрд╛ рдХреЗ рд▓рд┐рдП рдЖрддреЗ рд╣реИрдВ, рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ рдХрдорд╛рдВрдб рдмрдирд╛рдП рд╣реИрдВ рдЬреЛ рд╣рдореЗрдВ рдПрдХ рдСрдкрд░реЗрд╢рди рдореЗрдВ рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рдбреЗрдЯрд╛ рдкрд░ рд╕рдВрдЪрд╛рд▓рди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВред X86 рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпреЗ рдПрдХреНрд╕рдЯреЗрдВрд╢рди MMX, SSE, SSE2, SSE3, SSE4, SSE4.1, SSE4.2, AVX, AVX2, AVX512 рдореЗрдВ рджрд┐рдП рдЧрдП рдирд┐рд░реНрджреЗрд╢ рд╣реИрдВред

"рдЧрд┐рдиреА рдкрд┐рдЧ" рдХреЗ рд░реВрдк рдореЗрдВ рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рдХрд┐рдпрд╛:
рдкреНрд░рдХрд╛рд░ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдирд┐рдпрдВрддреНрд░рд┐рдд рдЧрд┐рд░рдлреНрддрд╛рд░реА рд╕рд░рдгреА рд╣реИ uint16_tред рдЖрдкрдХреЛ рдЕрд░реЗ рд╕рд░рдгреА рдореЗрдВ v рдХреА рдШрдЯрдирд╛рдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдЬреНрдЮрд╛рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ рд░реИрдЦрд┐рдХ рд╕рдордп рд╕рдорд╛рдзрд╛рди рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

int64_t cnt = 0; for (int i = 0; i < ARR_SIZE; ++i) if (arr[i] == v) ++cnt; 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░рд┐рдгрд╛рдо рджрд┐рдЦрд╛рддрд╛ рд╣реИ:

 ------------------------------------------------------------ Benchmark Time CPU Iterations ------------------------------------------------------------ BM_Count 2084 ns 2084 ns 333079 

рдХрдЯ рдХреЗ рддрд╣рдд, рдореИрдВ рдпрд╣ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдЗрд╕реЗ 5+ рдмрд╛рд░ рдХреИрд╕реЗ рддреЗрдЬ рдХрд┐рдпрд╛ рдЬрд╛рдПред

рдкрд░реНрдпрд╛рд╡рд░рдг рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВ


рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz рд╕рд╛рде рдПрдХ рд▓реИрдкрдЯреЙрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдХрдВрдкрд╛рдЗрд▓рд░ clang version 6.0.0 ред рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдорд╛рдкрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ Google рд╕реЗ рд▓рд╛рдЗрдмреЗрдВрдЪрдорд╛рд░реНрдХ рдЪреБрдирд╛ред рд╕рд░рдгреА рдХрд╛ рдЖрдХрд╛рд░ рдореИрдВрдиреЗ 1024 рддрддреНрд╡реЛрдВ рдХреЛ рд▓рд┐рдпрд╛, рддрд╛рдХрд┐ рд╢рд╛рд╕реНрддреНрд░реАрдп рддрд░реАрдХреЗ рд╕реЗ рдмрд╛рдХреА рддрддреНрд╡реЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рди рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред

SIMD рдХреНрдпрд╛ рд╣реИ?


SIMD (рд╕рд┐рдВрдЧрд▓ рдЗрдВрд╕реНрдЯреНрд░рдХреНрд╢рди, рдорд▓реНрдЯреАрдкрд▓ рдбреЗрдЯрд╛) - рд╕рд┐рдВрдЧрд▓ рдЗрдВрд╕реНрдЯреНрд░рдХреНрд╢рди рд╕реНрдЯреНрд░реАрдо, рдорд▓реНрдЯреАрдкрд▓ рдбреЗрдЯрд╛ рд╕реНрдЯреНрд░реАрдоред X86 рд╕рдВрдЧрдд рдкреНрд░реЛрд╕реЗрд╕рд░ рдореЗрдВ, рдпреЗ рдХрдорд╛рдВрдб SSE рдФрд░ AVX рдкреНрд░реЛрд╕реЗрд╕рд░ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреА рдХрдИ рдкреАрдврд╝рд┐рдпреЛрдВ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдП рдЧрдП рдереЗред рдмрд╣реБрдд рд╕рд╛рд░реА рдЯреАрдореЗрдВ рд╣реИрдВ, Intel рдХреА рдкреВрд░реА рд╕реВрдЪреА software.intel.com/sites/landingpage/IntrinsicsGuide рдкрд░ рджреЗрдЦреА рдЬрд╛ рд╕рдХрддреА рд╣реИред рдбреЗрд╕реНрдХрдЯреЙрдк AVX рдкреНрд░реЛрд╕реЗрд╕рд░ рдореЗрдВ, рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдЙрдкрд▓рдмреНрдз рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдЖрдЗрдП SSE рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░реЗрдВред

C / C ++ рдореЗрдВ SIMD рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдХреЛрдб рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛

 #include <x86intrin.h> 

рд╕рд╛рде рд╣реА, рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЛ рдмрддрд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЕрдиреНрдпрдерд╛ always_inline function '_popcnt32' requires target feature 'popcnt', but ... рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рддреНрд░реБрдЯрд┐рдпреЛрдВ always_inline function '_popcnt32' requires target feature 'popcnt', but ... рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рдХрдИ рддрд░реАрдХреЗ рд╣реИрдВ:

  1. рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП -mpopcnt , рд╕рднреА рдЖрд╡рд╢реНрдпрдХ -mpopcnt
  2. рдЖрд╡рд╢реНрдпрдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ рд▓рдХреНрд╖реНрдп рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП -march=corei7
  3. рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЛ рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ рд╕рднреА рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рджреЗрдВ, рдЬрд┐рд╕ рдкрд░ рдЕрд╕реЗрдВрдмрд▓реА рд╣реЛрддреА рд╣реИ: -march=native

3 рд▓рд╛рдЗрдиреЛрдВ рдХреЗ рдХреЛрдб рдореЗрдВ рдХреНрдпрд╛ рддреНрд╡рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ?


 for (int i = 0; i < ARR_SIZE; ++i) if (arr[i] == v) ++cnt; 

рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдХрдо рдХрд░рдирд╛ рдФрд░ рдПрдХ рдЪрдХреНрд░ рдореЗрдВ рдХрдИ рддрддреНрд╡реЛрдВ рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░рдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред рд╣рдо рдЗрдВрдЯреЗрд▓ рд╕реЗ рд╕рд╛рдЗрдЯ рдЦреЛрд▓рддреЗ рд╣реИрдВ, рд╣рдо рдХреЗрд╡рд▓ рдПрд╕рдПрд╕рдИ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдФрд░ "рддреБрд▓рдирд╛" рд╢реНрд░реЗрдгреА рдХрд╛ рдЪрдпрди рдХрд░рддреЗ рд╣реИрдВред рд╕реВрдЪреА рдореЗрдВ рдкрд╣рд▓рд╛ рдХрд╛рд░реНрдп __m128i _mm_cmpeq_epi* (__m128i a, __m128i b) ред

рдЫрд╡рд┐

рд╣рдо рдЙрдирдореЗрдВ рд╕реЗ рдкрд╣рд▓реЗ рдХрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬ рдЦреЛрд▓рддреЗ рд╣реИрдВ рдФрд░ рджреЗрдЦрддреЗ рд╣реИрдВ:
рд╕рдорд╛рдирддрд╛ рдХреЗ рд▓рд┐рдП рдП рдФрд░ рдмреА рдореЗрдВ рдкреИрдХ 16-рдмрд┐рдЯ рдкреВрд░реНрдгрд╛рдВрдХ рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВ, рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ dst рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВред
рдЖрдкрдХреЛ рдХреНрдпрд╛ рдЪрд╛рд╣рд┐рдП! рдпрд╣ рдХреЗрд╡рд▓ []int16_t рдореЗрдВ []int16_t рдХреЛ рдЪрд╛рд▓реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рдЗрд╕рдХреЗ рд▓рд┐рдП, "рд╕реЗрдЯ" рдФрд░ "рд▓реЛрдб" рд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рддреЛ, _mm_cmpeq_epi16 рдлрд╝рдВрдХреНрд╢рди "рд╕рд░рдгрд┐рдпреЛрдВ" a рдФрд░ b рдореЗрдВ рд╕рдорд╛рдирд╛рдВрддрд░ 8 int16_t рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╕рдорд╛рди рддрддреНрд╡реЛрдВ рдХреЗ рд▓рд┐рдП 0xFFFF рдХреА рд╕рдВрдЦреНрдпрд╛ рдФрд░ рднрд┐рдиреНрди рдХреЗ рд▓рд┐рдП 0x0000 рдХреА "рд╕рд░рдгреА" рджреЗрддрд╛ рд╣реИ:

рдЫрд╡рд┐

рдПрдХ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдмрд┐рдЯ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреА рддреНрд╡рд░рд┐рдд рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП, рдХреНрд░рдорд╢рдГ 32 рдФрд░ 64 рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реЗ _popcnt32 рдФрд░ _popcnt64 рдлрд╝рдВрдХреНрд╢рди рд╣реИрдВред рд▓реЗрдХрд┐рди, рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдРрд╕рд╛ рдХреЛрдИ рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ рдЬреЛ _mm_cmpeq_epi16 рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдПрдХ _mm_cmpeq_epi16 рдкрд░ рд▓рд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдлрд╝рдВрдХреНрд╢рди _mm_movemask_epi8 рдЬреЛ 16 int8_t рд╕рдВрдЦреНрдпрд╛ рдХреЗ "рд╕рд░рдгреА" рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рдСрдкрд░реЗрд╢рди рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди _mm_movemask_epi8 рдХреЛ 8 int16_t рд╕рдВрдЦреНрдпрд╛ рдХреЗ "рд╕рд░рдгреА" рдХреЗ рд▓рд┐рдП рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдмрд╕ рдЕрдВрдд рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдХреЛ 2 рд╕реЗ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдЕрдм SIMD рдХрд╛ рдкрд░реАрдХреНрд╖рдг рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдм рдХреБрдЫ рд╣реИред

рд╡рд┐рдХрд▓реНрдк 1


 int64_t cnt = 0; //     ""  8   auto sseVal = _mm_set1_epi16(VAL); for (int i = 0; i < ARR_SIZE; i += 8) { //     8       auto sseArr = _mm_set_epi16(arr[i + 7], arr[i + 6], arr[i + 5], arr[i + 4], arr[i + 3], arr[i + 2], arr[i + 1], arr[i]); //    * 2 cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); } //   2 cnt >>= 1; 

рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдиреЗ рдирд┐рдореНрди рдкрд░рд┐рдгрд╛рдо рджрд┐рдЦрд╛рдП:

 ------------------------------------------------------------ Benchmark Time CPU Iterations ------------------------------------------------------------ BM_Count 2084 ns 2084 ns 333079 BM_SSE_COUNT_SET_EPI 937 ns 937 ns 746435 

рдХреЗрд╡рд▓ 2 рдмрд╛рд░ рддреЗрдЬреА рд╕реЗ, рдФрд░ рдореИрдВрдиреЗ 5+ рдХрд╛ рд╡рд╛рджрд╛ рдХрд┐рдпрд╛ред

рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдЕрдбрд╝рдЪрдиреЗрдВ рдХрд╣рд╛рдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ, рдЖрдкрдХреЛ рдиреАрдЪреЗ рдЕрд╕реЗрдВрдмрд▓рд░ рд╕реНрддрд░ рдкрд░ рдЬрд╛рдирд╛ рд╣реЛрдЧрд╛ред

 ---------------  8   sseArr --------------- auto sseArr = _mm_set_epi16(arr[i + 7], arr[i + 6], arr[i + 5], arr[i + 4], arr[i + 3], arr[i + 2], 40133a: 48 8b 05 77 1d 20 00 mov 0x201d77(%rip),%rax # 6030b8 <_ZL3arr> arr[i + 1], arr[i]); 401341: 48 63 8d 9c fe ff ff movslq -0x164(%rbp),%rcx auto sseArr = _mm_set_epi16(arr[i + 7], arr[i + 6], arr[i + 5], arr[i + 4], arr[i + 3], arr[i + 2], 401348: 66 8b 54 48 0e mov 0xe(%rax,%rcx,2),%dx 40134d: 66 8b 74 48 0c mov 0xc(%rax,%rcx,2),%si 401352: 66 8b 7c 48 0a mov 0xa(%rax,%rcx,2),%di 401357: 66 44 8b 44 48 08 mov 0x8(%rax,%rcx,2),%r8w 40135d: 66 44 8b 4c 48 06 mov 0x6(%rax,%rcx,2),%r9w 401363: 66 44 8b 54 48 04 mov 0x4(%rax,%rcx,2),%r10w arr[i + 1], arr[i]); 401369: 66 44 8b 1c 48 mov (%rax,%rcx,2),%r11w 40136e: 66 8b 5c 48 02 mov 0x2(%rax,%rcx,2),%bx auto sseArr = _mm_set_epi16(arr[i + 7], arr[i + 6], arr[i + 5], arr[i + 4], arr[i + 3], arr[i + 2], 401373: 66 89 55 ce mov %dx,-0x32(%rbp) 401377: 66 89 75 cc mov %si,-0x34(%rbp) 40137b: 66 89 7d ca mov %di,-0x36(%rbp) 40137f: 66 44 89 45 c8 mov %r8w,-0x38(%rbp) 401384: 66 44 89 4d c6 mov %r9w,-0x3a(%rbp) 401389: 66 44 89 55 c4 mov %r10w,-0x3c(%rbp) 40138e: 66 89 5d c2 mov %bx,-0x3e(%rbp) 401392: 66 44 89 5d c0 mov %r11w,-0x40(%rbp) 401397: 44 0f b7 75 c0 movzwl -0x40(%rbp),%r14d 40139c: c4 c1 79 6e c6 vmovd %r14d,%xmm0 4013a1: 44 0f b7 75 c2 movzwl -0x3e(%rbp),%r14d 4013a6: c4 c1 79 c4 c6 01 vpinsrw $0x1,%r14d,%xmm0,%xmm0 4013ac: 44 0f b7 75 c4 movzwl -0x3c(%rbp),%r14d 4013b1: c4 c1 79 c4 c6 02 vpinsrw $0x2,%r14d,%xmm0,%xmm0 4013b7: 44 0f b7 75 c6 movzwl -0x3a(%rbp),%r14d 4013bc: c4 c1 79 c4 c6 03 vpinsrw $0x3,%r14d,%xmm0,%xmm0 4013c2: 44 0f b7 75 c8 movzwl -0x38(%rbp),%r14d 4013c7: c4 c1 79 c4 c6 04 vpinsrw $0x4,%r14d,%xmm0,%xmm0 4013cd: 44 0f b7 75 ca movzwl -0x36(%rbp),%r14d 4013d2: c4 c1 79 c4 c6 05 vpinsrw $0x5,%r14d,%xmm0,%xmm0 4013d8: 44 0f b7 75 cc movzwl -0x34(%rbp),%r14d 4013dd: c4 c1 79 c4 c6 06 vpinsrw $0x6,%r14d,%xmm0,%xmm0 4013e3: 44 0f b7 75 ce movzwl -0x32(%rbp),%r14d 4013e8: c4 c1 79 c4 c6 07 vpinsrw $0x7,%r14d,%xmm0,%xmm0 4013ee: c5 f9 7f 45 b0 vmovdqa %xmm0,-0x50(%rbp) 4013f3: c5 f9 6f 45 b0 vmovdqa -0x50(%rbp),%xmm0 4013f8: c5 f9 7f 85 80 fe ff vmovdqa %xmm0,-0x180(%rbp) 4013ff: ff ---------------    --------------- cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); 401400: c5 f9 6f 85 a0 fe ff vmovdqa -0x160(%rbp),%xmm0 401407: ff 401408: c5 f9 6f 8d 80 fe ff vmovdqa -0x180(%rbp),%xmm1 40140f: ff 401410: c5 f9 7f 45 a0 vmovdqa %xmm0,-0x60(%rbp) 401415: c5 f9 7f 4d 90 vmovdqa %xmm1,-0x70(%rbp) 40141a: c5 f9 6f 45 a0 vmovdqa -0x60(%rbp),%xmm0 40141f: c5 f9 6f 4d 90 vmovdqa -0x70(%rbp),%xmm1 401424: c5 f9 75 c1 vpcmpeqw %xmm1,%xmm0,%xmm0 401428: c5 f9 7f 45 80 vmovdqa %xmm0,-0x80(%rbp) 40142d: c5 f9 6f 45 80 vmovdqa -0x80(%rbp),%xmm0 401432: c5 79 d7 f0 vpmovmskb %xmm0,%r14d 401436: 44 89 b5 7c ff ff ff mov %r14d,-0x84(%rbp) 40143d: 44 8b b5 7c ff ff ff mov -0x84(%rbp),%r14d 401444: f3 45 0f b8 f6 popcnt %r14d,%r14d 401449: 49 63 c6 movslq %r14d,%rax 40144c: 48 03 85 b8 fe ff ff add -0x148(%rbp),%rax 401453: 48 89 85 b8 fe ff ff mov %rax,-0x148(%rbp) 

рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдкреНрд░реЛрд╕реЗрд╕рд░ рдирд┐рд░реНрджреЗрд╢ sseArr рдореЗрдВ рд╕рд░рдгреА рддрддреНрд╡реЛрдВ рдХреА рдирдХрд▓ sseArr ред

рд╡рд┐рдХрд▓реНрдк 2


_mm_set_epi16 рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрдЬрд╛рдп, рдЖрдк _mm_loadu_si128 рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рдорд╛рд░реЛрд╣ рд╡рд┐рд╡рд░рдг:
128-рдкреВрд░реНрдгрд╛рдВрдХ рдбреЗрдЯрд╛ рдХреЗ рдкреВрд░реНрдг-рдмрд┐рдЯ рдбреЗрдЯрд╛ рдХреЛ рдЕрдирд▓реЙрдЧреНрдб рдореЗрдореЛрд░реА рд╕реЗ dst рдореЗрдВ рд▓реЛрдб рдХрд░реЗрдВ
рдЗрдирдкреБрдЯ рдкрд░ рдореЗрдореЛрд░реА рдХреЗ рд▓рд┐рдП рдПрдХ рдкреЙрдЗрдВрдЯрд░ рдХреА рдЙрдореНрдореАрдж рдХреА рдЬрд╛рддреА рд╣реИ, рдЬреЛ рдЪрд░ рдореЗрдВ рдбреЗрдЯрд╛ рдХреА рдЕрдзрд┐рдХ рдЗрд╖реНрдЯрддрдо рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдкрд░ рд╕рдВрдХреЗрдд рджреЗрддрд╛ рд╣реИред рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:

 int64_t cnt = 0; auto sseVal = _mm_set1_epi16(VAL); for (int i = 0; i < ARR_SIZE; i += 8) { auto sseArr = _mm_loadu_si128((__m128i *) &arr[i]); cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); } 

рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдиреЗ ~ 2 рдмрд╛рд░ рд╕реБрдзрд╛рд░ рджрд┐рдЦрд╛рдпрд╛:

 ------------------------------------------------------------ Benchmark Time CPU Iterations ------------------------------------------------------------ BM_Count 2084 ns 2084 ns 333079 BM_SSE_COUNT_SET_EPI 937 ns 937 ns 746435 BM_SSE_COUNT_LOADU 454 ns 454 ns 1548455 

рдорд╢реАрди рдХреЛрдб рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

  auto sseArr = _mm_loadu_si128((__m128i *) &arr[i]); 401695: 48 8b 05 1c 1a 20 00 mov 0x201a1c(%rip),%rax # 6030b8 <_ZL3arr> 40169c: 48 63 8d bc fe ff ff movslq -0x144(%rbp),%rcx 4016a3: 48 8d 04 48 lea (%rax,%rcx,2),%rax 4016a7: 48 89 45 d8 mov %rax,-0x28(%rbp) 4016ab: 48 8b 45 d8 mov -0x28(%rbp),%rax 4016af: c5 fa 6f 00 vmovdqu (%rax),%xmm0 4016b3: c5 f9 7f 85 a0 fe ff vmovdqa %xmm0,-0x160(%rbp) 4016ba: ff cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); 4016bb: c5 f9 6f 85 c0 fe ff vmovdqa -0x140(%rbp),%xmm0 4016c2: ff 4016c3: c5 f9 6f 8d a0 fe ff vmovdqa -0x160(%rbp),%xmm1 4016ca: ff 4016cb: c5 f9 7f 45 c0 vmovdqa %xmm0,-0x40(%rbp) 4016d0: c5 f9 7f 4d b0 vmovdqa %xmm1,-0x50(%rbp) 4016d5: c5 f9 6f 45 c0 vmovdqa -0x40(%rbp),%xmm0 4016da: c5 f9 6f 4d b0 vmovdqa -0x50(%rbp),%xmm1 4016df: c5 f9 75 c1 vpcmpeqw %xmm1,%xmm0,%xmm0 4016e3: c5 f9 7f 45 a0 vmovdqa %xmm0,-0x60(%rbp) 4016e8: c5 f9 6f 45 a0 vmovdqa -0x60(%rbp),%xmm0 4016ed: c5 f9 d7 d0 vpmovmskb %xmm0,%edx 4016f1: 89 55 9c mov %edx,-0x64(%rbp) 4016f4: 8b 55 9c mov -0x64(%rbp),%edx 4016f7: f3 0f b8 d2 popcnt %edx,%edx 4016fb: 48 63 c2 movslq %edx,%rax 4016fe: 48 03 85 d8 fe ff ff add -0x128(%rbp),%rax 401705: 48 89 85 d8 fe ff ff mov %rax,-0x128(%rbp) 

рд╡рд┐рдХрд▓реНрдк 3


SSE рдирд┐рд░реНрджреЗрд╢ 16 рдмрд╛рдЗрдЯ рд╕рдВрд░реЗрдЦрд┐рдд рдореЗрдореЛрд░реА рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред _Mm_loadu_si128 рдлрд╝рдВрдХреНрд╢рди рдЖрдкрдХреЛ рдЗрд╕ рд╕реАрдорд╛ рд╕реЗ рдмрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЖрдк aligned_alloc(16, SZ) рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рд░рдгреА рдХреЗ рд▓рд┐рдП рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рд╕реАрдзреЗ SSE рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдкрддрд╛ рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

 int64_t cnt = 0; auto sseVal = _mm_set1_epi16(VAL); for (int i = 0; i < ARR_SIZE; i += 8) { auto sseArr = *(__m128i *) &allignedArr[i]; cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); } 

рдЗрд╕ рддрд░рд╣ рдХрд╛ рдЕрдиреБрдХреВрд▓рди рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдмрдврд╝рд╛рд╡рд╛ рджреЗрддрд╛ рд╣реИ:

 ------------------------------------------------------------ Benchmark Time CPU Iterations ------------------------------------------------------------ BM_Count 2084 ns 2084 ns 333079 BM_SSE_COUNT_SET_EPI 937 ns 937 ns 746435 BM_SSE_COUNT_LOADU 454 ns 454 ns 1548455 BM_SSE_COUNT_DIRECT 395 ns 395 ns 1770803 

3 рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреА рдмрдЪрдд рдХреЗ рдХрд╛рд░рдг рдРрд╕рд╛ рд╣реБрдЖ:

  auto sseArr = *(__m128i *) &allignedArr[i]; 40193c: 48 8b 05 7d 17 20 00 mov 0x20177d(%rip),%rax # 6030c0 <_ZL11allignedArr> 401943: 48 63 8d cc fe ff ff movslq -0x134(%rbp),%rcx 40194a: c5 f9 6f 04 48 vmovdqa (%rax,%rcx,2),%xmm0 40194f: c5 f9 7f 85 b0 fe ff vmovdqa %xmm0,-0x150(%rbp) 401956: ff cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); 401957: c5 f9 6f 85 d0 fe ff vmovdqa -0x130(%rbp),%xmm0 40195e: ff 40195f: c5 f9 6f 8d b0 fe ff vmovdqa -0x150(%rbp),%xmm1 401966: ff 401967: c5 f9 7f 45 d0 vmovdqa %xmm0,-0x30(%rbp) 40196c: c5 f9 7f 4d c0 vmovdqa %xmm1,-0x40(%rbp) 401971: c5 f9 6f 45 d0 vmovdqa -0x30(%rbp),%xmm0 401976: c5 f9 6f 4d c0 vmovdqa -0x40(%rbp),%xmm1 40197b: c5 f9 75 c1 vpcmpeqw %xmm1,%xmm0,%xmm0 40197f: c5 f9 7f 45 b0 vmovdqa %xmm0,-0x50(%rbp) 401984: c5 f9 6f 45 b0 vmovdqa -0x50(%rbp),%xmm0 401989: c5 f9 d7 d0 vpmovmskb %xmm0,%edx 40198d: 89 55 ac mov %edx,-0x54(%rbp) 401990: 8b 55 ac mov -0x54(%rbp),%edx 401993: f3 0f b8 d2 popcnt %edx,%edx 401997: 48 63 c2 movslq %edx,%rax 40199a: 48 03 85 e8 fe ff ff add -0x118(%rbp),%rax 4019a1: 48 89 85 e8 fe ff ff mov %rax,-0x118(%rbp) 

рдирд┐рд╖реНрдХрд░реНрд╖


рдЗрди рд╕рднреА рд╡рд┐рдзрд╛рдирд╕рднрд╛ рд╕реВрдЪрд┐рдпреЛрдВ рдХреЛ -0 рдХреЗ рд╕рдВрдХрд▓рди рдХреЗ рдмрд╛рдж рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдпрджрд┐ рдЖрдк -O3 рдХреЛ рд╕рдХреНрд╖рдо рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╕рдВрдХрд▓рдХ рдХреЛрдб рдХреЛ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдРрд╕рд╛ рдХреЛрдИ рд╕рдордп рд╡рд┐рднрд╛рдЬрди рдирд╣реАрдВ рд╣реЛрдЧрд╛:

 ------------------------------------------------------------ Benchmark Time CPU Iterations ------------------------------------------------------------ BM_Count 129 ns 129 ns 5359145 BM_SSE_COUNT_SET_EPI 70 ns 70 ns 9936200 BM_SSE_COUNT_LOADU 49 ns 49 ns 14187659 BM_SSE_COUNT_DIRECT 53 ns 53 ns 13401612 

рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХреЛрдб
 #include <benchmark/benchmark.h> #include <x86intrin.h> #include <cstring> #define ARR_SIZE 1024 #define VAL 50 static int16_t *getRandArr() { auto res = new int16_t[ARR_SIZE]; for (int i = 0; i < ARR_SIZE; ++i) { res[i] = static_cast<int16_t>(rand() % (VAL * 2)); } return res; } static auto arr = getRandArr(); static int16_t *getAllignedArr() { auto res = aligned_alloc(16, sizeof(int16_t) * ARR_SIZE); memcpy(res, arr, sizeof(int16_t) * ARR_SIZE); return static_cast<int16_t *>(res); } static auto allignedArr = getAllignedArr(); static void BM_Count(benchmark::State &state) { for (auto _ : state) { int64_t cnt = 0; for (int i = 0; i < ARR_SIZE; ++i) if (arr[i] == VAL) ++cnt; benchmark::DoNotOptimize(cnt); } } BENCHMARK(BM_Count); static void BM_SSE_COUNT_SET_EPI(benchmark::State &state) { for (auto _ : state) { int64_t cnt = 0; auto sseVal = _mm_set1_epi16(VAL); for (int i = 0; i < ARR_SIZE; i += 8) { auto sseArr = _mm_set_epi16(arr[i + 7], arr[i + 6], arr[i + 5], arr[i + 4], arr[i + 3], arr[i + 2], arr[i + 1], arr[i]); cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); } benchmark::DoNotOptimize(cnt >> 1); } } BENCHMARK(BM_SSE_COUNT_SET_EPI); static void BM_SSE_COUNT_LOADU(benchmark::State &state) { for (auto _ : state) { int64_t cnt = 0; auto sseVal = _mm_set1_epi16(VAL); for (int i = 0; i < ARR_SIZE; i += 8) { auto sseArr = _mm_loadu_si128((__m128i *) &arr[i]); cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); } benchmark::DoNotOptimize(cnt >> 1); } } BENCHMARK(BM_SSE_COUNT_LOADU); static void BM_SSE_COUNT_DIRECT(benchmark::State &state) { for (auto _ : state) { int64_t cnt = 0; auto sseVal = _mm_set1_epi16(VAL); for (int i = 0; i < ARR_SIZE; i += 8) { auto sseArr = *(__m128i *) &allignedArr[i]; cnt += _popcnt32(_mm_movemask_epi8(_mm_cmpeq_epi16(sseVal, sseArr))); } benchmark::DoNotOptimize(cnt >> 1); } } BENCHMARK(BM_SSE_COUNT_DIRECT); BENCHMARK_MAIN(); 



рднрд╛рдЧ реи

Source: https://habr.com/ru/post/hi440566/


All Articles