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

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

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

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

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

UPDATE

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

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

Ответ 1

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

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

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

Ответ 12

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, у вас будет низкая точность, когда ваш процесс усердно работает.

Ответ 13

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

Ответ 14

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

Ответ 15

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

Ответ 16

Я написал класс 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() из-за многозадачности.