c++优化2行关键代码

标签 c++ optimization

通过 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 的计算和后面的 if 语句占用了所有应用程序近 90% 的 CPU。

  • collisions_block初始化一次,类型为 int[100000]
  • config::是一个命名空间,变量包含全局配置
  • offsets初始化一次,类型为 uint8_t[1<<24]
  • 我正在运行 Centos7 Linux 3.10.0-327.13.1.el7.x86_64
  • 所有 CPU 都用于 usr没有iowait在 mpstat 输出中
  • 我正在使用 g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4) 和标记 -std=gnu++11 -Ofast -Wall 进行编译

有什么方法可以加快内循环?

最佳答案

我发现性能瓶颈是对数组 ++offsets[hash] 的无序访问.它消耗了大部分 CPU 时间 (75+%)。通过从 1<<24 减小数组的大小,我实现了 2.5 倍的速度提升。至 1<<21并尝试适当的 MASKS配置。

我将简要描述我是如何发现问题的

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

    }
  }
}
  1. 拆分关键的 2 行以分隔函数以便更好地分析(小心放置 __attribute__((noinline)) 以防止 gcc 内联新函数。如果内联它们将不会出现在调用堆栈中)
  2. -g -rdynamic编译代码gcc 标志
  3. 运行采样性能工具 perf record -p <pid> -F 200 -g --call-graph dwarf -- sleep 60
  4. 转换为 FlameGraph为了更好的可读性 perf script | ./stackcollapse-perf.pl > out.perf-folded && ./flamegraph.pl out.perf-folded > graph.svg
  5. 从火焰图中识别最昂贵的函数并对其进行优化

关于c++优化2行关键代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37881307/

相关文章:

mysql - 两列上的 MySQL 主键是否有助于查询第二列?

android - 如何为 Android NDK 中的特定文件设置优化级别?

java - 我从哪里开始优化 JVM?

c# - 如何将 ImageCodecInfo 转换为 byte[] 或 Stream

c++ - log4cxx 配置文件语法

c++ - Switch Case 和 For 循环 C++

c++ - 在 if 条件下对左右变化值的相等性检查是否有任何区别

c++ - 为什么zmq将多个消息打包到一个TCP帧中?

c++ - memcpy - BYTE 的 int 变量

mysql - 在 Varchar 上创建 MySQL 索引总是会产生 2 个索引?