Легко измерить прошедшее время

208

Я пытаюсь использовать time() для измерения различных точек моей программы.

Что я не понимаю, почему значения в до и после одинаковы? Я понимаю, что это не лучший способ профилировать мою программу, я просто хочу посмотреть, сколько времени займет что-то.

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? Означает ли это 26,339 наносекунд = 26,3 мсек?

Как насчет **time taken = 4 45025, означает ли это 4 секунды и 25 мсек?

  • 10
    Я не понимаю вопроса. Конечно значения разные. Время прошло между ними, поэтому time() возвращает другое значение.
  • 1
    Что вы имеете в виду «Я не понимаю, почему значения в до и после разные»? Вы получаете текущее время (в секундах с 1 января 1970 года), используя time(NULL) ... во второй раз, когда вы звоните, оно будет через N секунд после первого и, следовательно, ... другим (если не от вас » выполнение не займет секунду, чтобы завершить ... в этом случае, это будет так же, как первый).
Показать ещё 7 комментариев
Теги:
time

20 ответов

224
#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 "часы" в течение секунды. Это простое переносное измерение, хотя оно упрощено.

  • 117
    Имейте в виду, что clock() измеряет процессорное время, а не фактическое истекшее время (которое может быть намного больше).
  • 12
    При программировании параллельного кода для кластеров этот метод не отражает реального времени ...
Показать ещё 5 комментариев
196

Вы можете абстрагировать механизм измерения времени, и каждый вызываемый период выполнения измеряется с помощью минимального дополнительного кода, просто путем вызова структуры таймера. Кроме того, во время компиляции вы можете параметризовать тип синхронизации (миллисекунды, наносекунды и т.д.).

Благодаря обзору Loki Astari и предложению использовать вариативные шаблоны.Это, поэтому вызов переадресованной функции.

#include <iostream>
#include <chrono>

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

int main() {
    std::cout << measure<>::execution(functor(dummy)) << std::endl;
}

Demo

В соответствии с комментарием Howard Hinnant лучше не выходить из системы хронографа, пока нам не придется. Таким образом, вышеуказанный класс может дать пользователю возможность вызвать count вручную, предоставив дополнительный статический метод (показан на С++ 14)

template<typename F, typename ...Args>
static auto duration(F&& func, Args&&... args)
{
    auto start = std::chrono::steady_clock::now();
    std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
    return std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now()-start);
} 

// call .count() manually later when needed (eg IO)
auto avg = (measure<>::duration(func) + measure<>::duration(func)) / 2.0;

и быть наиболее полезным для клиентов, которые

"хотите выполнить пост-обработку нескольких длительностей до ввода-вывода (например, среднего значения)"


Полный код можно найти здесь. Моя попытка создать инструмент сравнения производительности на основе хронографа записывается здесь.


Если доступно С++ 17 std::invoke, вызов вызываемого в execution может быть выполнен следующим образом:

invoke(forward<decltype(func)>(func), forward<Args>(args)...);

чтобы указать вызывающие элементы, которые являются указателями на функции-члены.

  • 2
    Ницца; У меня есть что-то похожее в моем коде, но я использую другой интерфейс к классу: у меня есть класс ( code_timer ), который занимает время начала ( std::chrono::system_clock::now(); ) в конструкторе, методе code_timer::ellapsed который измеряет разницу между новым вызовом now() вызовом в конструкторе, и метод code_timer::reset который сбрасывает время начала до нового результата now() . Чтобы измерить выполнение функтора в моем коде, я использую свободную функцию вне класса. Это позволяет измерять время от построения объекта до завершения асинхронного вызова.
  • 0
    @utnapistim Thnx, я попросил обзор этого кода, вы можете проверить его здесь . Если у вас есть время, вы могли бы немного подробнее рассказать о своем дизайне, это звучит великолепно.
Показать ещё 23 комментария
141
//***C++11 Style:***
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() <<std::endl;
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds> (end - begin).count() <<std::endl;
  • 14
    Я считаю это действительно простым, и он работает для меня.
  • 7
    да, это должен быть ответ
Показать ещё 6 комментариев
46

Как я вижу из вашего вопроса, похоже, что вы хотите узнать прошедшее время после выполнения какой-либо части кода. Думаю, вам будет удобно видеть результаты в секундах. Если да, попробуйте использовать функцию 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 );
  • 3
    Это всегда дает мне целые секунды. Это должно случиться?
  • 8
    время всегда будет возвращать только секунды, поэтому оно не может быть использовано для измерений менее секунды.
24

Только для Windows: (тег Linux был добавлен после отправки ответа)

Вы можете использовать GetTickCount(), чтобы получить количество миллисекунд, прошедших с момента запуска системы.

long int before = GetTickCount();

// Perform time-consuming operation

long int after = GetTickCount();
  • 7
    Я использую это на Linux. Поэтому я не могу использовать функцию GetTickCount ().
  • 1
    уже не бери в голову;) Спасибо за обновление тега твоего поста
Показать ещё 1 комментарий
12

функция времени (NULL) вернет количество секунд, прошедших с 01.01.1970 в 00:00. И поскольку эта функция вызывается в разное время в вашей программе, она всегда будет отличаться Время в С++

  • 0
    Я не знаю, почему кто-то проголосовал, но ваш ответ не совсем правильный. Для начала он не возвращает дату и не всегда будет другим.
  • 0
    ах да, вот что пошло не так. Благодарю.
11

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(), а также в микросекундах.

9
#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 
  • 3
    Хотя ваш ответ приветствуется, мы предпочитаем преамбулу, содержащую краткое описание кода. Благодарю.
  • 2
    Это не прошедшее время, а время процессора.
7

Значения, напечатанные вашей второй программой, - это секунды и микросекунды.

0 26339 = 0.026'339 s =   26339 µs
4 45025 = 4.045'025 s = 4045025 µs
5
#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;
}
5
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 в области

ПРИМЕЧАНИЕ, это не мое, но я подумал, что это актуально здесь.

  • 1
    включает в себя отсутствие
2

В 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 );
  }
2

Из того, что видно, 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))
    );
2

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

2

Вызов функции time(NULL) возвращает число секунд, прошедших с момента epoc: 1 января 1970 года. Возможно, вы хотите сделать разницу между двумя отметками времени:

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

printf ("**MyProgram::time elapsed= %lds\n", time(NULL) - start);
1

Обычно я использую следующее:

#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, за исключением того, что я избегаю использования нестационарных часов и использую плавающее число секунд в качестве продолжительности.

  • 1
    На этом переключателе типов : обычно high_resolution_clock - это typedef для system_clock или steady_clock . Таким образом, чтобы отследить этот std::conditional если часть is_steady имеет значение true, вы выбираете high_resolution_clock который является (typedef для) steady_clock . Если значение steady_clock false, вы снова выбираете steady_clock . Просто используйте steady_clock с самого начала ...
  • 0
    @ nikos-athanasiou Я полностью согласен с комментарием 5gon12eder о том, что «типичный» случай не требуется стандартом, поэтому некоторые STL могут быть реализованы другим способом. Я предпочитаю, чтобы мой код был более общим и не связанным с деталями реализации.
Показать ещё 4 комментария
1

Причина, по которой оба значения одинаковы, заключается в том, что ваша длительная процедура не занимает много времени, менее одной секунды. Вы можете попробовать просто добавить длинный цикл (для (int я = 0; я < 100000000; я ++);) в конце функции, чтобы убедиться, что это проблема, тогда мы можем перейти оттуда...

В случае, если вышеизложенное окажется правдой, вам нужно будет найти другую системную функцию (я понимаю, что вы работаете с linux, поэтому я не могу помочь вам с именем функции) для более точного измерения времени. Я уверен, что есть функция, аналогичная функции GetTickCount() в Linux, вам просто нужно ее найти.

1

Они такие же, потому что ваша функция 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));
0

В ответ на OP три конкретных вопроса.

"Я не понимаю, почему значения в до и после одинаковы?"

первый вопрос и пример кода показывают, что time() имеет разрешение 1 секунду, поэтому ответ должен состоять в том, что две функции выполняются менее чем за 1 секунду. Но иногда он (по-видимому, нелогично) сообщает 1 секунду, если две метки таймера оседают на одну секунду.

В следующем примере используется gettimeofday(), который заполняет эту структуру

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

и второй вопрос спрашивает: "Как я могу прочитать результат **time taken = 0 26339? Означает ли это 26,339 наносекунд = 26,3 мсек?"

Мой второй ответ - это время, равное 0 секундам и 26339 микросекундам, то есть 0,026339 секунд, в котором первый пример выполняется менее чем за 1 секунду.

третий вопрос спрашивает: "Что насчет **time taken = 4 45025, значит ли это 4 секунды и 25 мсек?"

Мой третий ответ - это время 4 секунды и 45025 микросекунд, то есть 4.045025 секунд, что показывает, что ОП изменил задачи, выполняемые двумя функциями, которые он ранее выполнял.

-5

Вы можете использовать SFML-библиотеку, которая является простой и быстрой мультимедийной библиотекой. Он включает в себя множество полезных и четко определенных классов, таких как Clock, Socket, Sound, Graphics и т.д. Он настолько прост в использовании и настоятельно рекомендуется.

Это пример этого вопроса.

sf::Clock clock;
...
Time time1 = clock.getElapsedTime();
...
Time time2 = clock.restart();

Ещё вопросы

Сообщество Overcoder
Наверх
Меню