Разрешение std:: chrono:: high_resolution_clock не соответствует измерениям
Позвольте мне задать свой вопрос в этой тестовой программе:
#include <iostream>
#include <chrono>
using std::chrono::nanoseconds;
using std::chrono::duration_cast;
int main(int argc, char* argv[])
{
std::cout << "resolution (nano) = " << (double) std::chrono::high_resolution_clock::period::num
/ std::chrono::high_resolution_clock::period::den * 1000 * 1000 * 1000 << std::endl;
auto t1 = std::chrono::high_resolution_clock::now();
std::cout << "how much nanoseconds std::cout takes?" << std::endl;
auto t2 = std::chrono::high_resolution_clock::now();
auto diff = t2-t1;
nanoseconds ns = duration_cast<nanoseconds>(diff);
std::cout << "std::cout takes " << ns.count() << " nanoseconds" << std::endl;
return 0;
}
Выход на моей машине:
разрешение (nano) = 100
сколько наносекунд std:: cout принимает?
std:: cout принимает 1000200 наносекунд
В результате я получаю либо 1000200
, либо 1000300
или 1000400
или 1000500
или 1000600
или 2000600
(= 1 или 2 микросекунды). Очевидно, что либо разрешение std::chrono
не 100 наносекунд , либо, поскольку я измеряю время std::cout
неправильно. (почему я никогда не получаю что-то между 1 и 2 микросекундами, например 1500000
?)
Мне нужен таймер с высоким разрешением в С++. Сама ОС обеспечивает таймер с высоким разрешением, потому что я могу измерять вещи с точностью до микросекунды, используя класс С# Stopwatch
на той же машине. Поэтому мне просто нужно правильно использовать таймер высокого разрешения, который имеет ОС!
Как исправить мою программу для получения ожидаемых результатов?
Ответы
Ответ 1
Я собираюсь предположить, что вы используете VS2012; Если нет, не принимайте во внимание этот ответ. VS2012 typedef
high_resolution_clock
до system_clock
. К сожалению, это означает, что у него дерьмовая точность (около 1 мс). Я написал лучшие часы с высоким разрешением, которые используют QueryPerformanceCounter
для использования в VS2012...
HighResClock.h:
struct HighResClock
{
typedef long long rep;
typedef std::nano period;
typedef std::chrono::duration<rep, period> duration;
typedef std::chrono::time_point<HighResClock> time_point;
static const bool is_steady = true;
static time_point now();
};
HighResClock.cpp:
namespace
{
const long long g_Frequency = []() -> long long
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return frequency.QuadPart;
}();
}
HighResClock::time_point HighResClock::now()
{
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
return time_point(duration(count.QuadPart * static_cast<rep>(period::den) / g_Frequency));
}
(Я упустил assert и #ifs, чтобы посмотреть, компилируется ли он в 2012 году из приведенного выше кода)
Вы можете использовать эти часы везде и так же, как стандартные часы.
Ответ 2
Разрешение часов не обязательно совпадает с наименьшей продолжительностью, которая может быть представлена типом данных, который использует часы. В этом случае ваша реализация использует тип данных, который может представлять собой продолжительность не менее 100 наносекунд, но базовые часы на самом деле не имеют такого разрешения.
Низкое разрешение Visual Studio high_resolution_clock
было проблемой в течение нескольких лет. Стандартная библиотека Microsoft С++, Stephan T. Lavavej, указала, что это было исправлено в VS2015 с помощью QueryPerformanceCounter()
.
Ответ 3
Может быть, реализация не реализует таймер с более высоким разрешением?
Кажется, вы используете Windows (вы упоминаете С#), поэтому, если вы используете таймер, и вы действительно используете окна, вы можете использовать QueryPerformanceFrequency и QueryPerformanceCounter.