【问题标题】:How to profile time spent in memory access in C/C++ applications?如何分析 C/C++ 应用程序中内存访问所花费的时间?
【发布时间】:2017-03-29 02:20:18
【问题描述】:

一个函数在应用程序中花费的总时间可以大致分为两个部分:

  1. 实际计算所花费的时间 (Tcomp)
  2. 花在内存访问上的时间 (Tmem)

通常,分析器提供函数所花费总时间的估计值。是否可以根据上述两个组件(Tcomp 和 Tmem)估算所花费的时间?

【问题讨论】:

  • 有一个非常简单的方法可以回答这个问题。只需执行random pausing 并查看内存管理中的样本比例。 Here's an example.。一般来说,在应届毕业生编写的大型软件中,花费在内存管理上的时间比例往往为 50-99%。好消息是 2-100 的加速因子只等待重构。
  • Mike,你好,这不是关于内存管理(malloc/free/new/delete),而是关于 CPU 的有效使用。随机暂停并不能帮助我找到哪些代码量受内存延迟限制,哪些不受内存限制并且以全 ALU 速度运行。对于某些任务,我如何在 roofline 模型 (en.wikipedia.org/wiki/Roofline_model - crd.lbl.gov/departments/computer-science/PAR/research/roofline) 中获得要点:它使用 30 GFLOPS 和 15 GBytes/s 的内存层次请求,5 GBytes/s 是由主 RAM 提供服务; ram的util%是15%,ALU的util%是30%,使用AVX2
  • 你可能想看看likwid

标签: c++ profiling perf intel-vtune callgrind


【解决方案1】:

Brendan Gregg 在他最近的博客文章CPU Utilization is Wrong 中建议使用每周期 PMC 指令。简而言之,如果 IPC

如果您的 IPC

如果您的 IPC > 1.0,您可能会受到指令限制。寻找方法 减少代码执行:消除不必要的工作,缓存 CPU 火焰图是一个很好的工具 调查。对于硬件调优,请尝试更快的时钟频率等 核心/超线程。

对于我的上述规则,我在 1.0 的 IPC 上进行拆分。我从哪里得到的 从?根据我之前在 PMC 的工作,我弥补了这一点。这是你的方式 可以获得为您的系统和运行时自定义的值:编写两个 虚拟工作负载,一种受 CPU 限制,一种受内存限制。措施 他们的 IPC,然后计算他们的中点。

以下是stress tool 及其 IPC 生成的虚拟工作负载的一些示例。
内存绑定测试,IPC 低 (0,02):

$ perf stat stress --vm 4 -t 3
stress: info: [4520] dispatching hogs: 0 cpu, 0 io, 4 vm, 0 hdd
stress: info: [4520] successful run completed in 3s

 Performance counter stats for 'stress --vm 4 -t 3':

      10767,074968      task-clock:u (msec)       #    3,560 CPUs utilized          
                 0      context-switches:u        #    0,000 K/sec                  
                 0      cpu-migrations:u          #    0,000 K/sec                  
         4 555 919      page-faults:u             #    0,423 M/sec                  
     4 290 929 426      cycles:u                  #    0,399 GHz                    
        67 779 143      instructions:u            #    0,02  insn per cycle         
        18 074 114      branches:u                #    1,679 M/sec                  
             5 398      branch-misses:u           #    0,03% of all branches        

       3,024851934 seconds time elapsed

CPU 绑定测试,IPC 高 (1,44):

$ perf stat stress --cpu 4 -t 3
stress: info: [4465] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
stress: info: [4465] successful run completed in 3s

 Performance counter stats for 'stress --cpu 4 -t 3':

      11419,683671      task-clock:u (msec)       #    3,805 CPUs utilized          
                 0      context-switches:u        #    0,000 K/sec                  
                 0      cpu-migrations:u          #    0,000 K/sec                  
               108      page-faults:u             #    0,009 K/sec                  
    30 562 187 954      cycles:u                  #    2,676 GHz                    
    43 995 290 836      instructions:u            #    1,44  insn per cycle         
    13 043 425 872      branches:u                # 1142,188 M/sec                  
        26 312 747      branch-misses:u           #    0,20% of all branches        

       3,001218526 seconds time elapsed

【讨论】:

  • 谢谢!你能添加一两个命令如何在 Linux 中获取 IPC(可能使用perf stat,或者使用 vtune?)。是否有任何命令变体可以定期打印 IPC 和/或 IPC 的系统范围平均值(在 perf man7.org/linux/man-pages/man1/perf-stat.1.html 的人中找不到周期性间隔以每 1 或 5 次打印一次 second like vmstat and iostat and sar -n DEV did;什么是顶尖的)?有内存限制/延迟限制程序及其 IPC 的实际示例吗?
  • 为什么 IPC 为 1 是 mem/cpu 之间的边界?我认为 IPC 是按 x86 指令计入 perf 的,但我们中的许多人都知道,在时钟周期内要解码的 3 或 4 条指令组中,首先可能会产生许多微操作(微操作),其他最多 1 个;并且 CPU 的广泛执行引擎可能会开始执行最多 6 或 8 微指令...嗯,定期打印是 pmcarch - github.com/brendangregg/pmc-cloud-tools/blob/master/pmcarch(仅限 Intel 上的 Linux);提示是tiptop.gforge.inria.fr
  • 我认为大矩阵乘法会受内存限制,因为必须从内存中读取大量数据。计算 pi 将受 CPU 限制,因为不需要从内存中读取大量数据。在测量 2 个虚拟工作负载后选择 IPC 为 1。它可以是您系统的另一个值,这取决于测量值。
  • ks1322, DGEMM - 矩阵乘法是 BLAS3 并且需要低内存带宽:有 O(N^2) 内存访问和 O(N^3) cpu 操作(更大的矩阵大小)。 BLAS3 在 crd.lbl.gov/departments/computer-science/PAR/research/roofline 中以算术强度标度标记为密集线性代数组 ~ 每内存字节数十个 fpu op;还要检查spiral.ece.cmu.edu:8080/pub-spiral/pubfile/ispass-2013_177.pdf
【解决方案2】:

如果您正在寻找获取 CPU 周期的函数,那么 boost 将非常有帮助。 我使用 Boost Timer Utility 来计算系统调用的 CPU 周期。

另一方面,您可以将相同的功能放在完整的程序上以获得整体时间。

我希望这是您正在寻找的。 -维杰

【讨论】:

  • vijay,我不是在寻找以秒为单位的某些功能(在 C 和 C++ 应用程序中),而是寻找算术强度的方法 - 与内存请求量相比,完成了多少 ALU 指令指示。一些任务受内存带宽或内存延迟限制,其他受 ALU 限制。单一类型的测量(使用 Boost Timer 进行实时测量)将无济于事。应该使用硬件性能计数器 (PMC),问题是在 Intel/AMD CPU 上使用哪个 PMC。
  • @osgx:我评论了 OP 问题。
  • 迈克,你没有评论 OP 问题(这是关于 内存访问时间,而不是关于 内存管理的时间份额),你是不断告诉其他人(其中 400 万人)该做什么/该学什么。为什么您没有获得stackoverflow.com/help/badges/262/publicist 徽章,因为您始终将随机堆栈采样的唯一真正解决方案与描述中包含性能词的任何问题联系起来?
【解决方案3】:

算术强度的概念已由 Roofline 模型提出:https://crd.lbl.gov/departments/computer-science/PAR/research/roofline/。简单地说,它定义了每次内存访问执行的算术指令数。

计算算术强度通常是通过使用性能计数器来实现的。

【讨论】:

  • 谢谢曼努埃尔。这似乎比我想要理解和实现的更冷。我会给它一个详细的外观。根据更多阅读,我试图对应用程序受内存/计算限制进行定量估计。
  • 屋顶线模型已经完成了。我强烈建议阅读名为应用屋顶线模型的论文以了解实际细节:spiral.ece.cmu.edu:8080/pub-spiral/pubfile/ispass-2013_177.pdf
  • Manuel,您能否扩展论文中最有用的部分并将它们整合到您的答案中?
【解决方案4】:

这是不可能测量的(这样做没有任何意义),因为计算与当前处理器架构中的内存访问重叠。此外,访问内存通常被分解为更多步骤(访问内存、预取到各种缓存级别、实际读取到处理器寄存器)。

您可以使用 perf 及其硬件计数器(如果您的硬件支持)来测量各种缓存级别的缓存命中和未命中,以估计您的算法在硬件上的效率。

【讨论】:

  • 当您在正在运行的架构上优化应用程序的性能时,这可能没有意义。您是对的,因为缓存未命中/命中很有帮助,并且许多工具都提供了此信息。但是,恕我直言,当您需要独立于架构的应用程序配置文件时,这很有意义。当您在新兴架构上估计应用程序的性能时,这可能很有用。通过这种方式,您可以分别量化改进计算和内存访问的效果。换句话说,它将指出新架构的改进重点。
  • 为简单起见,我可以将内存访问时间视为实际计算中没有花费的时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-17
  • 2021-09-22
  • 1970-01-01
相关资源
最近更新 更多