gpt4 book ai didi

c++ - SSE微优化指令顺序

转载 作者:可可西里 更新时间:2023-11-01 15:39:18 25 4
gpt4 key购买 nike

我注意到有时 MSVC 2010 根本不会重新排序 SSE 指令。我认为我不必关心循环内的指令顺序,因为编译器处理得最好,但事实并非如此。

我应该如何考虑这个问题?什么决定了最佳指令顺序?我知道某些指令的延迟比其他指令高,并且某些指令可以在 cpu 级别并行/异步运行。哪些指标与上下文相关?我在哪里可以找到它们?

我知道我可以通过分析避免这个问题,但是这样的分析器很昂贵(VTune XE)并且我想知道它背后的理论,而不仅仅是实证结果。

我还应该关心软件预取 (_mm_prefetch) 还是我可以假设 cpu 会比我做得更好?

假设我有以下功能。我应该插入一些说明吗?我应该在流之前做商店,按顺序做所有的负载然后做计算等等......?我是否需要考虑 USWC 与非 USWC,以及时间与非时间?

            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);

最佳答案

我同意所有人的观点,即测试和调整是最好的方法。但是有一些技巧可以帮助它。

首先,MSVC 确实重新排序 SSE 指令。您的示例可能过于简单或已经优化。

一般来说,如果您有足够的寄存器来执行此操作,则完全交错往往会提供最佳结果。更进一步,将循环充分展开以使用所有寄存器,但不要过多溢出。在您的示例中,循环完全受内存访问限制,因此没有太多改进空间。

在大多数情况下,不必为了获得最佳性能而获得完美的指令顺序。只要它“足够接近”,编译器或硬件的乱序执行都会为您修复它。

我用来确定我的代码是否最优的方法是关键路径和瓶颈分析。在我写完循环后,我会查看哪些指令使用哪些资源。使用该信息,我可以计算性能上限,然后将其与实际结果进行比较,以了解我与最佳状态的差距。

例如,假设我有一个包含 100 次加法和 50 次乘法的循环。在 Intel 和 AMD(推土机之前的版本)上,每个内核每个周期都可以维持一个 SSE/AVX 加法和一个 SSE/AVX 乘法。由于我的循环有 100 次添加,我知道我不能比 100 次循环做得更好。是的,乘法器有一半时间是空闲的,但加法器是瓶颈。

现在我开始为我的循环计时,每次迭代我得到 105 个循环。这意味着我非常接近最佳状态并且没有更多收获。但是,如果我得到 250 个循环,则意味着循环有问题,值得对其进行更多修改。

关键路径分析遵循相同的思路。查看所有指令的延迟并找到循环关键路径的循环时间。如果您的实际表现非常接近它,那么您已经是最优的。

Agner Fog 对当前处理器的内部细节有很好的引用: http://www.agner.org/optimize/microarchitecture.pdf

关于c++ - SSE微优化指令顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7268800/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com