C++ получает время в миллисекундах в Linux - часы () не работают должным образом

В Windows clock() возвращает время в миллисекундах, но в этом окне Linux, над которым я работаю, оно округляется до ближайшей 1000, поэтому точность равна только "второму" уровню, а не уровню миллисекунд.

Я нашел решение с помощью Qt, используя QTime класс, создание объекта и вызов start() на это тогда звоню elapsed() чтобы получить количество прошедших миллисекунд.

Мне повезло, потому что я с самого начала работаю с Qt, но я бы хотел решение, которое не зависит от сторонних библиотек,

Нет ли стандартного способа сделать это?

ОБНОВИТЬ

Пожалуйста, не рекомендую Boost ..

Если Boost и Qt могут это сделать, конечно, это не волшебство, должно быть что-то стандартное, что они используют!

16 ответов

Решение

Вы можете использовать gettimeofday в начале и в конце вашего метода, а затем различать две структуры возврата. Вы получите структуру, подобную следующей:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    struct timeval start, end;

    long mtime, seconds, useconds;    

    gettimeofday(&start, NULL);
    usleep(2000);
    gettimeofday(&end, NULL);

    seconds  = end.tv_sec  - start.tv_sec;
    useconds = end.tv_usec - start.tv_usec;

    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;

    printf("Elapsed time: %ld milliseconds\n", mtime);

    return 0;
}

Обратите внимание, что clock не измеряет время настенных часов. Это означает, что если ваша программа занимает 5 секунд, clock не обязательно будет измерять 5 секунд, но может быть больше (ваша программа может запускать несколько потоков и, следовательно, может потреблять больше ресурсов ЦП, чем в реальном времени) или меньше. Он измеряет приблизительное время процессора. Чтобы увидеть разницу, рассмотрите этот код

#include <iostream>
#include <ctime>
#include <unistd.h>

int main() {
    std::clock_t a = std::clock();
    sleep(5); // sleep 5s
    std::clock_t b = std::clock();

    std::cout << "difference: " << (b - a) << std::endl;
    return 0;
}

Это выводит на мою систему

$ difference: 0

Потому что все, что мы делали, это спали и не использовали процессорное время! Однако, используя gettimeofday мы получаем то, что хотим (?)

#include <iostream>
#include <ctime>
#include <unistd.h>
#include <sys/time.h>

int main() {
    timeval a;
    timeval b;

    gettimeofday(&a, 0);
    sleep(5); // sleep 5s
    gettimeofday(&b, 0);

    std::cout << "difference: " << (b.tv_sec - a.tv_sec) << std::endl;
    return 0;
}

Выходы в моей системе

$ difference: 5

Если вам нужна большая точность, но вы хотите получить процессорное время, то вы можете использовать getrusage функция.

Я также рекомендую инструменты, предлагаемые Boost. Либо упомянутый Boost Timer, либо взломайте что-нибудь из Boost.DateTime, либо есть новая предлагаемая библиотека в песочнице - Boost.Chrono: эта последняя будет заменой для Timer и будет содержать:

  • Утилиты времени стандартной библиотеки C++0x, в том числе:
    • Шаблон класса duration
    • Шаблон класса time_point
    • Часы:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • Шаблон класса timerс помощью typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • Процессные часы и таймеры:
    • process_clock, захват реального, пользовательского и системного времени процессора.
    • process_timer, фиксируя истекшее реальное, пользовательское и системное время.
    • run_timer, удобная отчетность |process_timer| Результаты.
  • Рациональная арифметика времени компиляции стандартной библиотеки C++0x.

Вот источник списка возможностей

Я написал Timer класс на основе ответа CTT. Его можно использовать следующим образом:

Timer timer = Timer();
timer.start();
/* perform task */
double duration = timer.stop();
timer.printTime(duration);

Вот его реализация:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
using namespace std;

class Timer {
private:

    timeval startTime;

public:

    void start(){
        gettimeofday(&startTime, NULL);
    }

    double stop(){
        timeval endTime;
        long seconds, useconds;
        double duration;

        gettimeofday(&endTime, NULL);

        seconds  = endTime.tv_sec  - startTime.tv_sec;
        useconds = endTime.tv_usec - startTime.tv_usec;

        duration = seconds + useconds/1000000.0;

        return duration;
    }

    static void printTime(double duration){
        printf("%5.6f seconds\n", duration);
    }
};

Если вам не нужен код для переноса на старые устройства, вы можете использовать clock_gettime(), который даст вам время в наносекундах (если ваш процессор поддерживает это разрешение). Это POSIX, но с 2001 года.

Clock() имеет довольно паршивое разрешение. Если вы хотите измерить время на миллисекундном уровне, одной из альтернатив является использование clock_gettime(), как описано в этом вопросе.

(Помните, что вам нужно связать с -lrt в Linux).

С С ++11 и std::chrono::high_resolution_clock вы можете сделать это:

#include <iostream>
#include <chrono>
#include <thread>
typedef std::chrono::high_resolution_clock Clock;

int main()
{
    std::chrono::milliseconds three_milliseconds{3};

    auto t1 = Clock::now();
    std::this_thread::sleep_for(three_milliseconds);
    auto t2 = Clock::now();

    std::cout << "Delta t2-t1: " 
              << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count()
              << " milliseconds" << std::endl;
}

Выход:

Delta t2-t1: 3 milliseconds

Ссылка на демо: http://cpp.sh/2zdtu

Это должно работать... проверено на Mac...

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

int main() {
        struct timeval tv;
        struct timezone tz;
        struct tm *tm;
        gettimeofday(&tv,&tz);
        tm=localtime(&tv.tv_sec);
        printf("StartTime: %d:%02d:%02d %d \n", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec);
}

Да... запустить его дважды и вычесть...

clock() не возвращает миллисекунды или секунды в Linux. Обычно clock() возвращает микросекунды в системе Linux. Правильный способ интерпретации значения, возвращаемого функцией clock(), - это разделить его на CLOCKS_PER_SEC, чтобы выяснить, сколько времени прошло.

В стандарте POSIX clock его возвращаемое значение определено в терминах символа CLOCKS_PER_SEC, и реализация может определять его любым удобным способом. Под Linux мне повезло с times() функция.

gettimeofday - проблема в том, что могут иметь более низкие значения, если вы меняете аппаратные часы (например, с помощью NTP). Boost - недоступно для этого проекта clock() - обычно возвращает 4-байтовое целое число, что означает, что он имеет малую емкость, и через некоторое время он возвращает отрицательные числа.

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

class MyAlarm {
static int64_t tiempo;
static bool running;
public:
static int64_t getTime() {return tiempo;};
static void callback( int sig){
    if(running){
        tiempo+=10L;
    }
}
static void run(){ running = true;}
};

int64_t MyAlarm::tiempo = 0L;
bool MyAlarm::running = false;

чтобы обновить его, я использую setitimer:

int main(){
struct sigaction sa; 
struct itimerval timer; 

MyAlarm::run();
memset (&sa, 0, sizeof (sa)); 
sa.sa_handler = &MyAlarm::callback; 

sigaction (SIGALRM, &sa, NULL); 


timer.it_value.tv_sec = 0; 
timer.it_value.tv_usec = 10000; 



timer.it_interval.tv_sec = 0; 
timer.it_interval.tv_usec = 10000; 


setitimer (ITIMER_REAL, &timer, NULL); 
.....

Посмотрите на setitimer и ITIMER_VIRTUAL и ITIMER_REAL.

Не используйте функции будильника или ualarm, у вас будет низкая точность, когда ваш процесс получит тяжелую работу.

В качестве обновления отображается, что в windows clock() измеряет время настенных часов (с точностью CLOCKS_PER_SEC)

 http://msdn.microsoft.com/en-us/library/4e2ess30(VS.71).aspx

в то время как в Linux он измеряет время процессора между ядрами, используемыми текущим процессом

http://www.manpagez.com/man/3/clock

и (кажется, и как отметил оригинальный автор) на самом деле с меньшей точностью, чем CLOCKS_PER_SEC, хотя, возможно, это зависит от конкретной версии Linux.

Мне нравится метод Hola Soy, не использующий gettimeofday(). Это случилось со мной на работающем сервере, администратор изменил часовой пояс. Часы были обновлены, чтобы показать то же (правильное) локальное значение. Это привело к сдвигу функций time () и gettimeofday () на 2 часа, и все метки времени в некоторых службах зависли.

Я предпочитаю библиотеку Boost Timer за ее простоту, но если вы не хотите использовать библиотеки третьих сторон, использование clock() кажется разумным.

Я написал C++ класс с использованием timeb,

#include <sys/timeb.h>
class msTimer 
{
public:
    msTimer();
    void restart();
    float elapsedMs();
private:
    timeb t_start;
};

Функции-члены:

msTimer::msTimer() 
{ 
    restart(); 
}

void msTimer::restart() 
{ 
    ftime(&t_start); 
}

float msTimer::elapsedMs() 
{
    timeb t_now;
    ftime(&t_now);
    return (float)(t_now.time - t_start.time) * 1000.0f +
           (float)(t_now.millitm - t_start.millitm);
}

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

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char** argv) 
{
    msTimer t;
    for (int i = 0; i < 5000000; i++)
        ;
    std::cout << t.elapsedMs() << endl;
    return 0;
}

Вывод на моем компьютере "19". Точность msTimer класс порядка миллисекунд. В приведенном выше примере использования общее время выполнения, занятое forпетля отслеживается. На этот раз операционная система включала и выключала контекст выполнения main() из-за многозадачности.

Другие вопросы по тегам