Почему микросекундная временная метка повторяется с использованием (частной) gettimeoftheday (), т.е. эпохи

Я печатаю микросекунды непрерывно, используя gettimeofday (). Как показано в выходных данных программы, вы можете видеть, что время не является обновленным микросекундным интервалом, а повторяется для определенных выборок, а затем увеличивается не в микросекундах, а в миллисекундах.

while(1)
{
gettimeofday(&capture_time, NULL);
printf(".%ld\n", capture_time.tv_usec);
}

Выход программы:

.414719
.414719
.414719
.414719
.430344
.430344
.430344
.430344

e.t.c

Я хочу, чтобы вывод увеличивался последовательно, как,

.414719
.414720
.414721
.414722
.414723

или же

.414723, .414723+x, .414723+2x, .414723 +3x + ...+ .414723+nx

Кажется, что микросекунды не обновляются, когда я получаю его из capture_time.tv_usec.

=================================
// Полная программа

#include <iostream>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
#endif

struct timezone
{
int  tz_minuteswest; /* minutes W of Greenwich */
int  tz_dsttime;     /* type of dst correction */
};

timeval capture_time;  // structure

int gettimeofday(struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
unsigned __int64 tmpres = 0;
static int tzflag;

if (NULL != tv)
{
GetSystemTimeAsFileTime(&ft);

tmpres |= ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;

/*converting file time to unix epoch*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
tmpres /= 10;  /*convert into microseconds*/
tv->tv_sec = (long)(tmpres / 1000000UL);
tv->tv_usec = (long)(tmpres % 1000000UL);
}

if (NULL != tz)
{
if (!tzflag)
{
_tzset();
tzflag++;
}

tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
}

return 0;
}

int main()
{
while(1)
{
gettimeofday(&capture_time, NULL);
printf(".%ld\n", capture_time.tv_usec);// JUST PRINTING MICROSECONDS
}
}

2

Решение

Наблюдаемое вами изменение времени составляет от 0,414719 с до 0,430344 с. Разница составляет 15,615 мс. Тот факт, что представление числа является микросекунды, не означает, что он увеличивается на 1 микросекунду. На самом деле я бы ожидал 15,625 мс. Это приращение системного времени на стандартном оборудовании. Я внимательно посмотрел Вот а также Вот.
Это называется зернистость системного времени.

Окна:

Тем не менее, есть способ улучшить это, способ уменьшить гранулярность: Мультимедийные таймеры. В часности Получение и настройка разрешения таймера Раскроет способ увеличения частоты прерывания системы.

Код:

#define TARGET_PERIOD 1         // 1-millisecond target interrupt periodTIMECAPS tc;
UINT     wTimerRes;

if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
// this call queries the systems timer hardware capabilities
// it returns the wPeriodMin and wPeriodMax with the TIMECAPS structure
{
// Error; application can't continue.
}

// finding the minimum possible interrupt period:

wTimerRes = min(max(tc.wPeriodMin, TARGET_PERIOD ), tc.wPeriodMax);
// and setting the minimum period:

timeBeginPeriod(wTimerRes);

Это заставит систему работать с максимальной частотой прерывания. Как следствие
также обновление системного времени будет происходить чаще, а степень увеличения системного времени будет close to 1 milisecond на большинстве систем.

Когда вы заслуживаете разрешения / детализации, вы должны изучить QueryPerformanceCounter. Но это следует использовать с осторожностью при использовании в течение более длительных периодов времени. Частота этого счетчика может быть получена путем вызова QueryPerformanceFrequency. ОС считает эту частоту постоянной и будет все время давать одно и то же значение. Тем не менее, некоторые аппаратные средства производят эту частоту, и истинная частота отличается от заданного значения. Он имеет смещение и показывает тепловой дрейф. Таким образом, ошибка должна быть принята в диапазоне от нескольких до многих микросекунд / секунду. Более подробную информацию об этом можно найти во второй ссылке «здесь» выше.

Linux:

Ситуация выглядит несколько иначе для Linux. Увидеть этот чтобы получить представление. Linux
смешивает информацию о часах CMOS, используя функцию getnstimeofday (за секунды с начала эпохи) и информацию от счетчика высокой частоты (за микросекунды) с использованием функции timekeeping_get_ns. Это не тривиально и сомнительно с точки зрения точности, поскольку оба источника поддерживаются различным оборудованием. Два источника не имеют фазовой синхронизации, поэтому можно получить более менее чем один миллион микросекунд в секунду.

7

Другие решения

Системные часы Windows работают только каждые несколько миллисекунд — в вашем случае 64 раза в секунду, поэтому, когда они тикают, они увеличивают системное время на 15,625 мс.

Решение состоит в том, чтобы использовать таймер с более высоким разрешением, чем системное время (QueryPerformanceCounter).

Вы все равно не увидите .414723, .414723 + x, .414723 + 2x, .414723 + 3x + … + .414723 + nx, потому что ваш код не будет выполняться ровно один раз каждый x микросекунд. Он будет работать так быстро, как только может, но нет особой причины, по которой всегда должна быть постоянная скорость или что если это так, то это целое число микросекунд.

1

Я рекомендую вам посмотреть на C ++ 11 <chrono> заголовок.

high_resolution_clock (C ++ 11) часы с самым коротким доступным периодом тиков

тиковый период здесь упоминается частота обновления часов. Если мы посмотрим в больше деталей:

template<
class Rep,
class Period = std::ratio<1>
> class duration;

Шаблон класса std::chrono::duration представляет временной интервал.

Он состоит из количества тиков типа Rep и периода тиков, где период тика — это рациональная постоянная времени компиляции, представляющая количество секунд от одного тика до следующего.

Ранее такие функции, как gettimeofday даст вам время, выраженное в микросекундах, однако они совершенно не сообщат вам интервал обновления этого времени.

В стандарте C ++ 11 эта информация теперь ясна, чтобы было очевидно, что существует нет связи между единицей, в которой выражено время, и периодом тика. И это, следовательно, вам обязательно нужно принять во внимание оба.

поставить галочку Период чрезвычайно важен, когда вы хотите измерить длительности, близкие к нему. Если продолжительность, которую вы хотите измерить, ниже периода тика, то вы будете измерять ее «дискретно», как вы наблюдали: 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, … Я советую осторожность на этом этапе.

1

Это потому, что процесс, выполняющий ваш код, не всегда запланирован для выполнения.

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

Затем существуют периоды, когда система не планирует его выполнение и, следовательно, не может печатать значения.

Если вы хотите выполнять каждую микросекунду, это может быть возможно с некоторыми операционными системами реального времени, работающими на высокопроизводительном оборудовании.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector