C ++ высокая точность измерения времени в Windows - PullRequest
30 голосов
/ 01 декабря 2009

Я заинтересован в измерении определенного момента времени вплоть до наносекунды с использованием C ++ в Windows. Это возможно? Если это не так, возможно ли получить определенное время в микросекундах хотя бы? Любая библиотека должна делать, если я не думаю, что это возможно с управляемым кодом. спасибо

Ответы [ 14 ]

34 голосов
/ 01 декабря 2009

Если у вас есть многопоточное приложение, работающее на многоядерном компьютере, QueryPerformanceCounter может (и будет) возвращать различные значения в зависимости от того, на каком ядре выполняется код. См. эту статью MSDN. (rdtsc имеет ту же проблему)

Это не просто теоретическая проблема; мы столкнулись с этим в нашем приложении и пришли к выводу, что единственным надежным источником времени является timeGetTime, который имеет только мс точность (что, к счастью, было достаточно в нашем случае). Мы также попытались зафиксировать сродство потоков к нашим потокам, чтобы гарантировать, что каждый поток всегда получал согласованное значение от QueryPerformanceCounter, это работало, но абсолютно убивало производительность в приложении.

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

14 голосов
/ 01 декабря 2009

Windows имеет высокопроизводительный счетчик API .

Вам необходимо получить форму тиков QueryPerformanceCounter и поделить на частоту процессора, предоставленную QueryPerformanceFrequency.

LARGE_INTEGER frequency;
if (::QueryPerformanceFrequency(&frequency) == FALSE)
    throw "foo";

LARGE_INTEGER start;
if (::QueryPerformanceCounter(&start) == FALSE)
    throw "foo";

// Calculation.


LARGE_INTEGER end;
if (::QueryPerformanceCounter(&end) == FALSE)
    throw "foo";

double interval = static_cast<double>(end.QuadPart - start.QuadPart) / frequency.QuadPart;

Это interval должно быть в секундах.

6 голосов
/ 10 апреля 2011

Для дальнейшего использования в Windows Vista, 2008 и более поздних версиях Windows требуется аппаратная поддержка «HPET». Это работает независимо от процессора и его тактовой частоты и частоты. Можно получить время с точностью до микросекунды.

Для реализации этого вам НЕОБХОДИМО использовать QPC / QPF. Проблема в том, что QPF (частота) является НОМИНАЛЬНЫМ значением, поэтому использование необработанных вызовов вызовет смещение времени, которое может превышать минуты в день. Чтобы учесть это, вы должны измерить фактическую частоту и проверить ее дрейф с течением времени, так как это повлияет на тепло и другие физические условия работы.

Статья, которая описывает это, может быть найдена на MSDN (приблизительно 2004!) По этой ссылке. http://msdn.microsoft.com/en-us/magazine/cc163996.aspx

Я сам реализовал нечто похожее на это (и только что нашел вышеупомянутую ссылку сегодня!), Но предпочитаю не использовать «микросекундное время», потому что сам вызов QPC довольно длительный по сравнению с другими вызовами Windows, такими как GetSystemTimeAsFileTime, и добавление синхронизации больше накладных расходов. Поэтому я предпочитаю использовать метки времени в миллисекундах (примерно на 70% меньше времени вызова, чем при использовании QPC), особенно когда я пытаюсь получить время сотни тысяч раз в секунду.

5 голосов
/ 10 апреля 2014

Лучшим выбором являются функции QueryPerformanceCounter и QueryPerformanceFrequency.

Microsoft недавно (2014 г.) выпустила более подробную информацию о QueryPerformanceCounter:

Подробнее см. Получение меток времени с высоким разрешением (MSDN 2014).

Это всеобъемлющая статья с множеством примеров и подробным описанием. Необходимо прочитать для пользователей QPC.

3 голосов
/ 05 августа 2016

Я думаю, что микросекунды немного неразумно (без помощи оборудования). Миллисекунды выполнимы, но даже тогда они не настолько точны из-за различных гнусных проблем со встречным разрешением. Несмотря на это, я включаю свой собственный класс таймера (на основе std :: chrono) для вашего рассмотрения:

#include <type_traits>
#include <chrono>


class Stopwatch final
{
public:

    using elapsed_resolution = std::chrono::milliseconds;

    Stopwatch()
    {
        Reset();
    }

    void Reset()
    {
        reset_time = clock.now();
    }

    elapsed_resolution Elapsed()
    {
        return std::chrono::duration_cast<elapsed_resolution>(clock.now() - reset_time);
    }

private:

    std::chrono::high_resolution_clock clock;
    std::chrono::high_resolution_clock::time_point reset_time;
};

Обратите внимание, что под Windows в std :: chrono :: high_resolution_clock используется QueryPerformanceCounter, поэтому он такой же, но переносимый.

3 голосов
/ 10 января 2014

MSDN утверждает, что -

Объект Scenario - это высокоточный таймер, который регистрирует события ETW. (Трассировка событий для Windows) при запуске и остановке. Это разработано использоваться для измерения производительности и бенчмаркинга в версиях C # и C ++. ... как правило на современном аппаратное обеспечение, вызов Begin () или End () принимает порядок микросекунды, и полученные временные метки с точностью до 100 нс (т.е. 0,1 микросекунды). ... Версии доступны как для .NET 3.5 (написано на C #), так и для собственного C ++, и работают как на x86, так и на x64 платформ. Класс Scenario был изначально разработан с использованием Visual Studio 2008, но теперь ориентирован на разработчиков, использующих Visual Studio 2010].

С Домашняя страница сценария . Насколько я знаю, его предоставили те же люди, что и PPL.

Вы можете прочитать это Часы и таймеры с высоким разрешением для измерения производительности в Windows .

2 голосов
/ 12 мая 2014

В новых версиях Windows вы, вероятно, хотите GetSystemTimePreciseAsFileTime. См. Получение меток времени с высоким разрешением .

Многое из этого варьируется довольно неудачно в зависимости от аппаратного обеспечения и версии ОС.

1 голос
/ 20 октября 2015

Если вы можете использовать компилятор Visual Studio 2012 или выше, вы вполне можете использовать стандартную библиотеку std :: chrono .

#include <chrono>

::std::chrono::steady_clock::time_point time = std::chrono::steady_clock::now();

Обратите внимание, что версия MSVC 2012 может иметь точность только 1 мс . Более новые версии должны быть с точностью до микросекунды.

1 голос
/ 01 декабря 2009

Вы можете использовать API счетчика производительности, как предложил Конрад Рудольф, но следует предупредить, что он основан на частоте процессора. Эта частота не стабильна, например, когда режим энергосбережения включен. Если вы хотите использовать этот API, убедитесь, что процессор работает с постоянной частотой.

В противном случае вы можете создать некую «статистическую» систему, соотносящую такты процессора с тактовой частотой BIOS компьютера. Последний способ менее точен, но постоянен.

0 голосов
/ 03 декабря 2009

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

    class N_Script_Timer
{
    public:
        N_Script_Timer()
        {
            running = false;
            milliseconds = 0;
            seconds = 0;
            start_t = 0;
            end_t = 0;
        }
        void Start()
        {
            if(running)return;
            running = true;
            start_t = timeGetTime();
        }
        void End()
        {
            if(!running)return;
            running = false;
            end_t = timeGetTime();
            milliseconds = end_t - start_t;
            seconds = milliseconds / (float)1000;
        }
        float milliseconds;
        float seconds;

    private:
        unsigned long start_t;
        unsigned long end_t;
        bool running;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...