我注意到有时候MSVC 2010根本不重新排序SSE指令。我认为在循环内部我不需要关心指令的顺序,因为编译器会处理最佳方案,但这似乎并非如此。
我该如何思考这个问题?是什么决定了最佳指令顺序?我知道一些指令比其他指令具有更高的延迟,并且某些指令可以在CPU级别上并行/异步运行。哪些指标在这种情况下是相关的?我在哪里可以找到它们?
我知道我可以通过性能分析避免这个问题,但这样的性能分析器很昂贵(VTune XE),而且我想知道背后的理论,而不仅仅是实证结果。
另外,我应该关心软件预取(_mm_prefetch),还是可以假设CPU会比我做得更好?
假设我有以下函数。我应该交错一些指令吗?我应该在流之前存储所有数据,按顺序加载所有数据,然后进行计算等吗?我需要考虑USWC vs非USWC,以及暂态vs非暂态吗?
我该如何思考这个问题?是什么决定了最佳指令顺序?我知道一些指令比其他指令具有更高的延迟,并且某些指令可以在CPU级别上并行/异步运行。哪些指标在这种情况下是相关的?我在哪里可以找到它们?
我知道我可以通过性能分析避免这个问题,但这样的性能分析器很昂贵(VTune XE),而且我想知道背后的理论,而不仅仅是实证结果。
另外,我应该关心软件预取(_mm_prefetch),还是可以假设CPU会比我做得更好?
假设我有以下函数。我应该交错一些指令吗?我应该在流之前存储所有数据,按顺序加载所有数据,然后进行计算等吗?我需要考虑USWC vs非USWC,以及暂态vs非暂态吗?
auto cur128 = reinterpret_cast<__m128i*>(cur);
auto prev128 = reinterpret_cast<const __m128i*>(prev);
auto dest128 = reinterpret_cast<__m128i*>(dest;
auto end = cur128 + count/16;
while(cur128 != end)
{
auto xmm0 = _mm_add_epi8(_mm_load_si128(cur128+0), _mm_load_si128(prev128+0));
auto xmm1 = _mm_add_epi8(_mm_load_si128(cur128+1), _mm_load_si128(prev128+1));
auto xmm2 = _mm_add_epi8(_mm_load_si128(cur128+2), _mm_load_si128(prev128+2));
auto xmm3 = _mm_add_epi8(_mm_load_si128(cur128+3), _mm_load_si128(prev128+3));
// dest128 is USWC memory
_mm_stream_si128(dest128+0, xmm0);
_mm_stream_si128(dest128+1, xmm1);
_mm_stream_si128(dest128+2, xmm2);;
_mm_stream_si128(dest128+3, xmm3);
// cur128 is temporal, and will be used next time, which is why I choose store over stream
_mm_store_si128 (cur128+0, xmm0);
_mm_store_si128 (cur128+1, xmm1);
_mm_store_si128 (cur128+2, xmm2);
_mm_store_si128 (cur128+3, xmm3);
cur128 += 4;
dest128 += 4;
prev128 += 4;
}
std::swap(cur, prev);