使用valgrind和perf / FlameGraphs,我发现我的部分应用程序消耗了几乎100%的CPU:
for(size_t i = 0; i < objects.size(); i++) {
//this part consumes 11% CPU ----->
collions_count = database->get_collisions(collisions_block, objects[i].getKey());
feature1 = objects[i].feature1;
//<--------
for(int j = 0; j < collions_count * 2; j += 2) {
hash =
((collisions_block[j] & config::MASK_1) << config::SHIFT) |
((collisions_block[j+1] - feature1) & config::MASK_2);
if (++offsets[hash] >= config::THRESHOLD_1) {
//... this part consumes < 1% of CPU
}
}
}
哈希和后续if语句的计算占用了所有应用程序的近90%的CPU。
collisions_block
初始化一次,类型为int[100000]
config::
是包含全局配置变量的名称空间offsets
初始化一次,类型为uint8_t[1<<24]
usr
mpstat输出中没有iowait
-std=gnu++11 -Ofast -Wall
有没有办法加速内循环?
答案 0 :(得分:1)
我发现性能瓶颈是对数组++offsets[hash]
的无序访问。耗费了大部分CPU时间(75 +%)。通过将数组的大小从1<<24
减少到1<<21
并尝试使用适当的MASKS
配置,我实现了2.5倍的速度提升。
我将简要描述我如何识别问题
for(size_t i = 0; i < objects.size(); i++) {
//this part consumes 11% CPU ----->
collions_count = database->get_collisions(collisions_block, objects[i].getKey());
feature1 = objects[i].feature1;
//<--------
for(int j = 0; j < collions_count * 2; j += 2) {
hash = calculate_hash(collisions_block[j],
collisions_block[j+1],
feature1,
config::MASK_1,
config::MASK_2
config::SHIFT);
if (check_condition(hash, config::THRESHOLD_1)) {
//... this part consumes < 1% of CPU
}
}
}
__attribute__((noinline))
以防止gcc内联新函数。如果内联,它们将不会出现在调用堆栈中)-g -rdynamic
gcc flags perf record -p <pid> -F 200 -g --call-graph dwarf -- sleep 60
perf script | ./stackcollapse-perf.pl > out.perf-folded && ./flamegraph.pl out.perf-folded > graph.svg