_mm_set_epi*
을 피하고 _mm_load_si128
(또는 _mm_loadu_si128
)을 사용하는 것이 가장 좋음을 이해했습니다. 데이터가 정렬되지 않은 경우 작은 실적이 발생합니다. 그러나 성능에 미치는 영향이 저와 일치하지 않는 것 같습니다. 다음은 좋은 예입니다.왜 _mm_set_epi16이 _mm_load_si128보다 빠른 이유는 무엇입니까?
static uint32_t clmul_load(uint16_t x, uint16_t y)
{
const __m128i c = _mm_clmulepi64_si128(
_mm_load_si128((__m128i const*)(&x)),
_mm_load_si128((__m128i const*)(&y)), 0);
return _mm_extract_epi32(c, 0);
}
static uint32_t clmul_set(uint16_t x, uint16_t y)
{
const __m128i c = _mm_clmulepi64_si128(
_mm_set_epi16(0, 0, 0, 0, 0, 0, 0, x),
_mm_set_epi16(0, 0, 0, 0, 0, 0, 0, y), 0);
return _mm_extract_epi32(c, 0);
}
다음 함수는 두 가지의 성능 벤치 마크 :
가 SSE의 내장 함수 사용 다음과 같은 두 가지 기능을 고려 마지막으로
template <typename F>
void benchmark(int t, F f)
{
std::mt19937 rng(static_cast<unsigned int>(std::time(0)));
std::uniform_int_distribution<uint32_t> uint_dist10(
0, std::numeric_limits<uint32_t>::max());
std::vector<uint32_t> vec(t);
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < t; ++i)
{
vec[i] = f(uint_dist10(rng), uint_dist10(rng));
}
auto duration = std::chrono::duration_cast<
std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() -
start);
std::cout << (duration.count()/1000.0) << " seconds.\n";
}
을, 다음과 같은 주요 프로그램은 몇 가지 테스트를 수행합니다
int main()
{
const int N = 10000000;
benchmark(N, clmul_load);
benchmark(N, clmul_set);
}
MSVC 2013의 i7 Haswell에서 일반적인 출력 t은 일반적인 출력이 설명 무엇
0.312 seconds. // _mm_load_si128
0.262 seconds. // _mm_set_epi16
입니다 -O3 -std=c++11 -march=native
(약간 오래된 하드웨어) 매개 변수와 함께 GCC를 사용
0.208 seconds. // _mm_load_si128
0.129 seconds. // _mm_set_epi16
입니까? 실제로 _mm_set_epi*
이 _mm_load_si128
이상인 경우가 있습니까? 다른 경우에는 _mm_load_si128
이 더 잘 수행되는 것으로 나타 났지만 실제로는 그 관찰을 특성화 할 수 없습니다.
'_mm_insert_epi16' 시도해 볼 수 있습니다. '_mm_insert_epi16 (_mm_setzero_si128(), x, 0)'과 같은 것 - 정확히 맞는지 확실하지 않습니다. –