Da *_*eng 2 c performance gcc prefetch
我正在编写一个程序来分析社交网络图.这意味着程序需要大量的随机内存访问.在我看来,预取应该有所帮助.这是从顶点的邻居读取值的一小段代码.
for (size_t i = 0; i < v.get_num_edges(); i++) {
unsigned int id = v.neighbors[i];
res += neigh_vals[id];
}
Run Code Online (Sandbox Code Playgroud)
我将上面的代码转换为下面的代码,并预取顶点的邻居值.
int *neigh_vals = new int[num_vertices];
for (size_t i = 0; i < v.get_num_edges(); i += 128) {
size_t this_end = std::min(v.get_num_edges(), i + 128);
for (size_t j = i; j < this_end; j++) {
unsigned int id = v.neighbors[j];
__builtin_prefetch(&neigh_vals[id], 0, 2);
}
for (size_t j = i; j < this_end; j++) {
unsigned int id = v.neighbors[j];
res += neigh_vals[id];
}
}
Run Code Online (Sandbox Code Playgroud)
在这个C++代码中,我没有覆盖任何运算符.
不幸的是,代码并没有真正提高性能.我想知道为什么.显然,硬件预取在这种情况下不起作用,因为硬件无法预测内存位置.
我想知道它是否是由GCC优化引起的.当我编译代码时,我启用-O3.我真的希望即使启用-O3,预取也可以进一步提高性能.在这种情况下,-O3优化是否融合了两个循环?在这种情况下,-O3能否默认启用预取?
我使用gcc 4.6.3版,程序在Intel Xeon E5-4620上运行.
谢谢,Da
是的,GCC的一些最新版本(例如2015年3月的4.9)能够PREFETCH在优化时发出一些指令-O3(即使没有任何明确的__builtin_prefetch)
我们不知道get_neighbor在做什么,以及什么类型的v和neigh_val.
预取并不总是有利可图.添加显式__builtin_prefetch可能会降低代码速度.你需要衡量.
正如Retired Ninja评论的那样,在一个循环中进行预取并希望数据将在以下循环中缓存(在源代码中进一步向下)是错误的.
你也许可以尝试一下
for (size_t i = 0; i < v.get_num_edges(); i++) {
fg::vertex_id_t id = v.get_neighbor(i);
__builtin_prefetch (neigh_val[v.get_neighbor(i+4)]);
res += neigh_vals[id];
}
Run Code Online (Sandbox Code Playgroud)
你可以凭经验替换4任何适当的常数是最好的.
但我猜__builtin_prefetch上面的内容是无用的(因为编译器可能会自己添加它)并且它可能会损害(甚至崩溃程序,当计算其参数给出未定义的行为时,例如,如果v.get_neighbor(i+4)未定义;但是在外部预取地址您的地址空间不会受到伤害 - 但可能会减慢您的程序速度).请基准.
查看相关问题的答案.
请注意,在C++中,所有的[],get_neighbor都可能被重载并变得非常复杂的操作,所以我们无法猜测!
并且有些情况下硬件会限制性能,无论__builtin_prefetch你添加什么(并添加它们都会损害性能)
顺便说一下,您可以通过-O3 -mtune=native -fdump-tree-ssa -S -fverbose-asm了解更多编译器正在做的事情(并查看生成的转储文件和汇编程序文件); 而且,确实会-O3产生稍微慢于代码的代码-O2.
如果你有时间浪费在优化上,你可以考虑显式多线程,OpenMP,OpenCL.请记住,过早优化是邪恶的.您是否进行了基准测试,是否对整个应用程序进