轻松测量经过的时间

我试图使用时间()来测量我的程序的各个点。

我不明白的是为什么前后的值是一样的?我知道这不是分析我的程序的最佳方式,我只是想看看需要多长时间。

printf("**MyProgram::before time= %ld\n", time(NULL));


doSomthing();
doSomthingLong();


printf("**MyProgram::after time= %ld\n", time(NULL));

我试过:

struct timeval diff, startTV, endTV;


gettimeofday(&startTV, NULL);


doSomething();
doSomethingLong();


gettimeofday(&endTV, NULL);


timersub(&endTV, &startTV, &diff);


printf("**time taken = %ld %ld\n", diff.tv_sec, diff.tv_usec);

如何读取**time taken = 0 26339的结果?这是否意味着26339纳秒= 26.3毫秒?

**time taken = 4 45025呢,这意味着4秒25毫秒吗?

669849 次浏览

the time(NULL)函数将返回从1970年1月1日00:00开始经过的秒数。因为这个函数在程序中不同的时间被调用,所以它总是不同的 c++中的时间 < / p >

在内部,该函数将访问系统的时钟,这就是为什么每次调用它时它都会返回不同的值。一般来说,使用非函数式语言,函数中可能有许多副作用和隐藏状态,仅通过查看函数名和参数是看不到的。

time(NULL)返回自01/01/1970年00:00时经过的秒数(的时代)。所以这两个值之间的差就是处理所花费的秒数。

int t0 = time(NULL);
doSomthing();
doSomthingLong();
int t1 = time(NULL);


printf ("time = %d secs\n", t1 - t0);

使用getttimeofday()可以得到更好的结果,它返回以秒为单位的当前时间,就像time()一样,也以微秒为单位。

仅Windows平台: (Linux标签是在我张贴这个答案后添加的)

您可以使用GetTickCount ()来获取自系统启动以来经过的毫秒数。

long int before = GetTickCount();


// Perform time-consuming operation


long int after = GetTickCount();

它们是一样的,因为doSomething函数发生得比计时器的粒度快。试一试:

printf ("**MyProgram::before time= %ld\n", time(NULL));


for(i = 0; i < 1000; ++i) {
doSomthing();
doSomthingLong();
}


printf ("**MyProgram::after time= %ld\n", time(NULL));

time(NULL)函数调用将返回自epoc: 1970年1月1日以来经过的秒数。也许你要做的是取两个时间戳的差值:

size_t start = time(NULL);
doSomthing();
doSomthingLong();


printf ("**MyProgram::time elapsed= %lds\n", time(NULL) - start);
#include <ctime>


void f() {
using namespace std;
clock_t begin = clock();


code_to_time();


clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
}

time()函数只精确到一秒内,但是一秒内有CLOCKS_PER_SEC“时钟”。这是一种简单、便携的测量方法,尽管它过于简化了。

这两个值相同的原因是因为你的长过程不需要那么长时间-不到一秒。你可以试着添加一个长循环(for (int i = 0;我& lt;100000000;i++);)在函数的末尾确保这是问题所在,然后我们可以从那里…

如果上面的情况是正确的,你将需要找到一个不同的系统函数(我知道你在linux上工作,所以我不能帮助你知道函数名称)来更准确地测量时间。我相信在linux中有一个类似于GetTickCount()的函数,你只需要找到它。

第二个程序打印的值是秒和微秒。

0 26339 = 0.026'339 s =   26339 µs
4 45025 = 4.045'025 s = 4045025 µs

正如我从你的问题中看到的,看起来你想知道执行某段代码后所花费的时间。我猜你会很乐意在几秒钟内看到结果。如果是,尝试使用difftime()函数,如下所示。希望这能解决你的问题。

#include <time.h>
#include <stdio.h>


time_t start,end;
time (&start);
.
.
.
<your code>
.
.
.
time (&end);
double dif = difftime (end,start);
printf ("Elasped time is %.2lf seconds.", dif );
#include<time.h> // for clock
#include<math.h> // for fmod
#include<cstdlib> //for system
#include <stdio.h> //for delay


using namespace std;


int main()
{




clock_t t1,t2;


t1=clock(); // first time capture


// Now your time spanning loop or code goes here
// i am first trying to display time elapsed every time loop runs


int ddays=0; // d prefix is just to say that this variable will be used for display
int dhh=0;
int dmm=0;
int dss=0;


int loopcount = 1000 ; // just for demo your loop will be different of course


for(float count=1;count<loopcount;count++)
{


t2=clock(); // we get the time now


float difference= (((float)t2)-((float)t1)); // gives the time elapsed since t1 in milliseconds


// now get the time elapsed in seconds


float seconds = difference/1000; // float value of seconds
if (seconds<(60*60*24)) // a day is not over
{
dss = fmod(seconds,60); // the remainder is seconds to be displayed
float minutes= seconds/60;  // the total minutes in float
dmm= fmod(minutes,60);  // the remainder are minutes to be displayed
float hours= minutes/60; // the total hours in float
dhh= hours;  // the hours to be displayed
ddays=0;
}
else // we have reached the counting of days
{
float days = seconds/(24*60*60);
ddays = (int)(days);
float minutes= seconds/60;  // the total minutes in float
dmm= fmod(minutes,60);  // the rmainder are minutes to be displayed
float hours= minutes/60; // the total hours in float
dhh= fmod (hours,24);  // the hours to be displayed


}


cout<<"Count Is : "<<count<<"Time Elapsed : "<<ddays<<" Days "<<dhh<<" hrs "<<dmm<<" mins "<<dss<<" secs";




// the actual working code here,I have just put a delay function
delay(1000);
system("cls");


} // end for loop


}// end of main

0 -

使用delta函数计算时间差:

auto start = std::chrono::steady_clock::now();
std::cout << "Elapsed(ms)=" << since(start).count() << std::endl;

since接受任何时间点并产生任何持续时间(毫秒为默认值)。它的定义为:

template <
class result_t   = std::chrono::milliseconds,
class clock_t    = std::chrono::steady_clock,
class duration_t = std::chrono::milliseconds
>
auto since(std::chrono::time_point<clock_t, duration_t> const& start)
{
return std::chrono::duration_cast<result_t>(clock_t::now() - start);
}

Demo

1 -定时器

使用基于std::chrono的定时器:

Timer clock; // Timer<milliseconds, steady_clock>


clock.tick();
/* code you want to measure */
clock.tock();


cout << "Run time = " << clock.duration().count() << " ms\n";

Demo

Timer被定义为:

template <class DT = std::chrono::milliseconds,
class ClockT = std::chrono::steady_clock>
class Timer
{
using timep_t = typename ClockT::time_point;
timep_t _start = ClockT::now(), _end = {};


public:
void tick() {
_end = timep_t{};
_start = ClockT::now();
}
    

void tock() { _end = ClockT::now(); }
    

template <class T = DT>
auto duration() const {
gsl_Expects(_end != timep_t{} && "toc before reporting");
return std::chrono::duration_cast<T>(_end - _start);
}
};

正如霍华德Hinnant指出的那样,我们使用duration来保持在chrono类型系统中,并执行诸如求平均或比较之类的操作(例如,这里这意味着使用std::chrono::milliseconds)。当我们只是执行IO时,我们使用持续时间的count()或tick(例如这里的毫秒数)。

2 -仪器仪表

任何可调用对象(函数、函数对象、lambda等)都可以用于基准测试。假设你有一个函数F可调用,参数为arg1,arg2,此技术将导致:

cout << "F runtime=" << measure<>::duration(F, arg1, arg2).count() << "ms";

Demo

measure被定义为:

template <class TimeT  = std::chrono::milliseconds
class ClockT = std::chrono::steady_clock>
struct measure
{
template<class F, class ...Args>
static auto duration(F&& func, Args&&... args)
{
auto start = ClockT::now();
std::invoke(std::forward<F>(func), std::forward<Args>(args)...);
return std::chrono::duration_cast<TimeT>(ClockT::now()-start);
}
};

正如在(1)中提到的,使用w/o .count()的持续时间对于那些希望在I/ o之前对一堆持续时间进行后处理的客户端是最有用的,例如average:

auto avg = (measure<>::duration(func) + measure<>::duration(func)) / 2;
std::cout << "Average run time " << avg.count() << " ms\n";

+是为什么被转发的函数调用。

+完整的代码可以找到here

+我试图建立一个基准测试框架基于chrono被记录这里

+Old demo

//***C++11 Style:***
#include <chrono>


std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();


std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl;
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds> (end - begin).count() << "[ns]" << std::endl;

从所看到的内容来看,tv_sec存储所经过的秒数,而tv_usec单独存储所经过的微秒数。它们不是彼此的转换。因此,必须将它们更改为适当的单位,并添加它们以获得所消耗的总时间。

struct timeval startTV, endTV;


gettimeofday(&startTV, NULL);


doSomething();
doSomethingLong();


gettimeofday(&endTV, NULL);


printf("**time taken in microseconds = %ld\n",
(endTV.tv_sec * 1e6 + endTV.tv_usec - (startTV.tv_sec * 1e6 + startTV.tv_usec))
);

在OP的三个具体的问题。的答案

“我不明白的是,为什么之前和之后的数值是一样的?

第一个问题和示例代码显示time()的分辨率为1秒,因此答案必须是两个函数在1秒内执行。偶尔会(显然是不合逻辑的)通知1秒如果两个计时器标记跨越了一秒的边界。

下一个例子使用gettimeofday()填充这个结构体

struct timeval {
time_t      tv_sec;     /* seconds */
suseconds_t tv_usec;    /* microseconds */
};

第二个问题问:“如何读取**time taken = 0 26339的结果?”这是否意味着26339纳秒= 26.3毫秒?”

我的第二个答案是所花费的时间是0秒和26339微秒,即0.026339秒,这证实了第一个示例在不到1秒的时间内执行。

第三个问题问:**time taken = 4 45025呢,这是否意味着4秒25毫秒?”

我的第三个答案是所用的时间是4秒和45025微秒,即4.045025秒,这表明OP改变了他之前计时的两个函数执行的任务。

在linux上,clock_gettime()是一个很好的选择。 您必须链接实时库(-lrt)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>


#define BILLION  1000000000L;


int main( int argc, char **argv )
{
struct timespec start, stop;
double accum;


if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) {
perror( "clock gettime" );
exit( EXIT_FAILURE );
}


system( argv[1] );


if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) {
perror( "clock gettime" );
exit( EXIT_FAILURE );
}


accum = ( stop.tv_sec - start.tv_sec )
+ ( stop.tv_nsec - start.tv_nsec )
/ BILLION;
printf( "%lf\n", accum );
return( EXIT_SUCCESS );
}

我通常使用以下方法:

#include <chrono>
#include <type_traits>


using perf_clock = std::conditional<
std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock,
std::chrono::steady_clock
>::type;


using floating_seconds = std::chrono::duration<double>;


template<class F, class... Args>
floating_seconds run_test(Func&& func, Args&&... args)
{
const auto t0 = perf_clock::now();
std::forward<Func>(func)(std::forward<Args>(args)...);
return floating_seconds(perf_clock::now() - t0);
}

这与@nikos-athanasiou建议的相同,除了我避免使用非稳定时钟,并使用浮动秒数作为持续时间。

struct profiler
{
std::string name;
std::chrono::high_resolution_clock::time_point p;
profiler(std::string const &n) :
name(n), p(std::chrono::high_resolution_clock::now()) { }
~profiler()
{
using dura = std::chrono::duration<double>;
auto d = std::chrono::high_resolution_clock::now() - p;
std::cout << name << ": "
<< std::chrono::duration_cast<dura>(d).count()
<< std::endl;
}
};


#define PROFILE_BLOCK(pbn) profiler _pfinstance(pbn)

用法如下:

{
PROFILE_BLOCK("Some time");
// your code or function
}

这在范围上类似于RAII

注:这不是我的,但我认为这是相关的

#include <ctime>
#include <cstdio>
#include <iostream>
#include <chrono>
#include <sys/time.h>
using namespace std;
using namespace std::chrono;


void f1()
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
high_resolution_clock::time_point t2 = high_resolution_clock::now();
double dif = duration_cast<nanoseconds>( t2 - t1 ).count();
printf ("Elasped time is %lf nanoseconds.\n", dif );
}


void f2()
{
timespec ts1,ts2;
clock_gettime(CLOCK_REALTIME, &ts1);
clock_gettime(CLOCK_REALTIME, &ts2);
double dif = double( ts2.tv_nsec - ts1.tv_nsec );
printf ("Elasped time is %lf nanoseconds.\n", dif );
}


void f3()
{
struct timeval t1,t0;
gettimeofday(&t0, 0);
gettimeofday(&t1, 0);
double dif = double( (t1.tv_usec-t0.tv_usec)*1000);
printf ("Elasped time is %lf nanoseconds.\n", dif );
}
void f4()
{
high_resolution_clock::time_point t1 , t2;
double diff = 0;
t1 = high_resolution_clock::now() ;
for(int i = 1; i <= 10 ; i++)
{
t2 = high_resolution_clock::now() ;
diff+= duration_cast<nanoseconds>( t2 - t1 ).count();
t1 = t2;
}
printf ("high_resolution_clock:: Elasped time is %lf nanoseconds.\n", diff/10 );
}


void f5()
{
timespec ts1,ts2;
double diff = 0;
clock_gettime(CLOCK_REALTIME, &ts1);
for(int i = 1; i <= 10 ; i++)
{
clock_gettime(CLOCK_REALTIME, &ts2);
diff+= double( ts2.tv_nsec - ts1.tv_nsec );
ts1 = ts2;
}
printf ("clock_gettime:: Elasped time is %lf nanoseconds.\n", diff/10 );
}


void f6()
{
struct timeval t1,t2;
double diff = 0;
gettimeofday(&t1, 0);
for(int i = 1; i <= 10 ; i++)
{
gettimeofday(&t2, 0);
diff+= double( (t2.tv_usec-t1.tv_usec)*1000);
t1 = t2;
}
printf ("gettimeofday:: Elasped time is %lf nanoseconds.\n", diff/10 );
}


int main()
{
//  f1();
//  f2();
//  f3();
f6();
f4();
f5();
return 0;
}

正如其他人已经注意到的,C标准库中的time()函数的分辨率不超过1秒。唯一可以提供更好分辨率的完全可移植的C函数似乎是clock(),但它测量的是处理器时间而不是wallclock时间。如果一个人满足于将自己局限于POSIX平台(例如Linux),那么clock_gettime()函数是一个很好的选择。

自c++ 11以来,有更好的计时设备可用,它们以一种应该在不同编译器和操作系统之间非常可移植的形式提供更好的分辨率。类似地,boost::datetime库提供了良好的高分辨率计时类,这些类应该是高度可移植的。

使用这些工具的一个挑战是查询系统时钟带来的时间延迟。通过clock_gettime(), boost:: datetime和std::chrono的实验,这个延迟很容易是微秒的问题。因此,在测量代码的任何部分的持续时间时,您需要考虑到大约这个大小的测量误差,或者尝试以某种方式纠正零误差。理想情况下,您很可能希望收集函数所花费时间的多个测量值,并计算多次运行所花费的平均时间或最大/最小时间。

为了帮助解决所有这些可移植性和统计数据收集问题,我一直在开发Github上可用的cxx-rtimers库,它试图为c++代码的计时块提供一个简单的API,计算零错误,并从代码中嵌入的多个计时器报告统计数据。如果你有一个c++ 11编译器,你只需#include <rtimers/cxx11.hpp>,并使用类似于:

void expensiveFunction() {
static rtimers::cxx11::DefaultTimer timer("expensiveFunc");
auto scopedStartStop = timer.scopedStart();
// Do something costly...
}

在程序退出时,你会得到一个写入std::cerr的时间统计摘要,例如:

Timer(expensiveFunc): <t> = 6.65289us, std = 3.91685us, 3.842us <= t <= 63.257us (n=731)

它显示了平均时间,它的标准偏差,上限和下限,以及这个函数被调用的次数。

如果你想使用linux特定的计时函数,你可以#include <rtimers/posix.hpp>,或者如果你有Boost库但有一个旧的c++编译器,你可以#include <rtimers/boost.hpp>。这些计时器类也有不同版本,可以跨多个线程收集统计计时信息。还有一些方法允许您估计与两个立即连续的系统时钟查询相关的零错误。

c++ std::chrono具有跨平台的明显优势。 然而,与POSIX clock_gettime()相比,它也引入了显著的开销。 在我的Linux盒子上,所有std::chrono::xxx_clock::now()口味的执行大致相同:

std::chrono::system_clock::now()
std::chrono::steady_clock::now()
std::chrono::high_resolution_clock::now()

虽然POSIX clock_gettime(CLOCK_MONOTONIC, &time)应该与steady_clock::now()相同,但它要快3倍以上!

这是我的测试,为了完整性。

#include <stdio.h>
#include <chrono>
#include <ctime>


void print_timediff(const char* prefix, const struct timespec& start, const
struct timespec& end)
{
double milliseconds = end.tv_nsec >= start.tv_nsec
? (end.tv_nsec - start.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec) * 1e3
: (start.tv_nsec - end.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec - 1) * 1e3;
printf("%s: %lf milliseconds\n", prefix, milliseconds);
}


int main()
{
int i, n = 1000000;
struct timespec start, end;


// Test stopwatch
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i) {
struct timespec dummy;
clock_gettime(CLOCK_MONOTONIC, &dummy);
}
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("clock_gettime", start, end);


// Test chrono system_clock
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i)
auto dummy = std::chrono::system_clock::now();
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("chrono::system_clock::now", start, end);


// Test chrono steady_clock
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i)
auto dummy = std::chrono::steady_clock::now();
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("chrono::steady_clock::now", start, end);


// Test chrono high_resolution_clock
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i)
auto dummy = std::chrono::high_resolution_clock::now();
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("chrono::high_resolution_clock::now", start, end);


return 0;
}

这是我用gcc7.2 -O3编译时得到的输出:

clock_gettime: 24.484926 milliseconds
chrono::system_clock::now: 85.142108 milliseconds
chrono::steady_clock::now: 87.295347 milliseconds
chrono::high_resolution_clock::now: 84.437838 milliseconds

我需要测量库中各个函数的执行时间。我不希望每个函数的每次调用都用一个时间度量函数来包装,因为这样做很难看,而且会加深调用堆栈。我也不想把定时器代码放在每个函数的顶部和底部,因为当函数可能提前退出或抛出异常时,这会造成混乱。所以我最终做了一个计时器,用它自己的生命周期来测量时间。

通过这种方式,我可以测量一个代码块的wallall时间,方法是在有问题的代码块(函数或任何作用域)的开头实例化这些对象之一,然后允许实例析构函数测量实例超出作用域时自构造以来所花费的时间。你可以找到完整的例子在这里,但是结构体非常简单:

template <typename clock_t = std::chrono::steady_clock>
struct scoped_timer {
using duration_t = typename clock_t::duration;
const std::function<void(const duration_t&)> callback;
const std::chrono::time_point<clock_t> start;


scoped_timer(const std::function<void(const duration_t&)>& finished_callback) :
callback(finished_callback), start(clock_t::now()) { }
scoped_timer(std::function<void(const duration_t&)>&& finished_callback) :
callback(finished_callback), start(clock_t::now()) { }
~scoped_timer() { callback(clock_t::now() - start); }
};

当函数超出作用域时,该结构体将回调所提供的函数,这样您就可以对计时信息做一些事情(打印它或存储它或其他什么)。如果你需要做一些更复杂的事情,你甚至可以使用std::bindstd::placeholders来回调带有更多参数的函数。

下面是一个快速使用它的例子:

void test(bool should_throw) {
scoped_timer<> t([](const scoped_timer<>::duration_t& elapsed) {
auto e = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(elapsed).count();
std::cout << "took " << e << "ms" << std::endl;
});


std::this_thread::sleep_for(std::chrono::seconds(1));


if (should_throw)
throw nullptr;


std::this_thread::sleep_for(std::chrono::seconds(1));
}

如果你想更谨慎,你也可以使用newdelete显式地启动和停止计时器,而不依赖于作用域来为你做这些。

#include <ctime>
#include <functional>


using namespace std;


void f() {
clock_t begin = clock();


// ...code to measure time...


clock_t end = clock();


function<double(double, double)> convtime = [](clock_t begin, clock_t end)
{
return double(end - begin) / CLOCKS_PER_SEC;
};


printf("Elapsed time: %.2g sec\n", convtime(begin, end));


}

类似的例子,一个可用在这里,只有额外的转换功能+打印出来。

我已经创建了一个类来自动测量流逝的时间,请检查代码(c++11)在这个链接:https://github.com/sonnt174/Common/blob/master/time_measure.h

使用timmeasure类的示例:

void test_time_measure(std::vector<int> arr) {
TimeMeasure<chrono::microseconds> time_mea;  // create time measure obj
std::sort(begin(arr), end(arr));
}

Matlab味!

tic启动秒表计时器来测量性能。该功能记录执行tic命令时的内部时间。使用toc函数显示运行时间。

#include <iostream>
#include <ctime>
#include <thread>
using namespace std;


clock_t START_TIMER;


clock_t tic()
{
return START_TIMER = clock();
}


void toc(clock_t start = START_TIMER)
{
cout
<< "Elapsed time: "
<< (clock() - start) / (double)CLOCKS_PER_SEC << "s"
<< endl;
}


int main()
{
tic();
this_thread::sleep_for(2s);
toc();


return 0;
}

下面是一个简单的类,它将在指定的持续时间单位内打印它进入和离开作用域之间的持续时间:

#include <chrono>
#include <iostream>


template <typename T>
class Benchmark
{
public:
Benchmark(std::string name) : start(std::chrono::steady_clock::now()), name(name) {}
~Benchmark()
{
auto end = std::chrono::steady_clock::now();
T duration = std::chrono::duration_cast<T>(end - start);
std::cout << "Bench \"" << name << "\" took: " << duration.count() << " units" << std::endl;
}


private:
std::string name;
std::chrono::time_point<std::chrono::steady_clock> start;


};
int main()
{
Benchmark<std::chrono::nanoseconds> bench("for loop");
for(int i = 0; i < 1001000; i++){}
}

使用示例:

int main()
{
Benchmark<std::chrono::nanoseconds> bench("for loop");
for(int i = 0; i < 100000; i++){}
}

输出:

Bench "for loop" took: 230656 units