Измерение времени выполнения функции в С++

Я хочу узнать, сколько времени занимает определенная функция в моей программе на С++ для Linux. Впоследствии я хочу сделать сравнение скорости. Я видел несколько функций времени, но в итоге получил это от повышения. Chrono:

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

Теперь, я не понимаю, использую ли я вышеприведенную функцию, получаю ли я только время, затрачиваемое процессором на эту функцию?

Во-вторых, я не мог найти никакого примера использования указанной выше функции. Может ли кто-нибудь помочь мне в использовании вышеуказанной функции?

P.S: Сейчас я использую std::chrono::system_clock::now(), чтобы получить время в секундах, но это дает мне разные результаты из-за разной загрузки процессора каждый раз.

Ответ 1

Это очень простой в использовании метод в С++ 11. Вы должны использовать std::chrono::high_resolution_clock из заголовка <chrono>.

Используйте это так:

#include <iostream>
#include <chrono>

void function()
{
    long long number = 0;

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

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;
    return 0;
}

Это будет измерять продолжительность функции.

ПРИМЕЧАНИЕ. Вы не всегда получаете одинаковое время для функции. Это связано с тем, что центральный процессор вашего компьютера может в меньшей или меньшей степени использоваться другими процессами, выполняющимися на вашем компьютере, так же, как ваш разум может быть более или менее сконцентрированным при выполнении математического упражнения. В человеческом уме мы можем вспомнить решение математической задачи, но для компьютера тот же процесс всегда будет чем-то новым; таким образом, как я уже сказал, вы не всегда получите один и тот же результат!

Ответ 2

Здесь функция, которая будет измерять время выполнения любой функции, переданной как аргумент:

#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

Ответ 3

простая программа для поиска времени выполнения функции.

#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;
}

Ответ 4

В книге Скотта Мейерса я нашел пример универсального универсального лямбда-выражения, которое можно использовать для измерения времени выполнения функции. (С++ 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;
     };

Проблема в том, что вы измеряете только одно исполнение, поэтому результаты могут сильно отличаться. Чтобы получить достоверный результат, вы должны измерить большое количество казней. По словам Андрея Александреску, лекция на конференции code :: dive 2015 - Написание Fast Code I:

Измеренное время: tm = t + tq + tn + до

где:

tm - измеренное (наблюдаемое) время

t - фактическое время интереса

tq - время, добавленное шумом квантования

tn - время, добавленное различными источниками шума

до - накладные расходы (измерение, зацикливание, вызов функций)

Согласно тому, что он сказал позже в лекции, вы должны взять как минимум это большое количество казни в качестве результата. Я призываю вас взглянуть на лекцию, в которой он объясняет, почему.

Также есть очень хорошая библиотека от Google - https://github.com/google/benchmark. Эта библиотека очень проста в использовании и мощна. Вы можете ознакомиться с некоторыми лекциями Чандлера Каррута на YouTube, где он использует эту библиотеку на практике. Например, CppCon 2017: Чендлер Кэррут "Идет в никуда быстрее";

Пример использования:

#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;
}

EDIT: Конечно, вы всегда должны помнить, что ваш компилятор может оптимизировать что-то или нет. Такие инструменты, как perf, могут быть полезны в таких случаях.

Ответ 5

Простой способ для пожилых 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

Ответ 6

  •    Это очень простой в использовании метод в С++ 11.
  • Мы можем использовать std::chrono :: high_resolution_clock из заголовка
  • Мы можем написать метод для печати времени выполнения метода в удобочитаемой форме.

Например, чтобы найти все простые числа от 1 до 100 миллионов, потребуется примерно 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, ";
}

Ответ 7

Вот отличный шаблон класса только для заголовка для измерения прошедшего времени функции или любого кода:

#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 destructor 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;
}

Поскольку класс является шаблоном, мы можем легко определить, как мы хотим, чтобы наше время измерялось и отображалось. Это очень удобный шаблон класса утилит для выполнения настольной маркировки и очень прост в использовании.

Ответ 8

Я рекомендую использовать 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