Используя только ANSI C, есть ли способ измерить время с точностью до миллисекунд или более? Я просматривал time.h, но нашел только функции второй точности.
c
portability
time-precision
Корто
источник
источник
Ответы:
Не существует функции ANSI C, которая обеспечивает разрешение по времени лучше 1 секунды, но функция POSIX
gettimeofday
обеспечивает разрешение в микросекундах. Функция часов только измеряет количество времени, которое процесс потратил на выполнение, и не является точной во многих системах.Вы можете использовать эту функцию так:
Это возвращается
Time elapsed: 1.000870
на мою машину.источник
timeval::tv_usec
всегда меньше одной секунды, это зацикливание. Т.е. для того, чтобы отсчитывать разницу во времени больше 1 секунды, вам необходимо:long usec_diff = (e.tv_sec - s.tv_sec)*1000000 + (e.tv_usec - s.tv_usec);
timersub
функции. Мы можем использоватьtval_result
значения (tv_sec и tv_usec) как есть.источник
CLOCKS_PER_SEC / 1000
может быть неточным, что может повлиять на конечный результат (хотя, по моему опыту,CLOCKS_PER_SEC
он всегда был кратен 1000). Выполнение(1000 * clock()) / CLOCKS_PER_SEC
менее восприимчиво к делению неточностям, но с другой стороны, более восприимчив к переполнению. Просто некоторые вопросы для рассмотрения.Я всегда использую функцию clock_gettime (), возвращающую время из часов CLOCK_MONOTONIC. Возвращаемое время - это количество времени в секундах и наносекундах, прошедшее с некоторой неопределенной точки в прошлом, такой как запуск системы эпохи.
источник
clock_gettime(CLOCK_MONOTONIC, ...)
и есть даже макрос проверки функций_POSIX_MONOTONIC_CLOCK
.Внедрение портативного решения
Поскольку здесь уже упоминалось, что не существует подходящего решения ANSI с достаточной точностью для проблемы измерения времени, я хочу написать о том, как получить портативное и, если возможно, решение для измерения времени с высоким разрешением.
Монотонные часы против отметок времени
Вообще говоря, есть два способа измерения времени:
Первый использует монотонный счетчик часов (иногда его называют счетчиком тиков), который считает такты с заранее определенной частотой, поэтому, если у вас есть значение тактов и частота известна, вы можете легко преобразовать такты в прошедшее время. Фактически не гарантируется, что монотонные часы каким-либо образом отражают текущее системное время, они также могут считать такты с момента запуска системы. Но это гарантирует, что часы всегда запускаются с возрастающей скоростью, независимо от состояния системы. Обычно частота привязана к аппаратному источнику высокого разрешения, поэтому он обеспечивает высокую точность (зависит от оборудования, но большая часть современного оборудования не имеет проблем с источниками синхросигнала с высоким разрешением).
Второй способ предоставляет значение времени (дату) на основе текущего значения системных часов. Он также может иметь высокое разрешение, но у него есть один существенный недостаток: на это значение времени могут влиять различные настройки системного времени, например, изменение часового пояса, переход на летнее время (DST), обновление сервера NTP, спящий режим системы и т. Д. на. В некоторых случаях вы можете получить отрицательное значение прошедшего времени, что может привести к неопределенному поведению. На самом деле такой источник времени менее надежен, чем первый.
Итак, первое правило при измерении временных интервалов - по возможности использовать монотонные часы. Обычно он отличается высокой точностью и надежен по конструкции.
Резервная стратегия
При реализации портативного решения стоит рассмотреть альтернативную стратегию: использовать монотонные часы, если они доступны, и подход к использованию временных меток, если в системе нет монотонных часов.
Windows
Есть отличная статья под названием Получение меток времени с высоким разрешением в MSDN об измерении времени в Windows, в которой описаны все детали, которые вам могут понадобиться знать о поддержке программного и аппаратного обеспечения. Чтобы получить высокоточную отметку времени в Windows, вам необходимо:
запросить частоту таймера (тиков в секунду) с помощью QueryPerformanceFrequency :
Частота таймера фиксируется при загрузке системы, поэтому вам нужно получить ее только один раз.
запросить текущее значение тиков с помощью QueryPerformanceCounter :
масштабируйте тики до прошедшего времени, то есть до микросекунд:
По словам Microsoft, в большинстве случаев у вас не должно возникнуть проблем с этим подходом в Windows XP и более поздних версиях. Но вы также можете использовать два запасных решения в Windows:
GetTickCount
, но она доступна начиная с Windows Vista и выше.OS X (macOS)
OS X (macOS) имеет собственные единицы абсолютного времени Маха, которые представляют собой монотонные часы. Лучший способ начать - это статья Apple Technical Q&A QA1398: Absolute Time Units, в которой описывается (с примерами кода), как использовать API, специфичный для Mach, для получения монотонных тиков. Существует также местный вопрос об этом, называемый альтернативой clock_gettime в Mac OS X, который в конце может немного запутать вас, что делать с возможным переполнением значения, потому что частота счетчика используется в форме числителя и знаменателя. Итак, небольшой пример того, как узнать истекшее время:
получить числитель и знаменатель тактовой частоты:
Вам нужно сделать это только один раз.
запросить текущее значение тика с помощью
mach_absolute_time
:масштабируйте тики до истекшего времени, то есть до микросекунд, используя ранее запрошенные числитель и знаменатель:
Основная идея предотвращения переполнения - уменьшить деления до желаемой точности перед использованием числителя и знаменателя. Поскольку начальное разрешение таймера выражено в наносекундах, мы делим его на,
1000
чтобы получить микросекунды. Вы можете найти тот же подход, что и в chromium time_mac.c . Если вам действительно нужна точность до наносекунды, подумайте о прочтении Как я могу использовать mach_absolute_time без переполнения? ,Linux и UNIX
clock_gettime
Вызов является лучшим способом на любой POSIX-дружественной системы. Он может запрашивать время из разных источников часов, и нам нужен именно тотCLOCK_MONOTONIC
. Не все системы имеютclock_gettime
поддержкуCLOCK_MONOTONIC
, поэтому первое, что вам нужно сделать, это проверить ее доступность:_POSIX_MONOTONIC_CLOCK
определено как значение,>= 0
это означает, чтоCLOCK_MONOTONIC
оно доступно;Если
_POSIX_MONOTONIC_CLOCK
для0
него определено, значит, вы должны дополнительно проверить, работает ли он во время выполнения, я предлагаю использоватьsysconf
:Использование
clock_gettime
довольно простое:получить значение времени:
Я уменьшил время до микросекунд.
рассчитать разницу с предыдущим значением времени, полученным таким же образом:
Лучшая резервная стратегия - использовать
gettimeofday
вызов: он не монотонный, но обеспечивает довольно хорошее разрешение. Идея такая же, как и сclock_gettime
, но для получения временной стоимости вам необходимо:Опять же, значение времени уменьшено до микросекунд.
SGI IRIX
У IRIX есть
clock_gettime
вызов, но его не хватаетCLOCK_MONOTONIC
. Вместо этого он имеет свой собственный источник монотонной часы определяется как ,CLOCK_SGI_CYCLE
которые вы должны использовать вместоCLOCK_MONOTONIC
сclock_gettime
.Solaris и HP-UX
Solaris имеет собственный интерфейс таймера с высоким разрешением,
gethrtime
который возвращает текущее значение таймера в наносекундах. Хотя более новые версии Solaris могут иметьclock_gettime
, вы можете придерживаться их,gethrtime
если вам нужно поддерживать старые версии Solaris.Использование простое:
HP-UX отсутствует
clock_gettime
, но он поддерживает,gethrtime
которые вы должны использовать так же, как и в Solaris.BeOS
BeOS также имеет собственный интерфейс таймера с высоким разрешением,
system_time
который возвращает количество микросекунд, прошедших с момента загрузки компьютера.Пример использования:
OS / 2
OS / 2 имеет собственный API для получения меток времени с высокой точностью:
запросить частоту таймера (тиков на единицу) с
DosTmrQueryFreq
(для компилятора GCC):запросить текущее значение тиков с помощью
DosTmrQueryTime
:масштабируйте тики до прошедшего времени, то есть до микросекунд:
Пример реализации
Вы можете взглянуть на библиотеку plibsys, которая реализует все описанные выше стратегии (подробности см. В ptimeprofiler * .c).
источник
timespec_get
: stackoverflow.com/a/36095407/895245timespec_get
не монотонный.timespec_get
из C11Возвращает значение с точностью до наносекунд, округленное до разрешения реализации.
Похоже на грабеж ANSI из POSIX '
clock_gettime
.Пример: a
printf
выполняется каждые 100 мс в Ubuntu 15.10:Проект стандарта C11 N1570 7.27.2.5 «Функция timespec_get говорит»:
C ++ 11 также получил
std::chrono::high_resolution_clock
: кроссплатформенный таймер высокого разрешения C ++.реализация в glibc 2.21
Можно найти под
sysdeps/posix/timespec_get.c
как:так ясно:
только
TIME_UTC
в настоящее время поддерживаетсяон пересылается на
__clock_gettime (CLOCK_REALTIME, ts)
POSIX API: http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.htmlВ Linux x86-64 есть
clock_gettime
системный вызов.Обратите внимание, что это не надежный метод микротестирования, потому что:
man clock_gettime
говорит, что эта мера может иметь прерывания, если вы измените некоторые настройки системного времени во время работы программы. Конечно, это должно быть редким событием, и вы можете игнорировать его.это измеряет время стены, поэтому, если планировщик решит забыть о вашей задаче, она будет работать дольше.
По этим причинам
getrusage()
может быть лучший инструмент для тестирования POSIX, несмотря на меньшую максимальную точность в микросекундах.Дополнительная информация: Измерение времени в Linux - время vs часы vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?
источник
Наилучшая точность, которую вы можете получить, - это использование инструкции "rdtsc" только для x86, которая может обеспечить разрешение на уровне часов (конечно же, при этом необходимо учитывать стоимость самого вызова rdtsc, которую можно легко измерить на запуск приложения).
Основной уловкой здесь является измерение количества тактов в секунду, что не должно быть слишком сложно.
источник
Принятый ответ достаточно хорош, но мое решение более простое. Я просто тестирую в Linux, использую gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0.
Alse использование
gettimeofday
, тоtv_sec
есть часть второй, иtv_usec
это микросекунды , а не миллисекунды .Он напечатает:
1522139691342 1522139692342
, ровно секунду.источник
Под окнами:
источник