it-swarm.com.ru

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

Я пытаюсь использовать 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? Означает ли это, что 26339 наносекунд = 26,3 мсек?

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

258
hap497
#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 "часы". Это простое, портативное измерение, даже если оно чрезмерно упрощено.

258
Roger Pate

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

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

#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

Согласно комментарию Говарда Хиннанта лучше не выходить из системы хронографа, пока нам не придется. Таким образом, приведенный выше класс может дать пользователю возможность вызвать count вручную, предоставив дополнительный статический метод (показано в C++ 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;

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

"хотите обработать несколько периодов до ввода/вывода (например, в среднем)"


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


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

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

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

248
Nikos Athanasiou
//***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;
232
user3762106

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

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

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

long int before = GetTickCount();

// Perform time-consuming operation

long int after = GetTickCount();
30
RvdK

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

13
vodkhang

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

12
philant
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 по объему

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

11
user6266295
#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 
9
Eskay

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

0 26339 = 0.026'339 s =   26339 µs
4 45025 = 4.045'025 s = 4045025 µs
8
Didier Trosset
#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;
}
7
Akanksha Gupta

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
4
Alexey Polonsky

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

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

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

Из того, что видно, 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
Safar Ligal

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

2
Mike Weller

В 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
cloudrain21

Как уже отмечали другие, функция time () в стандартной библиотеке C не имеет разрешения лучше одной секунды. Похоже, единственной полностью переносимой функцией C, которая может обеспечить лучшее разрешение, является clock (), но она измеряет время процессора, а не время настенных часов. Если кто-то хочет ограничиться платформой POSIX (например, Linux), то функция clock_gettime () является хорошим выбором.

Начиная с C++ 11, есть гораздо лучшие средства синхронизации , которые предлагают лучшее разрешение в форме, которая должна быть очень переносимой для разных компиляторов и операционных систем. Точно так же библиотека boost :: datetime предоставляет хорошие классы синхронизации высокого разрешения, которые должны быть легко переносимыми.

Одной из проблем при использовании любого из этих средств является задержка, вызванная запросом системных часов. Из экспериментов с clock_gettime (), boost :: datetime и std :: chrono эта задержка может легко составлять несколько микросекунд. Таким образом, при измерении длительности любой части вашего кода вы должны учитывать наличие ошибки измерения около этого размера или пытаться каким-то образом исправить эту нулевую ошибку. В идеале может потребоваться собрать несколько измерений времени, затраченного вашей функцией, и вычислить среднее или максимальное/минимальное время, затраченное на несколько прогонов.

Чтобы справиться со всеми этими проблемами переносимости и сбора статистики, я разрабатывал библиотеку cxx-rtimers, доступную на Github , которая пытается предоставить простой API для блоков синхронизации кода C++, вычисляя ноль ошибок, и сообщать статистику от нескольких таймеров, встроенных в ваш код. Если у вас есть компилятор 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>. Существуют также версии этих классов таймеров, которые могут собирать статистическую информацию о времени из разных потоков. Существуют также методы, позволяющие оценить нулевую ошибку, связанную с двумя непосредственно последовательными запросами системных часов.

2
rwp

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

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

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::bind с std::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));
}

Если вы хотите быть более преднамеренным, вы также можете использовать new и delete, чтобы явно запускать и останавливать таймер, не полагаясь на то, что он сделает это за вас.

1
Kevin Kreiser

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

#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
oliora

Они одинаковы, потому что ваша функция 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));
1
kibibu

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

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

1
David Božjak

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

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

первый вопрос и пример кода показывают, что 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 секунды, что показывает, что OP изменил задачи, выполняемые двумя функциями, которые он ранее рассчитывал.

0
Weather Vane