【问题标题】:C++ function: Number of memory accessC++ 函数:内存访问次数
【发布时间】:2014-01-15 13:07:49
【问题描述】:

我想找出由于某个功能而导致的内存访问次数。为此,我正在使用 pintool。在 pintool 中,我使用了 pinatrace,但它会生成一个巨大的文件(文件大小 > 534 MB),其中包含整个程序的所有读写操作。但我想为一个特定的功能找到它。我仍然没有找到任何这样做的例子。请在这方面帮助我或提供任何有用的链接。

P.S : 我正在 Linux 上编译我的 c++ 程序。

【问题讨论】:

  • 我不熟悉 pintool 的输出格式,但我几乎可以肯定您可以提供一些开关,从而产生可以使用 grep、awk 等标准工具解析的输出。如果您给我们一个示例输出,它可能会有所帮助。
  • 使用 nm(1) 获取函数的起始地址。也许反汇编函数以获得它的大小。
  • @brianbeuning 你能详细说明一下吗?在哪里使用 nm(1)?

标签: c++ memory memory-management profiling


【解决方案1】:

Cachegrind,它是 Valgrind 的一部分,测量(或者更确切地说,模拟)缓存访问次数以及缓存未命中(即访问实际 RAM)。查找概览here

它可以在this format 中逐行输出您的代码的注释版本,以及缓存访问次数和缓存未命中次数。

Valgrind 包含在流行操作系统的包管理器中,并且易于安装。

这是一个例子:

#include <random>
#include <vector>

int main()
{
  std::vector<int> vec;

  // Seed with a real random value, if available
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> dist(1,10000);

  for (std::size_t i = 0 ; i < 1000 ; ++i)
    vec.push_back(dist(eng));

  for (auto &num : vec)
    num *= 3;

  return 0;
}
  1. 编译(确保使用 -g 选项)

    g++ -std=c++11 -W -Wall -g -o test test.cpp
    
  2. 在 cachegrind 模式下运行 valgrind

    valgrind --tool=cachegrind ./test
    
  3. 运行 cg_annotate 工具:

    cg_annotate ./cachegrind.out.2543 /absolute/path/test.cpp
    

这会产生:

==2438== Cachegrind, a cache and branch-prediction profiler
==2438== Copyright (C) 2002-2012, and GNU GPL'd, by Nicholas Nethercote et al.
==2438== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2438== Command: ./test
==2438== 
--2438-- warning: L3 cache found, using its data for the L2 simulation.
==2438== 
==2438== I   refs:      1,686,675
==2438== I1  misses:        1,160
==2438== LLi misses:        1,095
==2438== I1  miss rate:      0.06%
==2438== LLi miss rate:      0.06%
==2438== 
==2438== D   refs:        676,987  (458,995 rd   + 217,992 wr)
==2438== D1  misses:       12,616  ( 11,023 rd   +   1,593 wr)
==2438== LLd misses:        6,338  (  5,272 rd   +   1,066 wr)
==2438== D1  miss rate:       1.8% (    2.4%     +     0.7%  )
==2438== LLd miss rate:       0.9% (    1.1%     +     0.4%  )
==2438== 
==2438== LL refs:          13,776  ( 12,183 rd   +   1,593 wr)
==2438== LL misses:         7,433  (  6,367 rd   +   1,066 wr)
==2438== LL miss rate:        0.3% (    0.2%     +     0.4%  )

注意 1:Cachegrind 模拟缓存行为,因此其输出可能并不完全准确。特别是,模拟仅考虑您正在分析的过程;它忽略操作系统/内核活动和其他进程。

注意 2:Cachegrind 也可能会生成一个大的中间文件。因此,如果您的问题是空间要求,Cachegrind 可能不是一个好的解决方案。但是,如果您的问题仅仅是输出的格式和可读性,它会有所帮助,因为 cg_annotate 会生成易于阅读的输出。

【讨论】:

  • 我在编译和链接时使用了 cachegrind 和 -g,但仍然是我感兴趣的函数,它的统计信息不存在。甚至那个函数名也不存在。
  • 函数可能是内联的。在这种情况下,您仍然会得到函数内部调用的注释。
【解决方案2】:

pinatrace 只是一个示例,用于使用 mem 操作数跟踪每条指令。 当它调用时(例如) -

// Print a memory read record
VOID RecordMemRead(VOID * ip, VOID * addr)
{
    fprintf(trace,"%p: R %p\n", ip, addr);
}

它传递了一个IARG_INST_PTR,它是捕获指令的IP(指令指针)。如果您知道函数所在的虚拟地址的范围,您可以在里面添加一个检查并返回,如果您不在该范围内,则不打印任何内容。

【讨论】:

  • 有没有其他简单的方法来实现这个目标(在我的问题中提到)?
  • 取决于你在二进制文件中究竟有什么——如果你没有调试信息,那么识别这个函数的唯一方法就是使用它的地址
猜你喜欢
  • 1970-01-01
  • 2023-01-17
  • 2018-01-11
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 2016-12-23
  • 2011-02-01
相关资源
最近更新 更多