用C ++测量函数的执行时间

时间:2014-03-13 18:23:31

标签: c++ optimization profiling

我想知道某个函数在我的C ++程序中执行多长时间才能在 Linux 上执行。之后,我想进行速度比较。我看到了几个时间功能,但结果来自于boost。计时:

process_user_cpu_clock, captures user-CPU time spent by the current process

现在,我不清楚我是否使用上述功能,我将获得CPU花在该功能上的唯一时间吗?

其次,我找不到任何使用上述功能的例子。任何人都可以帮我如何使用上述功能?

P.S:现在,我正在使用std::chrono::system_clock::now()在几秒钟内获得时间,但由于每次CPU负载不同,这会给我不同的结果。

14 个答案:

答案 0 :(得分:186)

这是一个非常容易使用的C ++ 11方法。您必须使用std::chrono::high_resolution_clock标题中的<chrono>

像这样使用它:

#include <iostream>
#include <chrono>

using namespace std;
using namespace std::chrono;

void function()
{
    long long number = 0;

    for( long long i = 0; i != 2000000; ++i )
    {
       number += 5;
    }
}

int main()
{
    high_resolution_clock::time_point t1 = high_resolution_clock::now();
    function();
    high_resolution_clock::time_point t2 = high_resolution_clock::now();

    auto duration = duration_cast<microseconds>( t2 - t1 ).count();

    cout << duration;
    return 0;
}

这将测量功能的持续时间。

注意:并不要求始终获得相同的输出,因为计算机上运行的其他进程可能会少用或多用机器的CPU。正如您将要解决数学练习一样,您的思维可能会或多或少地集中在一起,因此您将在不同的时间解决这个问题。在人类的头脑中,我们可以记住数学问题的解决方案,但对于计算机来说,同样的过程总是会有新的东西,所以,正如我所说,不需要总是得到相同的结果!

答案 1 :(得分:11)

这是一个函数,它将测量作为参数传递的任何函数的执行时间:

#include <chrono>
#include <utility>

typedef std::chrono::high_resolution_clock::time_point TimeVar;

#define duration(a) std::chrono::duration_cast<std::chrono::nanoseconds>(a).count()
#define timeNow() std::chrono::high_resolution_clock::now()

template<typename F, typename... Args>
double funcTime(F func, Args&&... args){
    TimeVar t1=timeNow();
    func(std::forward<Args>(args)...);
    return duration(timeNow()-t1);
}

使用示例:

#include <iostream>
#include <algorithm>

typedef std::string String;

//first test function doing something
int countCharInString(String s, char delim){
    int count=0;
    String::size_type pos = s.find_first_of(delim);
    while ((pos = s.find_first_of(delim, pos)) != String::npos){
        count++;pos++;
    }
    return count;
}

//second test function doing the same thing in different way
int countWithAlgorithm(String s, char delim){
    return std::count(s.begin(),s.end(),delim);
}


int main(){
    std::cout<<"norm: "<<funcTime(countCharInString,"precision=10",'=')<<"\n";
    std::cout<<"algo: "<<funcTime(countWithAlgorithm,"precision=10",'=');
    return 0;
}

输出:

norm: 15555
algo: 2976

答案 2 :(得分:8)

查找函数执行时间的简单程序。

#include <iostream>
#include <ctime> // time_t
#include <cstdio>

void function()
{
     for(long int i=0;i<1000000000;i++)
     {
        // do nothing
     }
}

int main()
{

time_t begin,end; // time_t is a datatype to store time values.

time (&begin); // note time before execution
function();
time (&end); // note time after execution

double difference = difftime (end,begin);
printf ("time taken for function() %.2lf seconds.\n", difference );

return 0;
}

答案 3 :(得分:4)

在Scott Meyers的书中,我找到了一个通用通用lambda表达式的示例,该表达式可用于测量函数执行时间。 (C ++ 14)

auto timeFuncInvocation = 
    [](auto&& func, auto&&... params) {
        // get time before function invocation
        const auto& start = high_resolution_clock::now();
        // function invocation using perfect forwarding
        std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
        // get time after function invocation
        const auto& stop = high_resolution_clock::now();
        return stop - start;
     };

问题在于,您仅衡量一次执行,因此结果可能会大不相同。为了获得可靠的结果,您应该衡量大量的执行情况。 根据Andrei Alexandrescu在code :: dive 2015大会上的演讲-编写Fast Code I:

测量时间:tm = t + tq + tn +到

其中:

tm-测量(观察)的时间

t-实际感兴趣的时间

tq-量化噪声增加的时间

tn-各种噪声源所花费的时间

到-开销时间(测量,循环,调用函数)

根据他稍后在演讲中所说的,您应该以这种大量执行的最少次数作为结果。 我鼓励您看一下他解释其原因的演讲。

还有一个非常好的Google图书馆-https://github.com/google/benchmark。 该库非常易于使用且功能强大。您可以在YouTube上查看钱德勒·卡鲁斯(Chandler Carruth)在实践中使用此库的一些讲座。例如CppCon 2017:钱德勒·卡鲁斯(Chandler Carruth)“走得更快”;

用法示例:

#include <iostream>
#include <chrono>
#include <vector>
auto timeFuncInvocation = 
    [](auto&& func, auto&&... params) {
        // get time before function invocation
        const auto& start = high_resolution_clock::now();
        // function invocation using perfect forwarding
        for(auto i = 0; i < 100000/*largeNumber*/; ++i) {
            std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
        }
        // get time after function invocation
        const auto& stop = high_resolution_clock::now();
        return (stop - start)/100000/*largeNumber*/;
     };

void f(std::vector<int>& vec) {
    vec.push_back(1);
}

void f2(std::vector<int>& vec) {
    vec.emplace_back(1);
}
int main()
{
    std::vector<int> vec;
    std::vector<int> vec2;
    std::cout << timeFuncInvocation(f, vec).count() << std::endl;
    std::cout << timeFuncInvocation(f2, vec2).count() << std::endl;
    std::vector<int> vec3;
    vec3.reserve(100000);
    std::vector<int> vec4;
    vec4.reserve(100000);
    std::cout << timeFuncInvocation(f, vec3).count() << std::endl;
    std::cout << timeFuncInvocation(f2, vec4).count() << std::endl;
    return 0;
}

编辑: 当然,您始终需要记住,编译器可以优化某些内容,也可以不进行优化。在这种情况下,像perf这样的工具可能会有用。

答案 4 :(得分:3)

使用较旧的C ++或C的简便方法:

#include <time.h> // includes clock_t and CLOCKS_PER_SEC

int main() {

    clock_t start, end;

    start = clock();
    // ...code to measure...
    end = clock();

    double duration_sec = double(end-start)/CLOCKS_PER_SEC;
    return 0;
}

以秒为单位的计时精度为1.0/CLOCKS_PER_SEC

答案 5 :(得分:1)

  
      
  • 这是C ++ 11中非常易于使用的方法。
  •   
  • 我们可以在标题中使用std :: chrono :: high_resolution_clock
  •   
  • 我们可以编写一种方法,以易于阅读的形式打印方法的执行时间。
  •   

例如,要找到1到1亿之间的所有素数,大约需要1分钟40秒。 因此执行时间打印为:

Execution Time: 1 Minutes, 40 Seconds, 715 MicroSeconds, 715000 NanoSeconds

代码在这里:

#include <iostream>
#include <chrono>

using namespace std;
using namespace std::chrono;

typedef high_resolution_clock Clock;
typedef Clock::time_point ClockTime;

void findPrime(long n, string file);
void printExecutionTime(ClockTime start_time, ClockTime end_time);

int main()
{
    long n = long(1E+8);  // N = 100 million

    ClockTime start_time = Clock::now();

    // Write all the prime numbers from 1 to N to the file "prime.txt"
    findPrime(n, "C:\\prime.txt"); 

    ClockTime end_time = Clock::now();

    printExecutionTime(start_time, end_time);
}

void printExecutionTime(ClockTime start_time, ClockTime end_time)
{
    auto execution_time_ns = duration_cast<nanoseconds>(end_time - start_time).count();
    auto execution_time_ms = duration_cast<microseconds>(end_time - start_time).count();
    auto execution_time_sec = duration_cast<seconds>(end_time - start_time).count();
    auto execution_time_min = duration_cast<minutes>(end_time - start_time).count();
    auto execution_time_hour = duration_cast<hours>(end_time - start_time).count();

    cout << "\nExecution Time: ";
    if(execution_time_hour > 0)
    cout << "" << execution_time_hour << " Hours, ";
    if(execution_time_min > 0)
    cout << "" << execution_time_min % 60 << " Minutes, ";
    if(execution_time_sec > 0)
    cout << "" << execution_time_sec % 60 << " Seconds, ";
    if(execution_time_ms > 0)
    cout << "" << execution_time_ms % long(1E+3) << " MicroSeconds, ";
    if(execution_time_ns > 0)
    cout << "" << execution_time_ns % long(1E+6) << " NanoSeconds, ";
}

答案 6 :(得分:1)

如果您想保证安全的时间和代码行,可以使测量函数执行时间成为一行宏:

a)实现上面已经建议的时间测量类(这是我的android实现):

class MeasureExecutionTime{
private:
    const std::chrono::steady_clock::time_point begin;
    const std::string caller;
public:
    MeasureExecutionTime(const std::string& caller):caller(caller),begin(std::chrono::steady_clock::now()){}
    ~MeasureExecutionTime(){
        const auto duration=std::chrono::steady_clock::now()-begin;
        LOGD("ExecutionTime")<<"For "<<caller<<" is "<<std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()<<"ms";
    }
};

b)添加一个方便的宏,该宏使用当前函数名称作为TAG(此处使用宏很重要,否则__FUNCTION__的计算结果将为MeasureExecutionTime,而不是函数你想测量

#ifndef MEASURE_FUNCTION_EXECUTION_TIME
#define MEASURE_FUNCTION_EXECUTION_TIME const MeasureExecutionTime measureExecutionTime(__FUNCTION__);
#endif

c)在要测量的函数开始处编写宏。示例:

 void DecodeMJPEGtoANativeWindowBuffer(uvc_frame_t* frame_mjpeg,const ANativeWindow_Buffer& nativeWindowBuffer){
        MEASURE_FUNCTION_EXECUTION_TIME
        // Do some time-critical stuff 
}

这将导致以下输出:

ExecutionTime: For DecodeMJPEGtoANativeWindowBuffer is 54ms

请注意,此方法(与所有其他建议的解决方案一样)将测量函数调用到返回之间的时间,而不是CPU执行函数的时间。但是,如果您不给调度程序任何更改以通过调用sleep()或类似方法来暂停运行的代码,则两者之间没有任何区别。

答案 7 :(得分:1)

#include <iostream>
#include <chrono>

void function()
{
    // code here;
}

int main()
{
    auto t1 = std::chrono::high_resolution_clock::now();
    function();
    auto t2 = std::chrono::high_resolution_clock::now();

    auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();

    std::cout << duration<<"/n";
    return 0;
}

这对我有用。


注意:

high_resolution_clock 在不同标准库实现中的实现不一致,应避免使用它。它通常只是 std::chrono::steady_clockstd::chrono::system_clock 的别名,但具体取决于库或配置。当它是 system_clock 时,它不是单调的(例如,时间可以倒退)。

例如,gcc 的 libstdc++system_clock,MSVC 是 steady_clock,clang 的 libc++ 取决于配置。

通常应该直接使用 std::chrono::steady_clockstd::chrono::system_clock 而不是 std::chrono::high_resolution_clock:使用 steady_clock 进行持续时间测量,使用 system_clock 进行挂钟时间。

答案 8 :(得分:0)

这是一个很好的仅标题类模板,用于测量函数或任何代码块的运行时间:

#ifndef EXECUTION_TIMER_H
#define EXECUTION_TIMER_H

template<class Resolution = std::chrono::milliseconds>
class ExecutionTimer {
public:
    using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
                                     std::chrono::high_resolution_clock,
                                     std::chrono::steady_clock>;
private:
    const Clock::time_point mStart = Clock::now();

public:
    ExecutionTimer() = default;
    ~ExecutionTimer() {
        const auto end = Clock::now();
        std::ostringstream strStream;
        strStream << "Destructor Elapsed: "
                  << std::chrono::duration_cast<Resolution>( end - mStart ).count()
                  << std::endl;
        std::cout << strStream.str() << std::endl;
    }    

    inline void stop() {
        const auto end = Clock::now();
        std::ostringstream strStream;
        strStream << "Stop Elapsed: "
                  << std::chrono::duration_cast<Resolution>(end - mStart).count()
                  << std::endl;
        std::cout << strStream.str() << std::endl;
    }

}; // ExecutionTimer

#endif // EXECUTION_TIMER_H

以下是它的一些用途:

int main() {
    { // empty scope to display ExecutionTimer's destructor's message
         // displayed in milliseconds
         ExecutionTimer<std::chrono::milliseconds> timer;

         // function or code block here

         timer.stop();

    } 

    { // same as above
        ExecutionTimer<std::chrono::microseconds> timer;

        // code block here...

        timer.stop();
    }

    {  // same as above
       ExecutionTimer<std::chrono::nanoseconds> timer;

       // code block here...

       timer.stop();

    }

    {  // same as above
       ExecutionTimer<std::chrono::seconds> timer;

       // code block here...

       timer.stop();

    }              

    return 0;
}

由于课程是一个模板,我们可以轻松指定我们想要测量时间的方式。显示。这是一个非常方便的实用程序类模板,用于执行基准测试,并且非常易于使用。

答案 9 :(得分:0)

steady_clock不同,我建议使用保证为单调的high_resolution_clock

#include <iostream>
#include <chrono>

using namespace std;

unsigned int stopwatch()
{
    static auto start_time = chrono::steady_clock::now();

    auto end_time = chrono::steady_clock::now();
    auto delta    = chrono::duration_cast<chrono::microseconds>(end_time - start_time);

    start_time = end_time;

    return delta.count();
}

int main() {
  stopwatch(); //Start stopwatch
  std::cout << "Hello World!\n";
  cout << stopwatch() << endl; //Time to execute last line
  for (int i=0; i<1000000; i++)
      string s = "ASDFAD";
  cout << stopwatch() << endl; //Time to execute for loop
}

输出:

Hello World!
62
163514

答案 10 :(得分:0)

您可以有一个简单的类,可以用于此类测量。

0

唯一需要做的就是在函数的开始处创建一个对象

class duration_printer {
public:
    duration_printer() : __start(std::chrono::high_resolution_clock::now()) {}
    ~duration_printer() {
        using namespace std::chrono;
        high_resolution_clock::time_point end = high_resolution_clock::now();
        duration<double> dur = duration_cast<duration<double>>(end - __start);
        std::cout << dur.count() << " seconds" << std::endl;
    }
private:
    std::chrono::high_resolution_clock::time_point __start;
};

就是这样。可以根据您的要求修改班级。

答案 11 :(得分:0)

由于所提供的答案均不十分准确或无法提供可重复的结果,因此我决定在我的代码中添加一个链接,该链接具有亚纳秒精度和科学统计信息。

请注意,这仅适用于测量运行时间非常短(也就是几个时钟周期到几千个时钟)的代码:如果它们运行的​​时间太长,很可能会被某些中断-中断,那么显然不可能给出可重复的准确结果;结果是测量永远不会结束:也就是说,它将继续测量,直到统计上确定它有99.9%的把握才是正确的答案,而在代码运行时间过长的机器上运行其他进程的机器上永远不会发生。

https://github.com/CarloWood/cwds/blob/master/benchmark.h#L40

答案 12 :(得分:0)

C++11 清理版 Jahid 的回应:

#include <chrono>
#include <thread>

void long_operation(int ms)
{
    /* Simulating a long, heavy operation. */
    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}

template<typename F, typename... Args>
double funcTime(F func, Args&&... args){
    std::chrono::high_resolution_clock::time_point t1 = 
        std::chrono::high_resolution_clock::now();
    func(std::forward<Args>(args)...);
    return std::chrono::duration_cast<std::chrono::milliseconds>(
        std::chrono::high_resolution_clock::now()-t1).count();
}

int main()
{
    std::cout<<"expect 150: "<<funcTime(long_operation,150)<<"\n";

    return 0;
}

答案 13 :(得分:0)

这是一个非常基本的计时器类,您可以根据需要对其进行扩展。我想要一些简单的东西,可以在代码中干净利落地使用。您可以通过以下链接在编码领域搞乱它:http://tpcg.io/nd47hFqr

class local_timer {
    private:
        std::chrono::_V2::system_clock::time_point start_time;
        std::chrono::_V2::system_clock::time_point stop_time;
        std::chrono::_V2::system_clock::time_point stop_time_temp;
        std::chrono::microseconds most_recent_duration_usec_chrono;
        double most_recent_duration_sec;
    public:

        local_timer() {

        };

        ~local_timer() {

        };

        void start() {
            this->start_time = std::chrono::high_resolution_clock::now();
        };

        void stop() {
            this->stop_time = std::chrono::high_resolution_clock::now();
        };

        double get_time_now() {
            this->stop_time_temp = std::chrono::high_resolution_clock::now();
            this->most_recent_duration_usec_chrono = std::chrono::duration_cast<std::chrono::microseconds>(stop_time_temp-start_time);
            this->most_recent_duration_sec = (long double)most_recent_duration_usec_chrono.count()/1000000;
            return this->most_recent_duration_sec;
        };

        double get_duration() {
            this->most_recent_duration_usec_chrono = std::chrono::duration_cast<std::chrono::microseconds>(stop_time-start_time);
            this->most_recent_duration_sec = (long double)most_recent_duration_usec_chrono.count()/1000000;
            return this->most_recent_duration_sec;
        };


};

这个存在的用途

#include <iostream>
#include "timer.hpp" //if kept in an hpp file in the same folder, can also before your main function

int main() {
    //create two timers
    local_timer timer1 = local_timer();
    local_timer timer2 = local_timer();
    
    //set start time for timer1
    timer1.start();
    //wait 1 second
    while(timer1.get_time_now() < 1.0) {
    }
    //save time
    timer1.stop();
    //print time
    std::cout << timer1.get_duration() << " seconds, timer 1\n" << std::endl;

    timer2.start();
    for(long int i = 0; i < 100000000; i++) {
        //do something
        if(i%1000000 == 0) { 
            //return time since loop started
            std::cout << timer2.get_time_now() << " seconds, timer 2\n"<< std::endl;
        }
        
    }
    return 0;
}