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