Я работаю с алгоритмами бенчмаркинга.
Я читаю о новом <chrono>
заголовок в C ++ 11, так что я пошел с этим.
Я могу сделать измерения и все, но я борюсь с разрешением.
Когда делаешь что-то вроде
auto duration = chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count();
Я последовательно получаю времена, кратные 1000!
После дальнейшего расследования и выполнения следующих действий
cout << (double) chrono::high_resolution_clock::period::num /
chrono::high_resolution_clock::period::den << endl;
Я получил значение 1e-06
что микросекунды, не наносекунд. Он отлично отбрасывает до наносекунд, но бесполезно, если период с часов начинается только в микросекундах.
Я педантичен? Я знаю, что могу запустить свой тестовый код несколько раз и получить достаточно большое среднее время работы, и это то, что я делаю. Но для меня это почти принципиальный вопрос.
Дополнительная информация:
Я использую последнюю версию GCC (4.6.3) на сервере Ubuntu 12.04 X64 (я думаю)
Точность часов зависит от оборудования и операционной системы, на платформе x86 микросекунды Linux работают нормально. На моей красной шляпе 6 с ядром 2.6.30 я могу получить только около 10 мкс.
Чтобы получить лучшее разрешение, вам понадобится операционная система реального времени.
Fwiw, для меня это:
#include <ratio>
#include <chrono>
#include <string>
template <class Ratio, class CharT>
struct ratio_string
{
static std::basic_string<CharT> symbol()
{
return std::basic_string<CharT>(1, CharT('[')) +
std::to_string(Ratio::num) + CharT('/') +
std::to_string(Ratio::den) + CharT(']');
}
};
template <class CharT>
struct ratio_string<std::nano, CharT>
{
static std::basic_string<CharT> symbol()
{
return std::basic_string<CharT>(1, CharT('n'));
}
};
template <>
struct ratio_string<std::micro, char>
{
static std::string symbol() {return std::string("\xC2\xB5");}
};
template <>
struct ratio_string<std::micro, char16_t>
{
static std::u16string symbol() {return std::u16string(1, u'\xB5');}
};
template <>
struct ratio_string<std::micro, char32_t>
{
static std::u32string symbol() {return std::u32string(1, U'\xB5');}
};
template <>
struct ratio_string<std::micro, wchar_t>
{
static std::wstring symbol() {return std::wstring(1, L'\xB5');}
};
template <class CharT, class Rep, class Period>
inline
std::basic_string<CharT>
get_unit(const std::chrono::duration<Rep, Period>& d)
{
return ratio_string<Period, CharT>::symbol() + 's';
}
template <class Rep, class Period>
std::string
to_string(const std::chrono::duration<Rep, Period>& d)
{
return std::to_string(d.count()) + get_unit<char>(d);
}
#include <iostream>
int
main()
{
auto t0 = std::chrono::high_resolution_clock::now();
auto t1 = std::chrono::high_resolution_clock::now();
std::cout << to_string(t1-t0) << '\n';
}
при компиляции с -O3 выводит:
$ a.out
112ns
$ a.out
95ns
$ a.out
112ns
$ a.out
111ns
YMMV. Ваш вывод может быть аккуратнее, если вы добавите ratio_string
специализаций.
У меня сложилось впечатление, что duration_cast на самом деле даст мне наносекунды, а не только то, что разработчик конкретной реализации решил сделать, как в случае с MSVC ++.
Нет, duration_cast
просто преобразует длительность как есть в другой тип. Это не изменит то, как часы работают внутри, и не изменит разрешение часов.
В целом, хорошая идея — не делать эти приведения или преобразования, а просто позволить реализации выбрать соответствующий тип. Это также проще:
auto duration = end_time - start_time;
И с chrono_io Говарда Хиннанта вы можете просто распечатать это напрямую, и это даст вам правильные единицы.
std::cout << duration << '\n';
Это распечатало бы что-то вроде 112ns
, 2us
и т. д. в зависимости от фактического разрешения.