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


102

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

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

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

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

ОБНОВИТЬ

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

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


2
Насчет редактирования - но делать это портативным способом - это немного больно.
Anonymous,

Ответы:


37

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

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

РЕДАКТИРОВАТЬ: Как показывают два комментария ниже, clock_gettime (CLOCK_MONOTONIC) - гораздо лучший выбор, если он у вас есть, что в наши дни должно быть почти везде.

РЕДАКТИРОВАТЬ: кто-то еще прокомментировал, что вы также можете использовать современный C ++ с std :: chrono :: high_resolution_clock, но это не гарантирует монотонность. Вместо этого используйте stable_clock.


38
ужасно для серьезной работы. Большие проблемы дважды в год, когда кто-то делает свидания и, конечно, синхронизацию NTP. Use clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@AndrewStone: UNIX-время не меняется дважды в год. Или даже раз в год. Но да, CLOCK_MONOTONICон отлично подходит для того, чтобы избежать локальной корректировки системного времени.
Гонки легкости на орбите

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

4
Почему вы добавляете +0,5 к разнице?
Махмуд Аль-Кудси

19
@Computer Guru, это распространенный метод округления положительных значений. Когда значение усекается до целочисленного значения, любое значение от 0,0 до 0,4999 ... до того, как добавление будет усечено до 0, и между 0,5 и 0,9999 ... будет усечено до 1.
Марк Рэнсом

8
tv_usec - это не миллисекунды, а микросекунды.
NebulaFox

13
ужасно для серьезной работы. Большие проблемы дважды в год, когда кто-то делает свидания, и, конечно же, синхронизация NTP
AndrewStone

14
@AndrewStone прав, используйте clock_gettime (2) с CLOCK_REALTIME для сравнения времени на одном компьютере. Из gettimeofday (2) страница руководства: POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT, могли бы вы обновить пример, изменяя struct timevalк struct timespec, и gettimeofday(&start, NULL)для clock_gettime(CLOCK_MONOTONIC, &start)того , чтобы люди не столкнулись с проблемами?
Бобби Пауэрс

58

Обратите внимание, что 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функции.


⁺¹ по поводу упоминания sleep()- я уже думал задать вопрос (почему он работает нормально у всех, кроме меня ?!) , когда нашел ваш ответ.
Hi-Angel

18

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

  • Утилиты времени стандартной библиотеки 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.

Вот источник списка функций


На данный момент вы можете использовать таймер ускорения, а затем аккуратно перейти на Chrono, когда он будет рассмотрен / принят.
Anonymous,

13

Я написал 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);
    }
};

2
Это круто, но «nseconds» вводит в заблуждение, потому что timeval не содержит наносекунды, а содержит микросекунды, поэтому я бы посоветовал людям называть это «useconds».
pho0

Спасибо. Исправление сделано.
Крис Редфорд

9

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


4

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

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


4

С C ++ 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


2

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


нет в коробке, над которой я работаю! плюс, я имею деля CLOCKS_PER_SEC, но это бессмысленно , потому что разрешение только до второй
HASEN

честно говоря, единицы измерения - микросекунды (CLOCKS_PER_SEC - 1000000 во всех системах POSIX). Просто имеет секундное разрешение. :-П.
Эван Теран,

1

Это должно работать ... проверено на 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);
}

Ага ... прогони дважды и вычти ...


1

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


1

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.

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



0

В качестве обновления появляется, что в 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.


0

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


0

Я написал 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отслеживается общее время выполнения, занимаемое -loop. На этот раз операционная система включала и выключала контекст выполнения из- main()за многозадачности.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.