gprof没有输出结果

9

我正在尝试使用gprof来对我开发的一些数值代码进行性能分析,但是gprof似乎无法从我的程序中收集数据。这是我的命令行:

g++ -Wall -O3 -g -pg -o fftw_test fftw_test.cpp -lfftw3 -lfftw3_threads -lm && ./fftw_test
文件已经生成,但是似乎没有数据。当我运行时
gprof -b fftw_test gmon.out > gprof.out

我所得到的只有

Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  Ts/call  Ts/call  name    


                        Call graph


granularity: each sample hit covers 2 byte(s) no time propagated

index % time    self  children    called     name


Index by function name

有什么见解吗?

这段代码做了很多事情,它不仅仅是调用FFTW例程。它有计算某些复杂系数的函数,将输入数据乘以这些系数的函数等等。

编辑:包括示例代码和结果。

#include <cstdlib>
#include <ctime>

int main()
{
   std::srand( std::time( 0 ) );

   double sum = 0.0;

   for ( int i = 0; i < RAND_MAX; ++i )
      sum += std::rand() / ( double ) RAND_MAX;

   std::cout << sum << '\n';

   return 0;
}

命令行:

$ g++ -Wall -O3 -g -pg -o gprof_test gprof_test.cpp && ./gprof_test
1.07374e+09
$ gprof -b gprof_test gmon.out > gprof.out
$ cat gprof.out

结果:

Flat profile:

Each sample counts as 0.01 seconds.
 no time accumulated

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  Ts/call  Ts/call  name    


                        Call graph


granularity: each sample hit covers 2 byte(s) no time propagated

index % time    self  children    called     name


Index by function name

这就是全部了。


1
不进行任何互动?好吧,我尝试了Linux上的性能工具,它们似乎做得很好,但解释输出并不是一件简单的事情。我想出了自己的“穷人分析器”类来帮助我完成这项工作,并最终成功将计算时间大大减少。 - Elias
Elias,这很奇怪。Mike https://stackoverflow.com/users/23771/mike-dunlavey 通常在标记为[profiling]的几乎每个问题中都会推荐他未被专利保护的统计证明的5个随机回溯gdb贫民剖析。你的gprof可能有问题,操作系统是什么?你能否创建(或在fftw lib示例中找到)一个更简单的程序变体,它将填充一些数据并调用fftw,但仍带有空的gprof报告,以便我们测试您的情况? - osgx
1
我在一个简单的主程序中遇到了同样的问题。gcc 7.2.0和gprof 2.29.1在Archlinux上使用。就好像有什么不兼容的东西。 - Isaac Pascual
@IsaacPascual,你能在网上发布一下带有问题的程序示例吗?你的程序是否使用了大量的fftw计算,还是只是太短了? - osgx
你的程序将会在std::rand函数中占据 100% 减 epsilon 的时间,这个函数没有被使用 -g 编译,是吗?所以实质上在你的代码中不会发生任何采样。 - Mike Dunlavey
3个回答

8
如果您正在使用gcc 6,最有可能遇到this bug(请注意,该bug不仅限于Debian,而是取决于gcc的构建方式)。一个解决方法是使用`-no-pie`选项进行编译,这将禁用位置无关代码生成。
如果您想了解更多有关PIE的信息,这里是一个很好的开始。

1
我猜想问题出在你使用了O3优化级别。在gcc-8.4.0中,使用O3时什么也没有输出,在O2下只有少量数据(例如缺少函数调用次数) ,在O1O0下则有适当的配置文件。
这似乎是旧版本gcc的已知问题,然而我没有找到任何关于后期版本存在此类问题的来源。我只能假设这是编译器的错误或更激进的优化阻止了某些性能数据的收集。

0

gprof seems to fail to collect data from my program. Here is my command line:

g++ -Wall -O3 -g -pg -o fftw_test fftw_test.cpp -lfftw3 -lfftw3_threads -lm && ./fftw_test

你的程序使用了fftw库,可能几乎全部都是fftw库调用。运行时间是多少?你的程序可能太快了,无法使用gprof进行分析。

更新:库可能无法被gprof看到,因为它是在没有启用gprof分析的情况下编译的。

GNU gprof有两个部分。首先,它会在使用-pg选项(带有mcount函数调用-https://en.wikipedia.org/wiki/Gprof)编译的c/cpp文件中插入函数调用记录,以获取调用者/被调用者信息。其次,它会将额外的分析库链接到可执行文件中,以添加定期采样来查找哪些代码执行时间更长。采样是通过profil(setitimer)完成的。Setitimer分析具有有限的分辨率,无法解决小于10毫秒或1毫秒(每秒100或1000个样本)的间隔。

在你的例子中,fftw库可能是没有插装的,因此其中没有mcount调用。它仍然可以被采样部分捕获,但只能针对程序的主线程(https://en.wikipedia.org/wiki/Gprof -“通常只分析应用程序的主线程”)。

perf分析器没有使用mcount进行仪器化(当使用-g选项记录时,它从堆栈展开中获取被调用者/调用者),但它具有更好的统计/采样变量(它可以使用硬件PMU计数器),没有100或1000 Hz的限制,并且正确支持(分析)线程。尝试perf record -F1000 ./fftw_test(使用1 kHz采样频率),然后使用perf reportperf report > report.txt。还有一些GUI / HTML前端可用于perf:https://github.com/KDAB/hotspot https://github.com/jrfonseca/gprof2dot

对于更好的setitimer风格的分析器,请查看google-perftools https://github.com/gperftools/gperftools中的“CPU PROFILER”。

======

通过您的测试,我在Debian 8.6 Linux内核版本3.16.0-4-amd64 x86_64机器上使用g++(Debian 4.9.2-10)获得了一些gprof结果,gprof是“GNU gprof(Debian GNU Binutils)2.27”

$ cat gprof_test.cpp
#include <cstdlib>
#include <ctime>
#include <iostream>
int main()
{
   std::srand( std::time( 0 ) );
   double sum = 0.0;
   for ( int i = 0; i < 100000000; ++i )
      sum += std::rand() / ( double ) RAND_MAX;
   std::cout << sum << '\n';
   return 0;
}
$ g++ -Wall -O3 -g -pg -o gprof_test gprof_test.cpp && time ./gprof_test
5.00069e+06
real    0m0.992s
$ gprof -b gprof_test gmon.out
Flat profile:

Each sample counts as 0.01 seconds.
 no time accumulated

  %   cumulative   self              self     total
 time   seconds   seconds    calls  Ts/call  Ts/call  name
  0.00      0.00     0.00        1     0.00     0.00  _GLOBAL__sub_I_main

所以,在这个1秒的示例中,gprof没有捕获任何时间样本,并且没有关于调用库的信息(它们是在没有使用-pg编译的情况下编译的)。添加一些包装函数并禁止内联优化后,我从gprof获得了一些数据,但库时间没有被计算在内(它看到了2秒运行时间中的0.72秒):

$ cat *cpp
#include <cstdlib>
#include <ctime>
#include <iostream>

int rand_wrapper1()
{
  return std::rand();
}
int rand_scale1()
{
  return rand_wrapper1() / ( double ) RAND_MAX;
}
int main()
{
   std::srand( std::time( 0 ) );
   double sum = 0.0;
   for ( int i = 0; i < 100000000; ++i )
    sum+= rand_scale1();
//      sum += std::rand() / ( double ) RAND_MAX;
   std::cout << sum << '\n';
   return 0;
}
$ g++ -Wall -O3 -fno-inline -g -pg -o gprof_test gprof_test.cpp && time ./gprof_test
real    0m2.345s
$ gprof -b gprof_test gmon.out
Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ns/call  ns/call  name
 80.02      0.57     0.57                             rand_scale1()
 19.29      0.71     0.14 100000000     1.37     1.37  rand_wrapper1()
  2.14      0.72     0.02                             frame_dummy
  0.00      0.72     0.00        1     0.00     0.00  _GLOBAL__sub_I__Z13rand_wrapper1v
  0.00      0.72     0.00        1     0.00     0.00  __static_initialization_and_destruction_0(int, int) [clone .constprop.0]


                        Call graph


granularity: each sample hit covers 2 byte(s) for 1.39% of 0.72 seconds

index % time    self  children    called     name
                                                 <spontaneous>
[1]     97.9    0.57    0.14                 rand_scale1() [1]
                0.14    0.00 100000000/100000000     rand_wrapper1() [2]
-----------------------------------------------
                0.14    0.00 100000000/100000000     rand_scale1() [1]
[2]     19.0    0.14    0.00 100000000         rand_wrapper1() [2]

而且perf可以看到所有的部分:

$ perf record ./gprof_test
0
[ perf record: Woken up 2 times to write data ]
[ perf record: Captured and wrote 0.388 MB perf.data (~16954 samples) ]
$ perf report |more   
# Samples: 9K of event 'cycles'
# Event count (approx.): 7373484231
#
# Overhead     Command      Shared Object                     Symbol
# ........  ..........  .................  .........................
#
    25.91%  gprof_test  gprof_test         [.] rand_scale1()
    21.65%  gprof_test  libc-2.19.so       [.] __mcount_internal
    13.88%  gprof_test  libc-2.19.so       [.] _mcount
    12.54%  gprof_test  gprof_test         [.] main
     9.35%  gprof_test  libc-2.19.so       [.] __random_r
     8.40%  gprof_test  libc-2.19.so       [.] __random
     3.97%  gprof_test  gprof_test         [.] rand_wrapper1()
     2.79%  gprof_test  libc-2.19.so       [.] rand
     1.41%  gprof_test  gprof_test         [.] mcount@plt
     0.03%  gprof_test  [kernel.kallsyms]  [k] memset

这不是它。我使用一个运行大循环的程序也有相同的行为。 - Elias
Elias,你能否在线发布带有问题的程序示例(包括构建说明)? - osgx
我已经编辑了问题。如果您有任何特定的代码示例想让我运行,我很乐意这样做。 - Elias
Elias,谢谢,我会在几天内测试代码。你能否给一些有关你的平台的提示,它是linux还是BSD或者macos,以及操作系统的版本(比如 uname -a输出,真实主机名被删除)? g++和gprof版本? - osgx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接