LINUX.ORG.RU

Измерение интервалов времени в kernel space


1

1

Как измерить в kernel space интервалы времени по возможности наиболее точно?
Интересует реальное время (wall clock).
Необходимо измерять в ядре время между пришедшими TCP пакетами.
Нашел функции getrawmonotonic и getnstimeofday. Подойдут ли они для данной задачи, и в чем между ними разница?
Я так понимаю, что для x86 они по сути обертка вокруг rdtsc. Т.е. мне нужно привязать код к одному ядру процессора (так как tsc могут быть не синхронизированы между ядрами) и надеяться, что тактовая частота ядра будет неизменна во время его работы?
Будет также здорово, если кто-нибудь расскажет (или поделится ссылкой), как реализованы эти функции на не x86 архитектурах.

>Будет также здорово, если кто-нибудь расскажет (или поделится ссылкой), как реализованы эти функции на не x86 архитектурах.

В m68k(и m68knommu) используется таймер-счетчик, который генерирует прерывания по достижению заданного значения. Это прерывание дает 1 jiffy. Функции для работы со временем используют или jiffies, или (для большей точности) jiffies + счетчик таймера, который дает уточнение к jiffies.

Pavval ★★★★★
()
Ответ на: комментарий от frey

Что конкретно Вы хотите, чтобы я там прочитал?
В этой главе я нашел только get_cycles и do_gettimeofday.
Если Вы про первое, то я не вижу смысла городить свой велосипед переводя cycle_t, скажем, в struct timespec, когда в ядре уже есть функции, которые это делают и при этом надежнее в использовании.
Если про второе, то не вижу смысла использовать ее вместо getnstimeofday.

nocomer
() автор топика
Ответ на: комментарий от nocomer

Все функции get*timeofday() выдают время, которое корректируется (например по NTP). Поэтому как правило запрос monotime легче для системы, иногда в разы. Поэтому если нужны интервалы, то getrawmonotonic() однозначно.

Но в реальности все может быть «плохо». Во-первых могут быть проблемы с suspend. Во-вторых если вызывать getrawmonotonic() для каждого пакета при больших PPS, то может существенно пострадать производительность.

В реальности мне как-то пришлось отказаться от всего и юзать RDTSC, а пересчитывать tsc в секунды уже в userspace.

ly
()
Ответ на: комментарий от ly

Спасибо за пояснение. Не подскажете, с какого момента идет отчет времени при использовании getrawmonotonic (что является «эпохой»)? С загрузки ядра?

Но в реальности все может быть «плохо». Во-первых могут быть проблемы с suspend.

А проверка check_tsc_unstable в init_tsc_clocksource от этого не спасает? В плане, если tsc не гарантируется монотонным, то его рейтинг как источника времени зануляется и в результате ядро использует другой clocksource.

Во-вторых если вызывать getrawmonotonic() для каждого пакета при больших PPS, то может существенно пострадать производительность.

Можете поделиться опытом, что в getrawmonotonic сильнее всего влияло на производительность по сравнению с использованием rdtsc на прямую? Если производили подобные замеры, конечно.

nocomer
() автор топика
Ответ на: комментарий от ly

>В реальности мне как-то пришлось отказаться от всего и юзать RDTSC, а пересчитывать tsc в секунды уже в userspace.

rdtsc особо весел когда частота проца динамически изменяется:)

Pavval ★★★★★
()
Ответ на: комментарий от nocomer

>А проверка check_tsc_unstable в init_tsc_clocksource от этого не спасает? В плане, если tsc не гарантируется монотонным, то его рейтинг как источника времени зануляется и в результате ядро использует другой clocksource.

ЕМНИП ядро узнает о том, что tsc unstable только тогда, когда он им становится. Т.е. у меня, к примеру, на ноуте, в dmesg сыпалось «clocksource tsc unstable» только тогда, когда я его отсоединял от сети и у него менялась частота.

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

rdtsc особо весел когда частота проца динамически изменяется:)

При использовании getrawmonotonic и CONFIG_CPU_FREQ=y можно надеяться, что time_cpufreq_notifier поможет нам понять, что tsc в данной системе - плохой источник времени, и будет использован другой.
При использовании rdtsc напрямую также можно проверять «качество» tsc, вызывая check_tsc_unstable, благо он экспортирован.

nocomer
() автор топика

Лет ми спик фром май харт ин инглиш

Вычисление текущего времени в ядре основано на использовании так называемых «источниках времени» или struct clocksource.

Источник времени регистрируется драйвером с помошью функции clocksource_register(). Каждый источник имеет свой рейтинг точности, и если рейтинг нового выше, чем у текущего зарегистрированного, то начинает использоваться он.

Реализация clocksource архитектурно зависима, потому что на разных платформах есть разные устройства. Но есть также общий источник времени, построенный на jiffies: clocksource_jiffies. Он наименее точный из всех.

Если ты пишешь связанный с сетью драйвер, то используй доступный интерфейс getnstimeofday() и не заморачивайся его внутренней реализацией. Будет использоваться наиболее точный способ вычисления времени.

Функция getrawmonotonic(), на сколько я понимаю, для широкого круга пользователей ядра не предназначена. Она более низкоуровнева. Выдает время, масштабируемое к текущему источнику, который не обязательно читался последним — это одна из причин — а если поискать, то и другие найдуться. Короче, используется для других, внутренних нужд timekeeper.

ttnl ★★★★★
()
Ответ на: комментарий от nocomer

> Не подскажете, с какого момента идет отчет времени при использовании getrawmonotonic (что является «эпохой»)?

Как конкретно в актуальных ядрах - не знаю. IMHO лучше считать, что отсчет начинается с некой абстрактной величины. Если работать только с интервалами, то разницы не будет. В POSIX именно так определено использование CLOCK_MONOTONIC.

Можете поделиться опытом, что в getrawmonotonic сильнее всего влияло на производительность по сравнению с использованием rdtsc на прямую.

Мне нужно было в embedded-железке выжать максимум, с минимизацией латентности прерываний. Поэтому дело дошло до экономии на пересчете тиков в us/ns и минимизации codepath под cli. А так как можно было гарантировать, что tsc будет тикать правильно - то просто его и заюзал.

В зависимости от конкретной аппаратной платформы все может сильно меняться. Например, в зависимости от модели x86-проца доступен разный набор аппаратных счетчиков, которые ведут себя по-размому в зависимости от power-state и частоты.

Если не ошибаюсь (раньше так было), в худшем случае ядро полезет к реальным часам в CMOS - относительно это очень долго.

ly
()
Ответ на: Лет ми спик фром май харт ин инглиш от ttnl

Выдает время, масштабируемое к текущему источнику, который не обязательно читался последним

Честно говоря, не совсем понимаю, чем в данном случае getnstimeofday отличается от getrawmonotonic. Они обе работают с глобальной переменной clock,а учитывая реализацию change_clocksource, xtime обновляется также как и clock->raw_time за исключением добавления arch_gettimeoffset. Или разница проявляется, если убрать CONFIG_GENERIC_TIME?
По поводу arch_gettimeoffset(), кстати, можете подсказать для чего он нужен?

nocomer
() автор топика
Ответ на: комментарий от nocomer

Нашел комментарий в исходниках ядра

/* Some architectures do not supply their own clocksource.
 * This is mainly the case in architectures that get their
 * inter-tick times by reading the counter on their interval
 * timer. Since these timers wrap every tick, they're not really
 * useful as clocksources. Wrapping them to act like one is possible
 * but not very efficient. So we provide a callout these arches
 * can implement for use with the jiffies clocksource to provide
 * finer then tick granular time.
 */
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
extern u32 arch_gettimeoffset(void);
#else
static inline u32 arch_gettimeoffset(void) { return 0; }
#endif

nocomer
() автор топика
Ответ на: комментарий от nocomer

>change_clocksource, xtime обновляется также как и clock->raw_time

Ага, но на getrawmonotonic() не действует сильное колдунство из timekeeper. А оно может по-своему корректировать время, по событию ntp, например. Время может пойти даже назад.

Т.е. методом размышлений мы пришли к противоположному решению — в твоей задаче нужно использовать getrawmonotonic() :)

ttnl ★★★★★
()
Ответ на: комментарий от nocomer

>Нашел комментарий в исходниках ядра

Ага, «grep -R clocksource_register arch/sparc/» подтверждает, если я правильно перевел комментарий фром инглиш.

ttnl ★★★★★
()
Ответ на: комментарий от nocomer

>А Marking TSC unstable due to cpufreq changes в dmesg перед этим появлялось?

Нет (по крайней мере на дефолтных логлевелах консоли).

Pavval ★★★★★
()
Ответ на: комментарий от nocomer

А getrawmonotonic() всегда корректно работает на SMP или лучше привязать выполнение кода к одному ядру?

Корректно. Посмотри реализации read для каждого clocksource. Иначе в описании getrawmonotonic() было бы куча предупреждений.

На счет rdtsc смотри:

/*
 * We compare the TSC to the cycle_last value in the clocksource
 * structure to avoid a nasty time-warp. This can be observed in a
 * very small window right after one CPU updated cycle_last under
 * xtime/vsyscall_gtod lock and the other CPU reads a TSC value which
 * is smaller than the cycle_last reference value due to a TSC which
 * is slighty behind. This delta is nowhere else observable, but in
 * that case it results in a forward time jump in the range of hours
 * due to the unsigned delta calculation of the time keeping core
 * code, which is necessary to support wrapping clocksources like pm
 * timer.
 */
static cycle_t read_tsc(struct clocksource *cs)
{
        cycle_t ret = (cycle_t)get_cycles();

        return ret >= clocksource_tsc.cycle_last ?
                ret : clocksource_tsc.cycle_last;
}

Тут все понятно.

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

Хорошо. Тогда попробую использовать её.

nocomer
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.