[英]C++ optimize simple loop
我正在使用Visual Studio 2012并在x64发布模式下构建。 以下代码花费了我的程序运行时间的33.5%。 我使用Visual Studio Profiler对其进行了测量。
//every variable is unsigned int or unsigned int*
for(unsigned int i = 0; i < num; i++)
{
unique[ids[i]]++;//2.1%
total[ids[i]] += main_list[id];//31.4%
}
有人可以建议一种减少此功能运行时间的方法吗?
编辑 :根据您的输入,我尝试了以下代码:
const unsigned int now = main_list[id];
for(unsigned int i = ids[0], j = 0; j < num; j++)
{
++unique[i];//2.0%
total[i] += now;//16.7%
i = ids[j];//16.8%
}
这证实了以下理论:CPU分支预测可能会失败,因为位置是随机的(顺便说一下,它们不是完全随机的,而是经过排序的)。 请问是否有可能加快我的代码的速度?
第2次修改:我尝试了以下操作:
const unsigned int now = main_list[id];
for(unsigned int i = ids[0], j = 0; j < num; j++)
{
total[i] += now;//2.0%
++unique[i];//16.7%
i = ids[j];//16.8%
}
以上测试应清楚说明正在发生的情况。
您的代码没有任何地区友好性。 我会提出两个可能的想法。
分组unique
, total
在一起。
struct Stuff { unsigned int unique, total; }; for(unsigned int i = 0; i < num; i++) { Stuff& s = stuffs[ids[i]]; s.unique++; s.total += main_list[id]; // <== is this supposed to be ids[i]? }
这样可以确保您在内存中连续访问的内容实际上在内存中彼此相邻。 照num
,假设num
足够大,那么每一行都会丢失缓存。 那差不多是你能得到的。
排序ids
。 现在,您还在记忆中弹跳。 让我们确保我们可以按顺序进行:
std::sort(ids, ids + num); // rest of loop as before
这样,很可能在处理stuffs[ids[i]]
会预stuffs[ids[i+1]]
stuffs[ids[i]]
。 这样也可以节省您很多查找时间。
您可能会因别名而受到打击,因为它必须允许unique
, total
和main_list
在内存中重叠的可能性,从而使编译器无法在此处优化循环。 这可能会更好:
const auto mainListId = main_list[id];
for (unsigned int i = 0; i < num; ++i) {
const auto currId = ids[i];
++unique[currId];
total[currId] += mainListId;
}
当然,假设实际上没有任何混淆。
这样一个简单的循环可以做的事情不多。 您可以确保将编译器优化设置设置为最大,如果编译器没有为您完成循环,则可以尝试展开循环。 除此之外,您可能需要对算法进行改进,使其超出此处显示的代码范围。
由于ids
的顺序导致的非顺序内存访问,可能会限制内存。 可以通过在此循环之前对ids
数组进行排序来解决此问题,但是如果您没有更多上下文信息可以尝试进行操作,那么很难说这是否有意义。
我对i = ids[j]; //16.8%
感到惊讶i = ids[j]; //16.8%
i = ids[j]; //16.8%
应该会更快。 看来时机已到。 ++unique[i]; //2.0%
++unique[i]; //2.0%
是一种非线性(不可预取)访问,应该更慢,而不是快8倍。 实际上, ids[]
应该在高速缓存中,因此只有8分之1的访问会命中主内存。 声明应该快 8倍。 您确定您有正确的时间进行正确的操作吗?
也就是说,您应该并行化循环。 不会有太大帮助; 主内存不会变快。 但是,您应该保持主内存繁忙。 如果没有显式访问,CPU预取器的想法是抛出一些预测的访问。 如果预测正确,则可以节省时间,否则只会浪费一点能量。
因为ids[]
已排序,所以可以并行化循环。 即使存在重复的值,它们也是相邻的,因此您可以通过查找重复值的第一个出现点来找到分割点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.