如何分析每个函数的调用?

时间:2009-07-03 11:47:38

标签: c++ c profiling

我想以非标准方式描述我的执行情况。对于给定的函数,使用 gprof Valgrind Oprofile ...,我只得到其执行时间的平均值。我想要的是获得这个执行时间的标准偏差。

示例:

void a()
  sleep ( rand() % 10 + 10 )

void b()
  sleep ( rand() % 14 + 2 )

main
  for (1 .. 100)
    a()
    b()

使用标准工具, a b 功能将具有类似的行为。你知道任何可以通过自动方法给我这个结果的工具。

我已经使用 TAU 进行了测试,但直到现在,它并没有真正相关。我认为这样有一个解决方案,但我对TAU没有足够的信心。如果有人是Tau专家,我会尝试保留所有函数执行时间,并在最后进行数学计算。但我不知道如何在Tau中指定它。

我想描述一下C / C ++代码,但如果你有其他编程语言的领导,我就是开放的。

4 个答案:

答案 0 :(得分:3)

分析工具不是魔术,你可以在几行中为自己的目的滚动自己。

这样的事情,也许是:

// code profile.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

class cProfile
{
public:
    // construct profiler for a particular scope
    // call at begining of scope to be timed
    // pass unique name of scope
    cProfile( const char* name )
    {
        myName = string( name );
        QueryPerformanceCounter( (LARGE_INTEGER *)&myTimeStart );
    }
    // destructor - automatically called when scope ends
    ~cProfile();

    // constructor - produces report when called without parameters
    cProfile();


private:
    typedef accumulator_set<__int64, stats<tag::variance(lazy)> > acc_t;
    static map < string, acc_t > myMap;
    string myName;
    __int64 myTimeStart;
};
map < string, accumulator_set<__int64, stats<tag::variance(lazy)> > > cProfile::myMap;


cProfile::~cProfile()
{
    __int64 t=0;
    QueryPerformanceCounter( (LARGE_INTEGER *)&t );
    t -= myTimeStart;


    map < string, acc_t >::iterator p = myMap.find( myName );
    if( p == myMap.end() ) {
        // this is the first time this scope has run
        acc_t acc;
        pair<string,acc_t > pr(myName,acc);
        p = myMap.insert( pr ).first;
    }
    // add the time of running to the accumulator for this scope
    (p->second)( t );

}
// Generate profile report
cProfile::cProfile()
{
    __int64 f;
    QueryPerformanceFrequency( (LARGE_INTEGER *)&f );

    printf("%20s Calls\tMean (secs)\tStdDev\n","Scope");
    for( map < string, accumulator_set<__int64, stats<tag::variance(lazy)> > >::iterator p = myMap.begin();
        p != myMap.end(); p++ )
    {
        float av = mean(p->second) / f;
        float stdev = sqrt( ((double) variance(p->second))  ) / f;
        printf("%20s %d\t%f\t%f\n",p->first.c_str(),
            boost::accumulators::count(p->second), av, stdev);
    }
}
void a()
{
    cProfile profile("a"); 

    Sleep ( rand() % 10 + 10 );
}
void b()
{
    cProfile profile("b");

    Sleep ( rand() % 20 + 5 );
}


int _tmain(int argc, _TCHAR* argv[])
{
    for (int k=1;k<=100;k++) {
        a();
        b();
    }

    cProfile profile_report;

    return 0;
}

哪个产生

       Scope Calls      Mean (secs)     StdDev
           a 100        0.014928        0.002827
           b 100        0.015254        0.005671

答案 1 :(得分:2)

也许不适用,因为它是特定于gcc的,但我发现这可以节省我几个 至少时代。如果使用“ - finstrument-functions”标志编译代码,那么使用此标志编译的模块中函数的每个入口和出口点都将与调用仪器函数一起存根。所有你需要做的就是有一个内联,它会读取一些高精度计数器(例如x86上的rdtsc,虽然看this discussion)和一大堆记录:[func_addr,is_enter,timer_value]你可以不断写入仪器功能。退出后,将此数组转储到文件并离线分析。

远离“自动化”方法,您可能正在寻找 - 但希望这是有用的。下面的示例显示了gcc的行为,如果它是使用-finstrument-functions编译的。如果您不包含该标志,它将“正常”工作。

#include <stdio.h>
#include <stdlib.h>

void __cyg_profile_func_enter(void *fn, void *call)
    __attribute__ ((no_instrument_function));
void __cyg_profile_func_exit(void *fn, void *call)
    __attribute__ ((no_instrument_function));

void __cyg_profile_func_enter(void *fn, void *call) {
  printf("Enter %x,%x\n",fn,call);
}
void __cyg_profile_func_exit(void *fn, void *call) {
  printf("Exit %x,%x\n",fn,call);
}

int foo(int i) {
  printf("inside foo\n");
}

int main(int argc, char *argv[]) {
  printf("inside main 1\n");
  foo(123);
  printf("inside main 2\n");
  exit(0);
}

答案 2 :(得分:0)

我认为Apple的Shark分析工具可以为每个函数生成均值。当然,这只能帮助你在Mac上。

答案 3 :(得分:0)

实际上,Oprofile可以从调用图表视图中分析函数,这意味着具有不同调用者的同一被调用者例程将在不同的统计信息中进行分析。

为报告尝试opreport命令。