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

StackOverflow https://stackoverflow.com/questions/588307

  •  09-09-2019
  •  | 
  •  

Вопрос

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

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

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

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

ОБНОВЛЯТЬ

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

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

Это было полезно?

Решение

Вы можете использовать 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, либо взломайте что-нибудь из Boost.DateTime, либо в песочнице есть новая предложенная библиотека - Boost.Chrono:Последний будет заменой таймера и будет включать в себя:

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

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

Я написал Timer класс, основанный на Ответ СТТ.Его можно использовать следующим образом:

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(), поскольку объяснено в этом вопросе.

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

С 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

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

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

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

В стандарте 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;

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

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); 
.....

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

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

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

В качестве обновления выяснилось, что в 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 часа, а все временные метки в некоторых сервисах зависли.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top