首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用google perf工具

如何使用google perf工具
EN

Stack Overflow用户
提问于 2012-06-04 06:09:09
回答 2查看 26.8K关注 0票数 13

我刚开始使用谷歌性能工具(ubuntu中的google-perftoolslibgoogle-perftools4包),我发誓我用谷歌搜索了大约一天都没有找到答案!问题是,我无法通过CPU性能分析获得所有函数的结果。这是我的代码:

代码语言:javascript
复制
#include "gperftools/profiler.h"
#include <iostream>
#include <math.h>
using namespace std;
void bar()
{
        int a,b,c,d,j,k;
        a=0;
        int z=0;
        b = 1000;
        while(z < b)
        {
                while (a < b)
                {
                        d = sin(a);
                        c = cos(a);
                        j = tan(a);
                        k = tan(a);
                        k = d * c + j *k;
                        a++;
                }
                a = 0;
                z++;
        }
}
void foo()
{
        cout << "hey " << endl;
}

int main()
{
        ProfilerStart("/home/mohammad/gperf/dump.txt");

        int a = 1000;
        while(a--){foo();}
        bar();
        ProfilerFlush();
        ProfilerStop();
}

编译为g++ test.cc -lprofiler -o a.out

下面是我运行代码的方式:

代码语言:javascript
复制
CPUPROFILE=dump.txt ./a.out

我也尝试过这个:

代码语言:javascript
复制
CPUPROFILE_FREQUENCY=10000 LD_PRELOAD=/usr/local/lib/libprofiler.so.0.3.0 CPUPROFILE=dump.txt ./a.out

这是我从google-pprof --text a.out dump.txt得到的

代码语言:javascript
复制
Using local file ./a.out.
Using local file ./dump.txt.
Total: 22 samples
8  36.4%  36.4%        8  36.4% 00d8cb04
6  27.3%  63.6%        6  27.3% bar
3  13.6%  77.3%        3  13.6% __cos (inline)
2   9.1%  86.4%        2   9.1% 00d8cab4
1   4.5%  90.9%        1   4.5% 00d8cab6
1   4.5%  95.5%        1   4.5% 00d8cb06
1   4.5% 100.0%        1   4.5% __write_nocancel
0   0.0% 100.0%        3  13.6% __cos

但是没有关于foo函数的信息!

我的系统信息: ubuntu 12.04 g++ 4.6.3

这就是全部!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-06-02 02:28:28

TL;DR:foo太快太小了要获取性能分析事件,请再运行100次。频率设置有打字错误,pprof不会比CONFIG_HZ更频繁地采样(通常为250)。最好切换到更现代的Linux (tutorial from its authorswikipedia)。

长版本:

您的foo函数太短太简单了-只需调用两个函数即可。使用g++ test.cc -lprofiler -o test.s -S -g编译了测试,并使用c++filt程序过滤test.s以使c++名称可读:

代码语言:javascript
复制
foo():
.LFB972:
        .loc 1 27 0
        pushq   %rbp
        movq    %rsp, %rbp
        .loc 1 28 0
        movl    $.LC0, %esi
        movl    std::cout, %edi
        call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
        movl    std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&), %esi
        movq    %rax, %rdi
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
        .loc 1 29 0
        popq    %rbp
        ret
.LFE972:
        .size   foo(), .-foo()

因此,要在配置文件中查看它,您应该多次运行foo,将main中的int a = 1000;更改为更大的值,如10000或更好的100000 (正如我在测试中所做的那样)。

此外,您可以修复不正确的"CPUPROFILE_FREQUENC=10000“以更正CPUPROFILE_FREQUENCY (请注意Y)。我应该说10000对于CPUPROFILE_FREQUENCY来说太高了,因为它通常每秒只能生成1000到250个事件,这取决于内核配置CONFIG_HZ (大多数3.x内核有250个事件,请查看grep CONFIG_HZ= /boot/config*)。而pprof中CPUPROFILE_FREQUENCY的默认设置是100。

我在Ubuntu14.04上使用bash script测试了CPUPROFILE_FREQUENCY的不同值: 100000、10000、1000、250

代码语言:javascript
复制
for a in 100000 100000 10000 10000 1000 1000 300 300 250 250; do 
   echo -n "$a "; 
   CPUPROFILE_FREQUENCY=$a CPUPROFILE=dump$a.txt ./test >/dev/null;
done

并且结果是相同的120-140个事件和每个./test的运行时间大约0.5秒,所以来自google-perftools的cpuprofiler每秒处理的单线程事件数不能超过内核中设置的CONFIG_HZ (我有250个)。

代码语言:javascript
复制
100000 PROFILE: interrupts/evictions/bytes = 124/1/6584
100000 PROFILE: interrupts/evictions/bytes = 134/0/7864
10000 PROFILE: interrupts/evictions/bytes = 125/0/7488
10000 PROFILE: interrupts/evictions/bytes = 123/0/6960
1000 PROFILE: interrupts/evictions/bytes = 134/0/6264
1000 PROFILE: interrupts/evictions/bytes = 125/2/7272
300 PROFILE: interrupts/evictions/bytes = 137/2/7984
300 PROFILE: interrupts/evictions/bytes = 126/0/7216
250 PROFILE: interrupts/evictions/bytes = 123/3/6680
250 PROFILE: interrupts/evictions/bytes = 137/2/7352

对于原始的a=1000,foo和cout的函数运行得太快,无法在每次运行时获得任何分析事件(甚至250个事件/秒),因此您没有foo,也没有任何输入/输出函数。在少量运行中,__write_nocancel可能获得采样事件,然后将报告来自libstdc++的foo和I/O函数(不在最顶部的某个位置,因此使用pprofgoogle-pprof--text选项),自身事件计数为零,子事件计数为非零:

代码语言:javascript
复制
 ....
   1   0.9%  99.1%        1   0.9% __write_nocancel
 ....
   0   0.0% 100.0%        1   0.9% _IO_new_file_overflow
   0   0.0% 100.0%        1   0.9% _IO_new_file_write
   0   0.0% 100.0%        1   0.9% __GI__IO_putc
   0   0.0% 100.0%        1   0.9% foo
   0   0.0% 100.0%        1   0.9% new_do_write
   0   0.0% 100.0%        1   0.9% std::endl
   0   0.0% 100.0%        1   0.9% std::ostream::put

对于a=100000,foo仍然太短太快,无法获取自己的事件,但I/O函数获得了几个事件。这是我从冗长的--text输出中摘取的列表:

代码语言:javascript
复制
  34  24.6%  24.6%       34  24.6% __write_nocancel

   1   0.7%  95.7%       35  25.4% __GI__IO_fflush
   1   0.7%  96.4%        1   0.7% __GI__IO_putc
   1   0.7%  97.8%        2   1.4% std::operator<< 
   1   0.7%  98.6%       36  26.1% std::ostream::flush
   1   0.7%  99.3%        2   1.4% std::ostream::put
   0   0.0% 100.0%       34  24.6% _IO_new_file_sync
   0   0.0% 100.0%       34  24.6% _IO_new_file_write
   0   0.0% 100.0%       40  29.0% foo

   0   0.0% 100.0%       34  24.6% new_do_write

   0   0.0% 100.0%        2   1.4% std::endl

拥有零计数器的函数只能归功于pprof读取调用链的能力(如果不省略帧信息,它知道谁调用了获得样本的函数)。

我还可以推荐更现代、功能更强大的(软件和硬件事件,频率高达5 kHz或更高;用户空间和内核分析)和支持更好的分析器,即Linux分析器(tutorial from its authorswikipedia)。

这是来自a=10000perf的结果

代码语言:javascript
复制
$ perf record  ./test3  >/dev/null
 ... skip some perf's spam about inaccessibility of kernel symbols 
 ... note the 3 kHz frequency here VVVV
Lowering default frequency rate to 3250. 
Please consider tweaking /proc/sys/kernel/perf_event_max_sample_rate.
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.078 MB perf.data (~3386 samples) ]

要从perf.data输出文件查看文本报告,我将使用less (因为perf report默认情况下会启动交互式配置文件浏览器):

代码语言:javascript
复制
$ perf report |less
... skip some extra info about the machine, kernel, and perf starting command
# Samples: 1K of event 'cycles'
# Event count (approx.): 1155264208
# Overhead   Command   Shared Object          Symbol
    41.94%    test3  libm-2.19.so         [.] __tan_sse2                                                                                                                                                                    
    16.95%    test3  libm-2.19.so         [.] __sin_sse2    
    13.40%    test3  libm-2.19.so         [.] __cos_sse2                                                                                                                                                                    
     4.93%    test3  test3                [.] bar()                                                                                                                                                                         
     2.90%    test3  libc-2.19.so         [.] __GI___libc_write    
....
     0.20%    test3  test3                [.] foo()                                                                                                                                                                         

或使用perf report -n | less查看原始事件(示例)计数器:

代码语言:javascript
复制
# Overhead       Samples  Command        Shared Object 
    41.94%           663    test3  libm-2.19.so         [.] __tan_sse2                                                                                                                                                                    
    16.95%           268    test3  libm-2.19.so         [.] __sin_sse2   
    13.40%           212    test3  libm-2.19.so         [.] __cos_sse2                                                                                                                                                                    
     4.93%            78    test3  test3                [.] bar()                                                                                                                                                                         
     2.90%            62    test3  libc-2.19.so         [.] __GI___libc_write     
 ....
     0.20%             4    test3  test3                [.] foo()                                                                                                                                                                         
票数 13
EN

Stack Overflow用户

发布于 2013-05-15 01:31:55

尝试将LD_PRELOAD设置为

LD_PRELOAD=/usr/local/lib/libprofiler.so

当传递一个不以.so后缀结尾的共享库时,它会发生looks like there are problems

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10874308

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档