2016-02-24 8 views
2

Я использую функцию QueryPerformanceCounter() для измерения времени в моем приложении. Эта функция также используется для того, чтобы предоставить временную линию моего срока службы. Недавно я заметил, что существует дрейф времени относительно других временных функций. Наконец, я написал небольшой тест, чтобы проверить, является ли дрейф реальным или нет. (Я использую VS2013 компилятор)Окно временного дрейфа performancecounter C++

#include <Windows.h> 
    #include <chrono> 
    #include <thread> 
    #include <cstdio> 

    static LARGE_INTEGER s_freq; 

    using namespace std::chrono; 

    inline double now_WinPerfCounter() 
    { 
     LARGE_INTEGER tt; 
     if (TRUE != ::QueryPerformanceCounter(&tt)) 
     { 
      printf("Error in QueryPerformanceCounter() - Err=%d\n", GetLastError()); 
      return -1.; 
     } 
     return (double)tt.QuadPart/s_freq.QuadPart; 
    } 

    inline double now_WinTick64() 
    { 
     return (double)GetTickCount64()/1000.; 
    } 

    inline double now_WinFileTime() 
    { 
     FILETIME ft; 
     ::GetSystemTimeAsFileTime(&ft); 

     long long * pVal = reinterpret_cast<long long *>(&ft); 

     return (double)(*pVal)/10000000. - 11644473600LL; 
    } 


    int _tmain(int argc, _TCHAR* argv[]) 
    { 
     if (TRUE != ::QueryPerformanceFrequency(&s_freq)) 
     { 
      printf("Error in QueryPerformanceFrequency() - Err=#d\n", GetLastError()); 
      return -1; 
     } 

     // save all timetags at the beginning 
     double t1_0 = now_WinPerfCounter(); 
     double t2_0 = now_WinTick64(); 
     double t3_0 = now_WinFileTime(); 
     steady_clock::time_point t4_0 = steady_clock::now(); 

     for (int i = 0;; ++i) // forever 
     { 
      double t1 = now_WinPerfCounter(); 
      double t2 = now_WinTick64(); 
      double t3 = now_WinFileTime(); 
      steady_clock::time_point t4 = steady_clock::now(); 

      printf("%03d\t %.3lf %.3lf %.3lf %.3lf \n", 
      i, 
      t1 - t1_0, 
      t2 - t2_0, 
      t3 - t3_0, 
      duration_cast<nanoseconds>(t4 - t4_0).count() * 1.e-9 
      ); 

      std::this_thread::sleep_for(std::chrono::seconds(10)); 
     } 
    return 0; 
    } 

Выход был, запутанным:

000  0.000 0.000 0.000 0.000 
    ... 
    001  10.001 10.000 10.002 10.002 
    ... 
    015  150.006 150.010 150.010 150.010 
    ... 
    024  240.009 240.007 240.015 240.015 
    ... 
    025  250.010 250.007 250.015 250.015 
    ... 
    026  260.010 260.007 260.016 260.016 
    ... 
    070  700.027 700.039 700.041 700.041 

Почему есть разница? Похоже, что одна секунда не одинакова при использовании разных функций API? Кроме того, в течение дня разница не постоянна ...

+0

Ниже я приведу дополнительную информацию. Однако не могли бы вы рассказать о стоимости вашей частотной частоты ** (s_freq.QuadPart) **. Это число позволило бы дать более глубокое понимание, поскольку оно раскрывает информацию о вашей платформе. – Arno

+0

Привет @Arno, s_freq.QuadPart равна 3507568 –

+0

3,6 ГГц платформа? – Arno

ответ

1

Edit: Основной причиной дрейфа вы наблюдаете неточность счетчика частоты производительности. Система предоставляет вам постоянное значение, возвращаемое QueryPerformanceFrequency. Эта постоянная частота составляет только вблизи истинной частоты. Он сопровождается смещением и возможным дрифтом. Современные платформы (Windows> 7, инвариантные TSC) имеют небольшое смещение и небольшой дрейф.

Пример: смещение 5 ppm приведет к тому, что время будет двигаться вперед на 5 us/s или 432 ms/day быстрее, чем ожидалось, если вы используете частоту счетчика производительности для масштабирования значений счетчика производительности до времени.

Общие сведения: QueryPerformanceCounter и GetSystemTimeAsFileTime используют разные ресурсы (оборудование). Современные платформы получают QueryPerformanceCounter из счетчика временных меток ЦП (TSC) и GetSystemTimeAsFileTime, используя таймер PIT, таймер ACPI PM или аппаратное обеспечение HPET. См. Intel 64® and IA-32 Architectures Software Developer's Manual, Volume 3B: System Programming Guide, Part 2. Невозможно иметь дело с дрейфом, когда два API используют разные аппаратные средства. Однако вы можете расширить свой тестовый код для калибровки дрейфа. Аппаратура с частотным генератором, как правило, чувствительна к температуре. Поэтому дрейф может варьироваться в зависимости от нагрузки. См. The Windows Timestamp Project.

2

Это обычные, доступные часы никогда не имеют бесконечной точности. GetSystemTime() и GetTickCount() периодически откалиброваны с сервера времени Интернета, time.windows.com по умолчанию. Который использует недоступные атомные часы для поддержания времени. Корректировки, чтобы наверстать упущенное или замедлить, являются постепенными, чтобы не давать программному обеспечению сердечный приступ. Время, которое они сообщают, будет отключено от вращения Земли не более чем на несколько секунд, периодическая повторная калибровка ограничивает долговременную ошибку дрейфа.

Но QPF не откалиброван, его разрешение слишком велико, чтобы такие регулировки не влияли на измерения коротких интервалов, для которых обычно используются. Он получен из источника частоты, доступного на чипсете, выбранного системным застройщиком. В зависимости от типичных допусков на электронные детали температура, в частности, влияет на точность и вызывает переменный дрейф в течение более длительных периодов времени. Поэтому QPF подходит только для измерения относительно коротких интервалов.

Неизменно оба часа могут быть не такими же, и вы будет см. Их разброс. Вы должны выбрать тот или другой, который будет «главными» часами. Если важна долгосрочная точность, вам придется выбирать калиброванный источник, если важно высокое разрешение, но не точность, а затем QPF. Если оба важны, вам нужно специальное оборудование, например, часы GPS.

0

Возможно, разные функции измеряют время по-разному.

QueryPerformanceCounter - это временные метки высокого разрешения или временные интервалы измерений.

GetSystemTimeAsFileTime - извлекает текущую системную дату и время в формате UTC.

Таким образом, это не совсем правильно, чтобы использовать эти функции и сравнивать время с ними.

+0

Хорошо, я сравниваю в миллисекунговом разрешении. Поэтому я считаю, что дрифт 2 миллисекунда в течение 10 секунд слишком много –

+0

Это не так много, нет, и по умолчанию системное разрешение часов в Windows составляет 15 мс, поэтому вы находитесь ниже этого допуска ... – galinette

+0

Ну, через пару часов дрифт больше 1 секунды, для моего приложения это не вариант. –

0

Возможно, это плохая идея использовать несколько методов измерения; разные функции имеют разные разрешения, вы эффективно увидите шум от значений, округленных до их точности. И, конечно, небольшое количество времени пройдет при установке t1..t4, поскольку функции требуют времени для выполнения, поэтому дрейф неизбежен.

+0

Ну, я согласен, что это плохая идея. Именно поэтому я хочу выбрать один метод. Я использовал QPF, но при работе в течение целого дня он имел дрейф более 1 секунды. Это не вариант в моем приложении. –

+0

Я также отмечаю, что вы используете спящий режим в цикле - не уверен, что это затуманенный пример или как выполняется реальный код - это может вызвать дрейф - события (или даже прерывания, если приложение требует/поддерживает его) чтобы быть путем. –

+0

Сон предназначен только для этого теста. У меня нет никакого реального смысла. Я просто хотел напечатать один раз за период (который не должен быть постоянным). Печатный diff касается времени = 0. –

0

Возможно, вы захотите ознакомиться с API GetSystemTimePreciseAsFileTime. Он является высокоточным и может периодически настраиваться с внешних серверов времени.

+0

Спасибо, но я не могу предположить, что он работает на Win8 или выше ОС –

 Смежные вопросы

  • Нет связанных вопросов^_^