使用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
}
}
}
hash和follow if语句的计算占用了所有应用程序的近90%的CPU.
> collisions_block初始化一次,类型为int [100000]
> config ::是一个包含全局配置变量的命名空间
>偏移初始化一次,类型为uint8_t [1 << 24]
>我正在运行Centos7 Linux 3.10.0-327.13.1.el7.x86_64
>所有CPU都用于usr,mpstat输出中没有iowait
>我正在编译g(GCC)4.8.5 20150623(Red Hat 4.8.5-4)和标志-std = gnu 11 -Ofast -Wall
有没有办法加快内循环?
最佳答案 我发现性能瓶颈是对数组偏移[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
}
}
}
>将关键的2行拆分为单独的函数以便更好地进行分析(小心放置__attribute __((noinline))以防止gcc内联新函数.如果内联,它们不会出现在调用堆栈中)
>使用-g -rdynamic gcc标志编译代码
>运行采样pefrormance工具perf记录-p< pid> -F 200 -g – 呼叫图矮人 – 睡60
>转换为FlameGraph以获得更好的可读性性能脚本| ./stackcollapse-perf.pl\u0026gt; out.perf-fold&& ./flamegraph.pl out.perf-folded> graph.svg
>从火焰图中识别最昂贵的功能并对其进行优化