Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прецизионный таймер в Linux
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы
vzn
Добрый день.
Подскажите как в Linux можно реализовать посылку сигнала SIGALRM в мое приложение с периодом
порядка 100us(микросекунд).

Настройка обычного таймера в Linux согласно man предполагает минимальный период 10 ms.

Вариант с перекомпиляцией ядра для уменьшения времени отклика не подходит.

Какие еще могут быть способы реализовать таймер?
appsoft
Думаю реализовать такой таймер средствами Linux не получится. Linux не является системой с жестким realtime, соответственно нет никакой гарантии, что в ядре нет функций выполняющихся дольше 100 мкс, и следовательно, оно не сможет гарантировать посылку сигнала. Единственный выход в таком случае использовать прерывание, генерируемое с требуемой частотой. Но если речь идет о платформе х86, то разрешения системного таймера вряд ли хватит. Т.е. только вариант прерывания с нужной частотой от внешнего устройства.
makc
В ядре Линукса есть определение макроса HZ=100, который определяет частоту вызова шедулера при переключении задач. Т.е. задачи по умолчанию переключаются с частотой 100 Гц, иными словами, период переключения задачи = 10 мс, что и указано в man. Если хотите сделать задержки меньше, то можете попытаться организовать отдельный поток и вызывать в нем функцию usleep, которая может приостанавливать выполнение (давать задержку) на заданное число микросекунд.
yanich
Цитата(vzn @ Apr 6 2006, 12:39) *
Добрый день.
Подскажите как в Linux можно реализовать посылку сигнала SIGALRM в мое приложение с периодом
порядка 100us(микросекунд).

Настройка обычного таймера в Linux согласно man предполагает минимальный период 10 ms.

Вариант с перекомпиляцией ядра для уменьшения времени отклика не подходит.

Какие еще могут быть способы реализовать таймер?

Я одно время работал в QNX 6.x. Так там можно библиотечными функциями устанавливать требуемую частоту срабатывания аппаратоного таймера (до 10 мкс). И как написано в хелпе, ОС именно по прерыванию аппартного таймера вызыват шедулер, обрабатывает таймеры и т.д. То есть разрешение таймера POSIX не может быть меньше, чем частота работы аппартного таймера. Но на эту частоты можно повлиять. Поищите описание аппаратного таймера в Инете.
Никто не мешает Вам реализовать программный псевдотаймер. То есть просто крутить циклы, которые делают какую нибудь пустую работу.
sensor_ua
Может, поможет http://www.ittc.ku.edu/kurt/
Olej
Цитата(vzn @ Apr 6 2006, 11:39) *
Вариант с перекомпиляцией ядра для уменьшения времени отклика не подходит.
Какие еще могут быть способы реализовать таймер?


Если бы wink.gif ... ваш вариант гораздо хуже, чем просто перекомпиляция ядра sad.gif :
- все службы времени ОС привязаны к системному тику (timeslice)...
- это не совсем то же, что интервал (о чём говорили здесь: HZ=100) решедулирования (например в QNX6 интервал решедулирования = 4 * timeslice и изменить это никакими силами нельзя), но они могут и совпадать ... не помню что там в Linux...;
- но если вы и уменьшите интервал до T, то, согласно требованиям POSIX 1003b (realtime расширения) - время срабатывания временных интервалов минимальное будет 3T ... с большой вероятностью wink.gif, иногда - 2T (это всё объясняется, но не место здесь это делать);
- итого, вам нужно было бы уменьшить timeslice как минимум до 30мкс (в 300 раз)...
- при этом решедулирование и всё обслуживание системного времени участиться в 300 раз ... и в разы завалит вам итоговую производительность системы...

Цитата(makc @ Apr 6 2006, 12:08) *
Если хотите сделать задержки меньше, то можете попытаться организовать отдельный поток и вызывать в нем функцию usleep, которая может приостанавливать выполнение (давать задержку) на заданное число микросекунд.


Не поможет wink.gif - все события в системе, разделённые интервалом времени меньше timeslice - неразличимы и выглядят так, как если бы они произошли в одной точке времени.


Чем делу можно помочь?

Можете попробовать использовать другой задатчик времени: RTC (который на IRQ8 сидит а не на IRQ0) ... можете об этих делах почитать здесь:
http://qnx.org.ru/index.php?option=com_min...273&page=0.html
http://en.wikipedia.org/wiki/Real-time_clock
А вот здесь:
ftp://ftp.qnx.org.ru/pub/projects/ed1k/clock.tgz
- лежит давненько уже написанная статья, одним знакомым, где с полным программным кодом показывается и объясняется как это делается... Только тягомутина всё это организовать - "ещё та" wink.gif, и есть смысл этим заниматься, только если действительно нужно и ничего другого придумать нельзя.

P.S. но, кстати, использование любого внешнего аппаратного источника, как здесь предлагали, программно не будет проще, т.к. RTC и есть уже такой источник.
Olej
Цитата(vzn @ Apr 6 2006, 12:39) *
Подскажите как в Linux можно реализовать посылку сигнала SIGALRM в мое приложение с периодом
порядка 100us(микросекунд).


На худой конец wink.gif - вы ведь не сказали что в этот период должно выполняться? - если это требуется что-то типа тайм-аут на блокирующей операции, то можно изобразить что-то по типу активного ожидания:

Цитата(yanich @ Apr 6 2006, 13:07) *
Никто не мешает Вам реализовать программный псевдотаймер. То есть просто крутить циклы, которые делают какую нибудь пустую работу.


1. запускаем отдельный поток приоритетом на 1 меньше - он тут же вытесняется...
2. запускаем блокирующую операцию, которую нужно ждать "не более чем"...
3. в состояние RUN переходит вытесненный поток...
4. который может "просто крутить циклы" ... но проще использовать функции активного ожидания POSIX (которые делают то же самое, только не нужно программные циклы в единицы времени пересчитывать на разных процессорах): см. nanospin(), spin() POSIX-овские, или что там есть (точно есть) их Linux эквиваленты...
5. как только активные циклы "накрутились" - поток посылает SIGALRM (или всё что угодно) блокированному родителю...
6. и тот разблокируется сигналом.
Harbour
Попытки вытянуть за уши из non-rt реализации rt задачу ничем хорошим не закончится. Хотите без пыли и шуму получить надежный rt в userspace - юзайте rtai.
Olej
Цитата(Harbour @ Apr 6 2006, 22:08) *
Попытки вытянуть за уши из non-rt реализации rt задачу ничем хорошим не закончится. Хотите без пыли и шуму получить надежный rt в userspace - юзайте rtai.


Ну, наверное, не совсем так категорично: измените временнЫе масштабы (из микросекундного диаппазона в ... сотне миллисекундный wink.gif) и траблы такого рода даже не будут возникать. А есть RT задачи, которые требуют вот этого RT качества в микросекундной шкале, а есть и такие - которые в секундной.
Harbour
Да ну ? Есть такая фигня как гарантированный deadline - запутят на той non-rt оси какой-нить низкоприоритетный процесс, который заюзает ram+swap на 100% - и скажем bye-bye этому "realtim'у", пусть даже секундному и никакие posix расширения не спасут.
Olej
Цитата(Harbour @ Apr 7 2006, 11:53) *
Да ну ?


http://qnxclub.net/files/articles/RemarksO...TheMargins.html

smile.gif
vzn
Спасибо всем за дельные советы.

Пока я остановился на следующем решении основаном на использовании rdtscl()(#include <asm/msr.h>). Оно конечно не оптимальное, но для моих условий пока подходит.

Привязал исполнение моей real-time задачи не к SIGALRM, а к счетчику тактов процессора.
То есть задача должна выполнятся например каждые 100us.
Для этого оцениваем, сколько тактов нашего процессора в этих 100us. Часть тактов выполняем задачу (задача выполняется менее чем за 100us) часть тактов ждем ничего не делая, пока не на тикает оставшееся количество тактов. Все в обычном цикле.

При исполнении только моего приложения и ничего кроме него, решение дает приемлемый результат по точности. Если исполняется еще что-либо, то происходят сбои.
Olej
Цитата(vzn @ Apr 7 2006, 13:22) *
Пока я остановился на следующем решении основаном на использовании rdtscl()(#include <asm/msr.h>). Оно конечно не оптимальное, но для моих условий пока подходит.

Привязал исполнение моей real-time задачи не к SIGALRM, а к счетчику тактов процессора.
То есть задача должна выполнятся например каждые 100us.
Для этого оцениваем, сколько тактов нашего процессора в этих 100us. Часть тактов выполняем задачу (задача выполняется менее чем за 100us) часть тактов ждем ничего не делая, пока не на тикает оставшееся количество тактов. Все в обычном цикле.

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


Вы то же самое могли бы сделать и по схеме с сигналами или любым другим асинхронным уведомлением (это и проще по коду, и точнее будет - затраты на вычисления уйдут из цикла активного ожидания):
- запускаете пустой цикл с rdtscl() (это на самом деле 1 команда RDTSC на x86)...
- и как только счётчик перевалит через заранее фиксированное значение - kill() самому себе ... SIGUSR1 или SIGRTMIN ...
- а в обработчике сигнала - запуск своей кратковременной задачи.
Или, если так больше нравится - всё то же можно выполнить в 2-х потоках.

Цитата(Harbour @ Apr 7 2006, 11:53) *
Есть такая фигня как гарантированный deadline - запутят на той non-rt оси какой-нить низкоприоритетный процесс, который заюзает ram+swap на 100% - и скажем bye-bye этому "realtim'у", пусть даже секундному и никакие posix расширения не спасут.


В общем ... оно и правильно. Но свопирование во всех (нормальных wink.gif : FreeBSD, Linux) OS можно запретить для задачи - это обязательное условие для таких задач... так же как в QNX - оно всегда запрещено (или всегда отсутствует, если кому так больше нравитс wink.gif).
Но вопрос, заданный в этой теме - он не относится к какой-либо OS, он будет возникать везде... даже в уже "некуда далее RT" wink.gif QNX - можно уменьшить шаг системного времени до 10мксек (а минимальный интервал, как я уже говорил, вы принципиально не сделаете меньше 20мксек) - но всегда найдётся кто-то, кому понадобится временной шаг в ... 7 мксек wink.gif. И опять та же история: нельзя разрешить 2 события, временной интервал которых меньше шага системного времени ... независимо RT это OS или не RT.
Harbour
Если речь идет о самой критической задаче то вызов в начале mlock(MCL_CURRENT | MCL_FUTURE) - это must be по определению. Речь шла о гарантии вызова этой самой задачи операционной системой при получении тика, или скажем так - минимальном времени вызова. В случае non-rt этого никто не гаранитурет - вот к примеру товарисч который померяет свой rtdsc вариант будет очень удивлен результатами, а если запустит ping -f, ls -lR /, xperf -all и т.д. то будет удручен wink.gif
Olej
Цитата(Harbour @ Apr 7 2006, 14:17) *
В случае non-rt этого никто не гаранитурет - вот к примеру товарисч который померяет свой rtdsc вариант будет очень удивлен результатами, а если запустит ping -f, ls -lR /, xperf -all и т.д. то будет удручен wink.gif


А он будет так же удручён, строя службу уведомления времени на RDTSC в любой ОС - это другая система времени, астрономическое время, отличное от службы системного времени ОС, и построенная на ней служба времени будет так же удручать, под какой самой RTOS её не построй (кстати, в этом крайне просто убеждаться: Linux-приложение перекомпилируется в QNX, из-за их общей gcc-основанности и ... убеждаемся, что всё так и есть).
Но в его случае - это наипростейшее приемлемое (при некоторых условиях) решение.
Konstantin_SPB
Используйте select(), читайте man select, как это сделать smile.gif
Olej
Цитата(Konstantin_SPB @ Jun 22 2006, 13:05) *
Используйте select(), читайте man select, как это сделать smile.gif


тайм-ауты select() выражены в той же дискретной сетке timeslice, и срабатывание наступит на следующем (а иногда и не следующем) истечении timeslice ... т.е. задачу временного разрешения это никак не меняет.

P.S. кроме того, select() - это один из самых старых и мощных средств API, но именно из-за того, что старых - он принципиально not thread safe, что в новых проектах может стать ну очень серьёзным препятствием ... с select() нужно сильно осторожно wink.gif.
Илья Игоревич
Решение есть. Появилось совсем недавно, в виде патча к последнему(или одному из последних) ядер 2.6. Собственно, страница с патчем: http://kerneltrap.org/node/6750 После патча и включения его в ядро, функции usleep и nanosleep начинают работать настолько точно, насколько позволяет ваша машина. (Насколько я понимаю, зависит это от чипсета) Мне-таки удалось получить 100 микросекундную выдержку - проверял осциллографом. На старом компьютере (PIII c VIA Apollo Pro) минимальным временем задержки стала 1 миллисекунда вместо 20 мс, что тоже неплохо. Впрочем, судя по дате последнего сообщения, это уже неактуально.

P.S. А вот интересно, под windows кто-нибудь пробовал получать задержки в порядка сотни микросекунд..?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.