Windows API: получите микросекунды между миллисекундами - PullRequest
1 голос
/ 21 сентября 2019

GetSystemTimePreciseAsFileTime: извлекает текущую системную дату и время с максимально возможным уровнем точности (<1us).</p>

Что дает нам FILETIME

Затем мы передаем его в: FileTimeToSystemTime, который дает нам SYSTEMTIME

Но SYSTEMTIME показывает нам с точностью до миллисекунды.

typedef struct _SYSTEMTIME {
  WORD wYear;
  WORD wMonth;
  WORD wDayOfWeek;
  WORD wDay;
  WORD wHour;
  WORD wMinute;
  WORD wSecond;
  WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;

Итак, как мне добраться до (<1us) части?Я хочу иметь возможность напечатать что-то вроде </p>

printf( "milli:[%u] micro:[%u] nano:[%u]\n", 
         st.wMilliseconds, st.wMicro, st.Nano );

Спасибо

Я пробовал следующее:

int main()
{
    FILETIME ft = { 0 };
    SYSTEMTIME st = { 0 };

    UINT32 nsT = 0;
    UINT32 us = 0;
    UINT32 ns = 0;

    for (int i = 0; i < 32; i++)
    {

        GetSystemTimePreciseAsFileTime(&ft);

        FileTimeToSystemTime(&ft, &st);

        nsT = (ft.dwLowDateTime & 0x0FFFFFFFFLL) | (ft.dwHighDateTime << 32LL);

        us = (nsT % 10000LL) / 10LL;
        ns = (nsT % 10LL);

        wprintf(L"DT:[%u%02u%02u %02u:%02u:%02u:%03u:%03u:%u]\n",
            st.wYear, st.wMonth, st.wDay,
            st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, us, ns);
    }
}

Однако это приводит к выходам из строя

DT:[20190921 12:48:51:152:735:4]
DT:[20190921 12:48:51:164:561:4]
DT:[20190921 12:48:51:169:126:3]
DT:[20190921 12:48:51:172:595:0]
DT:[20190921 12:48:51:173:428:7]
DT:[20190921 12:48:51:173:415:9]
DT:[20190921 12:48:51:177:446:2]
DT:[20190921 12:48:51:181:309:8]
DT:[20190921 12:48:51:182:386:7]
DT:[20190921 12:48:51:184:650:6]
DT:[20190921 12:48:51:184:740:6]
DT:[20190921 12:48:51:189:271:8]
DT:[20190921 12:48:51:190:471:4]
DT:[20190921 12:48:51:194:746:6]
DT:[20190921 12:48:51:197:049:5]
DT:[20190921 12:48:51:198:793:4]
DT:[20190921 12:48:51:200:823:4]
DT:[20190921 12:48:51:200:529:1]
DT:[20190921 12:48:51:202:606:3]
DT:[20190921 12:48:51:210:913:4]
DT:[20190921 12:48:51:214:764:6]
DT:[20190921 12:48:51:214:815:4]
DT:[20190921 12:48:51:219:079:4]
DT:[20190921 12:48:51:222:580:2]
DT:[20190921 12:48:51:223:959:5]
DT:[20190921 12:48:51:224:933:8]
DT:[20190921 12:48:51:225:844:7]
DT:[20190921 12:48:51:226:810:7]
DT:[20190921 12:48:51:228:811:1]
DT:[20190921 12:48:51:230:139:1]
DT:[20190921 12:48:51:253:539:1]
DT:[20190921 12:48:51:253:653:9]

Обратите внимание на следующее для данной милли (173), у нас есть нисходящие микро (428 до 415). 415 должен быть больше, чем 428.

DT:[20190921 12:48:51:173:428:7]
DT:[20190921 12:48:51:173:415:9]

DT:[20190921 12:48:51:200:823:4]
DT:[20190921 12:48:51:200:529:1]

Я тогда выбежалстроку в глобальный массив и напечатал ее в последующем цикле, чтобы убедиться, что нет условия гонки stdout, но он все еще не в порядке в более мелком масштабе:

DT:[20190921 13:05:01:228:534:1]
DT:[20190921 13:05:01:228:534:3]
DT:[20190921 13:05:01:228:534:3]
DT:[20190921 13:05:01:228:534:1]
DT:[20190921 13:05:01:228:534:3]
DT:[20190921 13:05:01:228:534:1]
DT:[20190921 13:05:01:228:534:3]

Если я добавлю некоторый код для сравненияРассчитанные миллисекунды против ST.wMilliseconds мы видим несоответствия:

ms:[140][0x8C] != st.wMilliseconds:[177][0xB1]
ms:[284][0x11C] != st.wMilliseconds:[184][0xB8]
ms:[337][0x151] != st.wMilliseconds:[236][0xEC]

Следующий код, кажется, работает отлично благодаря Адриану:

int main()
{
    WCHAR b[MAX][256] = { 0 };

    FILETIME ft = { 0 };
    SYSTEMTIME st = { 0 };

    UINT64 ftLo = 0;
    UINT64 ftHi = 0;
    UINT64 myTime = 0;
    UINT64 ms = 0;
    UINT64 us = 0;
    UINT64 ns = 0;

    for (int i = 0; i < MAX; i++)
    {
        GetSystemTimePreciseAsFileTime(&ft);

        FileTimeToSystemTime(&ft, &st);

        ftLo = ft.dwLowDateTime;
        ftHi = ft.dwHighDateTime;
        myTime = ftLo | (ftHi << 32uLL);

        ms = (myTime % 10000000uLL) / 10000uLL;
        us = (myTime % 10000uLL) / 10uLL;
        ns = (myTime % 10uLL);

        if (ms != st.wMilliseconds)
            wprintf(L"ms:[%llu][0x%llX] != st.wMilliseconds:[%u][0x%X]\n",
                    ms, ms, st.wMilliseconds, st.wMilliseconds);

        wprintf(L"%u%02u%02u %02u:%02u:%02u:%03llu:%03llu:%llu\n",
            st.wYear, st.wMonth, st.wDay,
            st.wHour, st.wMinute, st.wSecond,
            ms, us, ns);


    }

    return 0;
}

Результаты:

20190922 10:51:20:625:917:4
20190922 10:51:20:626:065:5
20190922 10:51:20:628:774:2
20190922 10:51:20:631:084:5
20190922 10:51:20:631:628:4
20190922 10:51:20:632:223:0
20190922 10:51:20:635:252:7
20190922 10:51:20:637:841:8
20190922 10:51:20:641:058:9
20190922 10:51:20:649:869:0
20190922 10:51:20:651:283:0
20190922 10:51:20:652:677:9
20190922 10:51:20:652:749:7
20190922 10:51:20:652:808:6
20190922 10:51:20:654:621:0
20190922 10:51:20:656:662:3
20190922 10:51:20:659:048:9
20190922 10:51:20:660:926:0
20190922 10:51:20:664:202:1
20190922 10:51:20:666:506:9
20190922 10:51:20:666:592:6
20190922 10:51:20:666:712:8
20190922 10:51:20:670:800:7
20190922 10:51:20:680:442:7
20190922 10:51:20:680:522:0
20190922 10:51:20:681:207:1
20190922 10:51:20:682:988:3
20190922 10:51:20:684:476:8
20190922 10:51:20:685:727:1
20190922 10:51:20:685:777:0
20190922 10:51:20:686:526:3
20190922 10:51:20:686:919:9

1 Ответ

0 голосов
/ 21 сентября 2019

Вы не можете сделать это, используя структуру SYSTEMTIME, как вы заметили.Вам нужно извлечь данные из возвращенной структуры FILETIME и обработать их как 64-разрядное целое число:

FILETIME fTime;
GetSystemTimePreciseAsFileTime(&fTime);
uint64_t ftLo = uint64_t(fTime.dwLowDateTime);
uint64_t ftHi = uint64_t(fTime.dwHighDateTime);
uint64_t myTime = ftLo | (ftHi << 32uLL);

Переменная myTime будет содержать число интервалов в 100 наносекунд с 01 января.-1601.

Чтобы перейти от значения 'epoch' к 'пропущенным' полям us и ns в SYSTEMTIME, вы можете просто использовать приведенный ниже код.Вы также должны получить свое собственное значение в миллисекундах, если преобразование в SYSTEMTIME «округлило» значение dwMilliseconds (не знаю, происходит ли это или нет):

uint64_t millis = (myTime % 10000000uLL) / 10000uLL;
uint64_t micros = (myTime % 10000uLL) / 10uLL;
uint64_t nanos = (myTime % 10uLL) * 100uLL; // Will have a resolution of only 100ns

(Это работает при условии, что все дни, начиная с 01.01.1601, имели целое число миллисекунд, что я считаю разумным предположением!)

ПРИМЕЧАНИЕ. Другой вариант - скопировать(или приведение) структуры FILETIME к ULARGE_INTEGER, а затем присвойте элемент QuadPart этого объединения к myTime.Это будет также работать, но, в стандарте C ++, запись в одну часть объединения и затем чтение из другой формально - неопределенное поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...