LINUX.ORG.RU

Realtime sequencer


0

2

Всем привет.

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

Основная проблема в том, что никто не гарантирует нашей программе real-time scheduling. Пускай мы вызываем gettimeofday(); usleep(100); gettimeofday() - нет никакой гарантии, что между вызовами действительно прошло 100 миллисекунд. Во время usleep() приложение могло быть заторможено свапом, работой мусоросборщика, могло быть засуспенжено через SIGSTOP, наконец. Как в таких условиях обеспечить равномерно «ползущий» указатель проигрывания (так называемый playhead)? Пока что придумалось следующее:

1. Установить разрешение, например, 25ms.
2. Вызывать usleep(25) в цикле, запоминая показания gettimeofday().
3. Если реально прошедшее время (полученное вычитанием показаний gettimeofday) похоже на правду, то есть не сильно отличается от 25ms, то мы полагаем, что наш scheduling стабилен, и даём соответствующее приращение позиции playhead.
4. Если реально прошедшее время сильно отличается от 25ms, то, значит, приложение было заторможено, и scheduling дестабилизировался. В этом случае мы просто ничего не делаем, и надеемся на стабилизацию в следующих циклах.

Извне это будет выглядеть как пауза в проигрывании при наступлении тяжёлых внешних условиях (свап, GC, остановка по SIGSTOP, гибернация) и возобновление при восстановлении нормального течения времени. Может, кто-то предложит вариант получше? Спасибо.

P.S. Исходные тексты Qtractor, Rosegarden и т.п. у меня есть, но ковыряться в них довольно затратно. Может, быстрее разберёмся сами.

P.P.S. все названия функций - вымышленные, язык не специфицируется, но пускай для определённости это будут Java, Python или C++.

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

Если я что-то в этом понимаю, то к примеру в винде программы типа Cubase через ASIO всё загоняют в буфер звуковой карты, а та уже сама данные оттеда вытаскивает и ровно воспроизводит. Как по-другому обеспечить равномерное воспроизведение чё-та не придумывается.

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

Да, Cubase и прочие Сонары используют звуковую карту в качестве «timing master». Но как быть, если такой аппаратуры вообще нет в системе? И если мы собираемся воспроизводить не аудио/видео, а просто абстрактные события? Да, порядок частоты событий примерно такой, как в audio/MIDI-секвенсах, или же в векторных анимациях типа флеша.

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

> sched_setscheduler(..., SCHED_FIFO, ...); не поможет?

Скажем так, не помешает. Но гарантий всё равно не будет никаких, в частности, от SIGSTOP или гибернации. Потом, не хочется зависеть от конкретной платформы (Linux) или языка (Си). Rosegarden с Qtractor'ом ведь как-то справляются и на обычном шедулинге?

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

> а вы уверены, что они справляются?

Скажем так, меня бы удовлетворило справляться на таком же уровне :-)

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

> sched_setscheduler(..., SCHED_FIFO, ...); не поможет?

для SCHED_FIFO необходимо иметь соответствующие права, которые по дефолту только рут имеет.

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

> в частности, от SIGSTOP

это тебя вообще не должно беспокоить.

> или гибернации

а в чём проблема? тебе приходит сообщение об опустошении буфера и ты сверяешь время, если оно неприлично большое — ресинхронизация.

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

>для SCHED_FIFO необходимо иметь соответствующие права, которые по дефолту только рут имеет.

Да это понятно. Но можно же ту часть программы, которой нужно RT вынести в аккуратно написанный демон с suid битом?

AptGet ★★★
()

> Как в таких условиях обеспечить равномерно «ползущий» указатель проигрывания (так называемый playhead)?

А мне-то всю жизнь казалось, что плеер ориентируется не на системные часы, а на позицию в потоке.

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

> А мне-то всю жизнь казалось, что плеер ориентируется не на системные часы, а на позицию в потоке.
> плеер

Речь идёт не о плеере, а о секвенсере. Примеры: MIDI sequencer, система управления сценическим освещением, система векторной анимации.

Посему никакого «потока» и позиции в нём нет. ( arsi, и никаких «буферов» и «опустошения» тоже.) Есть список событий с их запланированным временем наступления. Необходимо обеспечить наступление событий с максимальной точностью по времени.

Для этого я предлагаю:
ждать в цикле некоторыми квантами (например, по 25 миллисекунд),
вычислять, сколько реально прошло времени,
давать приращение позиции playhead,
инициировать события, если пришло их время.

Проблема в том, что мы можем круто проспать событие. Очнувшись после очередного sleep'а, можем с удивлением обнаружить (базируясь на показаниях системных часов), что прошло не 25 миллисекунд, а все 250, а то и круче. У вас есть предложения, как бороться с такими ситуациями?

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

Кстати, не поленился поэкспериментировать. Для программ на Си и Java при кванте 25 мс отставание обычно находится в пределах до 7 мс. Максимальное отставание, которого удалось добиться путём насилия над компьютером - 70 мс для Си и 290 мс для Java. Насилие заключалось в запуске Firefox на фоне сброшенных кэшей, dd if=/dev/urandom, свапа и прочего 12309. Сишная программа значительно лучше держит удар, редко выбиваясь за 7 мс.

Кстати, sched_setscheduler(0, SCHED_FIFO, ...) сделать не даёт, даже под рутом. Ядро 2.6.36, не реалтаймовое.

Ochkarik
() автор топика
Ответ на: комментарий от Ochkarik
[~]$ ./test
sched_setscheduler: Operation not permitted
[~]$ su -c 'chown root test && chmod +s test'
Пароль:
[~]$ ./test &
[2] 30751
[~]$ chrt -p `pgrep test`
pid 30751's current scheduling policy: SCHED_FIFO
pid 30751's current scheduling priority: 30
[~]$ Tick!
Tick!

[~]$ cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>

int main (int argc, char **argv) {
        int i;
        struct sched_param param;

        param.sched_priority = 30;

        if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
                perror("sched_setscheduler");
                exit(0);
        }

        for (i = 0; i < 10; i++) {
                sleep(10);
                printf("Tick!\n");
        }

        exit(0);
}

[~]$ uname -rs
Linux 2.6.18-274.3.1.el5PAE

AptGet ★★★
()

> Исходные тексты Qtractor, Rosegarden и т.п. у меня есть

Они не при чем, кури исходники JACK.

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