Bursty пишет на SD / USB, останавливая мои критичные ко времени приложения на встроенном Linux - PullRequest
13 голосов
/ 17 сентября 2008

Я работаю над проектом встроенного Linux, который связывает ARM9 с аппаратным чипом видеокодера и записывает видео на SD-карту или USB-накопитель. Архитектура программного обеспечения включает драйвер ядра, который считывает данные в пул буферов, и приложение пользователя, которое записывает данные в файл на смонтированном съемном устройстве.

Я обнаружил, что выше определенной скорости передачи данных (около 750 Кбайт / с) я начинаю видеть, как приложение для записи видео пользователя останавливается на полсекунды, примерно каждые 5 секунд. Этого достаточно, чтобы драйвер ядра исчерпал буферы - и даже если бы я мог увеличить количество буферов, видеоданные должны быть синхронизированы (в идеале в пределах 40 мс) с другими вещами, которые происходят в режиме реального времени. В промежутке между этими 5-секундными «скачками задержки» записи завершаются в течение 40 мс (что касается приложения - я ценю, что они буферизируются ОС)

Я думаю, что этот скачок отставания связан с тем, как Linux записывает данные на диск - я отмечаю, что pdflush предназначен для пробуждения каждые 5 секунд, я понимаю, что это будет то, что делает запись. Как только остановка завершена, приложение пользователя может быстро обслуживать и записывать резервные копии буферов (которые не переполняются).

Я думаю, что устройство, на которое я пишу, имеет разумную предельную пропускную способность: копирование 15 МБ файла из памяти fs и ожидание завершения синхронизации (и индикатор usb-флешки перестает мигать) дали мне скорость записи около 2,7 МБ /sec.

Я ищу два вида подсказок:

  1. Как я могу помешать пакетной записи блокировать мое приложение - возможно, обрабатывать приоритеты, исправления в реальном времени или настраивать код файловой системы для непрерывной, а не прерывистой записи?

  2. Как я могу сообщить своим приложениям о том, что происходит с файловой системой, с точки зрения невыполнения записи и пропускной способности карты / флешки? У меня есть возможность изменять битрейт видео в аппаратном кодеке на лету, что было бы намного лучше, чем отбрасывание кадров или наложение искусственного ограничения на максимально допустимый битрейт.

Еще немного информации: это 200MHz ARM9, в настоящее время работающий на ядре Montavista 2.6.10.

Обновление:

  • Монтирование файловой системы SYNC приводит к слишком низкой пропускной способности.
  • Съемный носитель отформатирован в FAT / FAT32 и должен быть задан, так как цель этого проекта - чтобы носитель можно было подключить к любому ПК с Windows и прочитать.
  • Регулярный вызов sync () или fsync (), скажем, каждая секунда вызывает регулярные задержки и недопустимо низкую пропускную способность.
  • Я использую write () и open (O_WRONLY | O_CREAT | O_TRUNC), а не fopen () и т. Д.
  • Я не могу сразу найти в Интернете что-либо об упомянутых "файловых системах Linux реального времени". Ссылки?

Надеюсь, это имеет смысл. Первый вопрос по встроенному Linux на stackoverflow? :)

Ответы [ 10 ]

10 голосов
/ 19 октября 2008

Для справки, оказалось, что есть два основных аспекта, которые, кажется, устранили проблему во всех, кроме самых крайних случаев. Эта система все еще находится в разработке и еще не прошла тщательных испытаний на пытки, но работает довольно хорошо (дотронуться до дерева).

Большая победа была достигнута благодаря тому, что приложение userland writer стало многопоточным. Иногда вызовы write () блокируют: другие процессы и потоки все еще работают. Пока у меня есть поток, обслуживающий драйвер устройства и обновляющий количество кадров и другие данные для синхронизации с другими работающими приложениями, данные могут быть буферизованы и записаны через несколько секунд без нарушения сроков. Сначала я попробовал простой двойной буфер для пинг-понга, но этого было недостаточно; маленькие буферы будут перегружены, а большие просто вызовут большие паузы, пока файловая система переваривает записи. Пул из 10 1 МБ буферов, поставленных в очередь между потоками, теперь работает хорошо.

Другим аспектом является отслеживание максимальной пропускной способности записи на физический носитель. Для этого я слежу за статистикой Dirty: сообщается / proc / meminfo. У меня есть некоторый грубый и готовый код для регулирования энкодера, если Dirty: поднимается выше определенного порога, кажется, работает неопределенно. Дополнительные испытания и настройки понадобятся позже. К счастью, у меня есть много оперативной памяти (128 МБ), чтобы дать мне несколько секунд, чтобы увидеть, как мое отставание растет и плавно сокращается.

Я постараюсь вспомнить и обновить этот ответ, если обнаружу, что мне нужно что-то еще сделать, чтобы решить эту проблему. Спасибо другим ответчикам.

4 голосов
/ 17 сентября 2008

Я выкину несколько предложений, совет дешевый.

  • убедитесь, что вы используете API нижнего уровня для записи на диск, не используйте функции кэширования в пользовательском режиме, такие как fopen, fread, fwrite, используйте функции нижнего уровня open, read, write.
  • при открытии файла передается флаг O_SYNC, это приведет к блокировке каждой операции записи до записи на диск, что приведет к удаленному пакетному поведению ваших записей ... за счет того, что каждая запись будет медленнее.
  • Если вы выполняете операции чтения / ioctl с устройства для захвата порции видеоданных, вы можете рассмотреть вопрос о выделении области общей памяти между приложением и ядром, в противном случае вы получите удар по copy_to_user при передаче буферов видеоданных из пространства ядра в пространство пользователя.
  • Возможно, вам понадобится проверить, достаточно ли быстрой записи на вашем USB-устройстве флэш-памяти для записи данных.

Просто пара мыслей, надеюсь, это поможет.

3 голосов
/ 17 сентября 2008

Здесь - некоторая информация о настройке pdflush для операций с интенсивной записью.

2 голосов
/ 17 сентября 2008

Похоже, вы ищете файловые системы Linux в реальном времени. Обязательно поищите в Google и др.

XFS имеет опцию в реальном времени, хотя я не играл с ней.

hdparm может полностью отключить кеширование.

Настройка параметров файловой системы (отключение всех лишних ненужных атрибутов файла) может уменьшить объем ненужной очистки, тем самым ускоряя очистку. Хотя я сомневаюсь, что это сильно поможет.

Но я бы предложил вообще не использовать флешку в качестве файловой системы, а вместо этого использовать ее в качестве необработанного устройства. Заполните данные, как если бы вы использовали 'dd'. Затем в другом месте прочитайте эти необработанные данные и запишите их после выпечки.

Конечно, я не знаю, подходит ли вам этот вариант.

1 голос
/ 18 ноября 2010

Мне сказали, что после того, как хост отправляет команду, карты MMC и SD "должны отвечать в пределах от 0 до 8 байтов".

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

Я вижу, что некоторые недорогие флеш-чипы, такие как M25P80, имеют гарантированное "максимальное время стирания одного сектора", равное 3 секундам, хотя обычно для этого "только" требуется 0,6 секунды.

Эти 0,6 секунды звучат подозрительно похоже на ваше "сваливание на полсекунды".

Я подозреваю, что компромисс между дешевыми, медленными флеш-чипами и дорогими, быстрыми флеш-чипами как-то связан с широким разбросом результатов USB-накопителей:

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

Таким образом, если у вас есть приложение, критичное ко времени, вам может потребоваться (а) проверить свои карты SD и USB-накопители, чтобы убедиться, что они соответствуют минимальной задержке, полосе пропускания и т. Д., Требуемым вашим приложением, и (б) периодически повторно протестируйте или предварительно замените эти устройства памяти.

1 голос
/ 18 сентября 2008

Полезной функцией Linux и альтернативой sync или fsync является sync_file_range. Это позволяет планировать данные для записи, не дожидаясь, пока буферная система в ядре дойдет до нее.

Чтобы избежать длинных пауз, убедитесь, что ваша очередь ввода-вывода (например: / sys / block / hda / queue / nr_requests) достаточно велика. В этой очереди данные помещаются между сбросом из памяти и поступлением на диск.

Обратите внимание, что sync_file_range не является переносимым и доступен только в ядрах 2.6.17 и новее.

1 голос
/ 17 сентября 2008

Имеет вспомогательное средство отладки, вы можете использовать strace, чтобы увидеть, какие операции занимают время. С FAT / FAT32 может быть что-то удивительное.

Вы пишете в один файл или в несколько файлов?

Вы можете создать поток чтения, который будет поддерживать пул видеобуфера, готовый для записи в очередь. Когда кадр получен, он добавляется в очередь, и поток записи сигнализируется

Общие данные

empty_buffer_queue
ready_buffer_queue
video_data_ready_semaphore

Чтение темы:

buf=get_buffer()
bufer_to_write = buf_dequeue(empty_buffer_queue)
memcpy(bufer_to_write, buf)
buf_enqueue(bufer_to_write, ready_buffer_queue)
sem_post(video_data_ready_semaphore)

Написание темы

sem_wait(vido_data_ready_semaphore)
bufer_to_write = buf_dequeue(ready_buffer_queue)
write_buffer
buf_enqueue(bufer_to_write, empty_buffer_queue)

Если запись в потоке заблокирована в ожидании ядра, это может сработать. Однако, если вы заблокированы внутри пространства Kerne, вы ничего не можете сделать, кроме как искать более свежее ядро, чем ваш 2.6.10

.
1 голос
/ 17 сентября 2008

Не зная больше о ваших конкретных обстоятельствах, я могу предложить только следующие предположения:

Попробуйте использовать fsync () / sync (), чтобы заставить ядро ​​чаще сбрасывать данные на устройство хранения. Похоже, ядро ​​буферизует все ваши записи, а затем связывает шину или иным образом останавливает вашу систему во время выполнения фактической записи. С осторожными вызовами fsync () вы можете попытаться запланировать записи по системной шине более детально.

Возможно, имеет смысл структурировать приложение таким образом, чтобы задача кодирования / захвата (вы не упомянули захват видео, поэтому я делаю здесь предположение - возможно, вы захотите добавить больше информации) запускается в своей задаче. собственный поток и буферизует его вывод в пользовательском пространстве - тогда второй поток может обрабатывать запись на устройство. Это даст вам буфер сглаживания, чтобы кодировщик всегда заканчивал свои записи без блокировки.

Одна вещь, которая звучит подозрительно, это то, что вы видите эту проблему только при определенной скорости передачи данных - если бы это действительно была проблема с буферизацией, я бы ожидал, что проблема будет возникать реже при более низких скоростях передачи данных, но я все же ожидал бы чтобы увидеть эту проблему.

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

Учитывая предоставленную вами дополнительную информацию, похоже, что пропускная способность устройства довольно мала для небольших записей и частых сбросов. Если вы уверены, что для больших операций записи вы можете получить достаточную пропускную способность (и я не уверен, что это так, но файловая система может делать что-то глупое, например, обновлять FAT после каждой записи), тогда иметь данные о потоках кодирования потоку записи с достаточной буферизацией в потоке записи, чтобы избежать зависаний. В прошлом я использовал кольцевые буферы с общей памятью для реализации такого рода схемы, но любой механизм IPC, который позволял бы записывающему устройству записывать в процесс ввода-вывода без остановки, если буфер не переполнен, должен справиться с задачей.

0 голосов
/ 17 сентября 2008

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

Это может быть очевидным, но убедитесь, что вы не вызываете write () слишком часто - убедитесь, что у каждой write () достаточно данных для записи, чтобы оправдать затраты на системный вызов. Кроме того, в другом направлении, не вызывайте его слишком редко, иначе он будет блокироваться достаточно долго, чтобы вызвать проблему.

На более сложном для повторения пути вы пытались переключиться на асинхронный ввод-вывод? Используя aio, вы можете запустить запись и передать ей один набор буферов, пока вы всасываете видеоданные в другой набор, а когда запись завершится, вы переключаете наборы буферов.

0 голосов
/ 17 сентября 2008

Ну, во-первых, очевидно, вы пытались явно указать файлу сброс? Я также думаю, что может быть какой-то ioctl, который вы можете использовать для этого, но, честно говоря, я мало занимался программированием файлов на C / POSIX.

Видя, что вы работаете с ядром Linux, вы сможете настроить и перестроить ядро ​​под то, что лучше соответствует вашим потребностям, например. гораздо более частые, но затем и более мелкие сбросы в постоянное хранилище.


Быстрая проверка в моих справочных страницах находит это:

SYNC(2)                    Linux Programmer’s Manual                   SYNC(2)

NAME
       sync - commit buffer cache to disk

SYNOPSIS
       #include <unistd.h>

       void sync(void);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       sync(): _BSD_SOURCE || _XOPEN_SOURCE >= 500

DESCRIPTION
       sync() first commits inodes to buffers, and then buffers to disk.

ERRORS
       This function is always successful.
...