расширение функциональности std :: chrono для работы с постоянными периодами времени выполнения (не во время компиляции)

Я экспериментировал со всеми видами таймеров в Linux и OSX и хотел бы попытаться обернуть некоторые из них тем же интерфейсом, что и std :: chrono.

Это легко сделать для таймеров, которые имеют четко определенный «период» во время компиляции, например, семейство POSIX clock_gettime (), семейство clock_get_time () в OSX или gettimeofday ().

Однако есть некоторые полезные таймеры, для которых «период» — хотя и постоянный — известен только во время выполнения.
Например:
— POSIX сообщает, что период clock (), CLOCKS_PER_SEC, может быть переменной в не-XSI системах
— в Linux период times () задается во время выполнения sysconf (_SC_CLK_TCK)
— в OSX период mach_absolute_time () задается во время выполнения посредством mach_timebase_info ()
— на последних процессорах Intel регистр DST работает с постоянной скоростью, но, конечно, это можно определить только во время выполнения

Чтобы обернуть эти таймеры в интерфейс std :: chrono, одной из возможностей будет использование периода std :: chrono :: наносекунда и преобразование значения каждого таймера в наносекунды. Другим подходом может быть использование представления с плавающей запятой. Однако оба подхода привели бы к (очень небольшим) издержкам функции now () и (возможно, небольшим) потерям в точности.

Решение, которое я пытаюсь найти, состоит в том, чтобы определить набор классов для представления таких «постоянных времени выполнения» периодов, построенных по тем же линиям, что и класс std :: ratio.
Однако я ожидаю, что для этого потребуется переписать все связанные классы и функции шаблона (так как они принимают значения constexpr).

У кого-нибудь есть опыт работы с такими таймерами в стиле хронографа?

Или с использованием значений non-constexpr для периода времени часов?

3

Решение

Кто-нибудь имеет опыт работы с такими таймерами?
la std: хроно?

На самом деле я делаю. И на OSX, одна из ваших платформ интереса. 🙂

Вы упоминаете:

в OSX период mach_absolute_time () задается во время выполнения как
mach_timebase_info ()

Абсолютно правильно. Также на OSX Libc ++ реализация high_resolution_clock а также steady_clock на самом деле основан на mach_absolute_time, Я являюсь автором этого кода с открытым исходным кодом и щедрой лицензией (делайте с ним все, что хотите, пока сохраняете авторские права).

Вот источник для Libc ++ s steady_clock::now(). Он построен так, как вы и предполагали. Время выполнения преобразуется в наносекунды до возвращения. В OS X коэффициент преобразования очень часто равен 1, и код использует этот факт для оптимизации. Однако код достаточно общий для обработки не-1 коэффициентов преобразования.

По первому звонку now() есть небольшая стоимость запроса коэффициента преобразования времени выполнения в наносекунды. В общем случае вычисляется коэффициент преобразования с плавающей запятой. В общем случае (коэффициент преобразования == 1) последующая стоимость вызывается через указатель функции. Я обнаружил, что накладные расходы действительно вполне разумны.

В OS X коэффициент преобразования, хотя и не определяется до времени выполнения, остается постоянным (т. Е. Не изменяется во время выполнения программы), поэтому его необходимо вычислять только один раз.

Если вы находитесь в ситуации, когда ваш период на самом деле меняется динамически, вам понадобится больше инфраструктуры, чтобы справиться с этим. По сути, вам нужно будет интегрировать (исчислить) период и кривую времени, а затем вычислить средний период между двумя моментами времени. Это потребует постоянного мониторинга периода, так как он меняется со временем, и <chrono> не правильный инструмент для этого. Такие инструменты обычно обрабатываются на уровне ОС.

3

Другие решения

[У кого-нибудь есть опыт] Или с использованием значений non-constexpr для периода времени часов?

После прочтения стандарта (20.11.5, Продолжительность шаблона класса) «период», как ожидается, будет «специализация отношения»:

Примечания: Если Период не является специализацией соотношения, программа некорректна.

и все шаблоны хроно в значительной степени зависят от функциональности constexpr.

У кого-нибудь есть опыт работы с такими таймерами в стиле хронографа?

я обнаружил Вот предложение использовать длительность с period = 1, boost :: рациональное в качестве rep, но без каких-либо конкретных примеров.

0

Я сделал подобное для моих целей, но только для Linux. Вы найдете код Вот; не стесняйтесь использовать код любым удобным для вас способом.

Проблемы, с которыми сталкивается моя реализация, частично совпадают с теми, которые упоминаются в вашем вопросе. В частности:

  • Тиковый коэффициент (необходимый для преобразования тиков часов в единицу времени на основе секунд) извлекается во время выполнения, но только в первый раз now() используется. Если вас беспокоят небольшие накладные расходы, вы можете позвонить now() Работайте один раз при запуске, прежде чем измерять фактические интервалы. Фактор тика сохраняется в статической переменной, что означает, что все еще есть некоторые издержки, так как — на самом низком уровне — каждый вызов now() Функция подразумевает проверку инициализации статической переменной. Тем не менее, эти накладные расходы будут то же самое в каждом вызове now(), так что это не должно влиять на измерения временных интервалов.

  • По умолчанию я не преобразую в наносекунды, потому что при измерении относительно длинных периодов времени (например, нескольких секунд) это вызывает очень быстрое переполнение. На самом деле это главная причина, почему я не использую реализацию boost. Вместо преобразования в наносекунды, я реализую базовый блок как параметр шаблона (называемый Precision в коде). я использую std::ratio из C ++ 11 в качестве аргументов шаблона. Так что я могу выбрать, например, clock<micro>, что подразумевает, что вызов now() Функция будет внутренне преобразовываться в микросекунды, а не наносекунды, что означает, что я могу измерять периоды в несколько секунд или минут без переполнений и при этом с хорошей точностью. (Это не зависит от единицы, используемой для производства продукции. Вы можете иметь clock<micro> и отобразить результат в секундах и т. д.)

  • Мой тип часов, который называется combined_clock объединяет пользовательское время, системное время и время настенных часов. Для этого тоже есть тип тактовых импульсов, но он не совместим с типами коэффициентов и единицами измерения из stdтогда как мой есть.

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

Таким образом, вы используете его следующим образом:

#include "util/proctime.hpp"
#include <ratio>
#include <chrono>
#include <thread>
#include <utility>
#include <iostream>

int main()
{
using std::chrono::duration_cast;
using millisec   = std::chrono::milliseconds;
using clock_type = rlxutil::combined_clock<std::micro>;

auto tp1 = clock_type::now();

/* Perform some random calculations. */
unsigned long step1 = 1;
unsigned long step2 = 1;
for (int i = 0 ; i < 50000000 ; ++i) {
unsigned long step3 = step1 + step2;
std::swap(step1,step2);
std::swap(step2,step3);
}

/* Sleep for a while (this adds to real time, but not CPU time). */
std::this_thread::sleep_for(millisec(1000));

auto tp2 = clock_type::now();

std::cout << "Elapsed time: "<< duration_cast<millisec>(tp2 - tp1)
<< std::endl;

return 0;
}

Приведенное выше использование включает в себя функцию pretty-print, которая генерирует вывод, подобный следующему:

Elapsed time: [user 40, system 0, real 1070 millisec]
0
По вопросам рекламы [email protected]