如何将每个调用分配给一个函数?
我想以非标准的方式来分析我的执行情况。使用gprof,Valgrind,Oprofile ...对于给定的函数,我只能得到其执行时间的平均值。我想要的是获得这个执行时间的标准偏差。如何将每个调用分配给一个函数?
实施例:
void a()
sleep (rand() % 10 + 10)
void b()
sleep (rand() % 14 + 2)
main
for (1 .. 100)
a()
b()
用标准工具,一个和b功能将有类似的行为。你知道有什么工具可以给我这个结果,还有一个自动的方法。
我已经用TAU进行了测试,但是到现在为止,它并没有真正的相关性。我认为这样有一个解决方案,但我对TAU不够信心。如果有人是Tau专家,我会尽量保留所有的功能执行时间,并在最后进行数学运算。但我不知道如何在Tau中指定它。
我想剖析C/C++代码,但是如果您在其他编程语言中有任何领先地位,我是开放的。
我认为苹果的鲨鱼剖析工具可以生成每个函数的均值。当然,这只能帮助你在Mac上。
分析工具并不神奇,您可以在几行内为任何目的推出自己的产品。
事情是这样的,也许:
// 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
其实OProfile的可以分析从呼叫图形视图,这意味着用不同的来电者一样调用例程的功能将在不同的被异形统计。
尝试报告的opreport命令。
也许不适用,因为它是gcc特有的,但我发现这至少为我节省了一些 次。如果使用“-finstrument-functions”标志编译代码,则模块中使用此标志编译的函数的每个入口和出口点都将与对仪器函数的调用进行桩工。所有你需要做的是有一个内联读取一些高精度的计数器(例如,x86上的rdtsc,尽管见this discussion)和大量的记录:[func_addr,is_enter,timer_value],你会不断地在仪器功能。退出时,将该数组转储到文件并进行离线分析。
与“自动化”方法相距甚远,您可能正在寻找 - 但希望这有用。下面的示例显示了使用-finstrument-functions编译的gcc的行为。如果你不包括国旗,它将“正常”工作。
#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);
}
它是否必须是自动的?只需写一些宏,并在表格中写下结果,然后就可以计算出你想要的结果。 – Makis 2009-07-03 12:19:22