Приоритет модулей ядра и потоков SCHED_RR

#c #c #linux #real-time #scheduling

#c #c #linux #в режиме реального времени #планирование

Вопрос:

У меня есть встроенная платформа Linux (Beagleboard, работающая под управлением Angstrom Linux) с двумя подключенными устройствами:

  • лазерный дальномер (Hokuyo UTM 30), подключенный через USB
  • пользовательская внешняя плата, подключенная через SPI

У нас есть написанный модуль ядра Linux, который отвечает за передачу данных SPI. Он имеет обработчик IRQ, в котором вызывается spi_async, который, в свою очередь, вызывает метод обратного асинхронного вызова.

Мое приложение на C состоит из трех потоков:

  • основной поток для обработки данных
  • поток лазерного опроса
  • поток опроса SPI

Я испытываю проблемы, которые, по-видимому, вызваны тем, как взаимодействуют модули, описанные выше.

  • Когда я выключаю USB-устройство (лазерный дальномер) Я получаю все сообщения SPI правильно (1 сообщение каждые 3 мс, длина сообщения, деленная на скорость передачи данных, составляет <1 мс), независимо от планирования потоков
  • Когда я включаю USB-устройство и запускаю свою программу с обычным планированием потоков (SCHED_OTHER, приоритет 0, не установлен хороший уровень), около 1% сообщений «теряется», потому что метод обратного вызова spi_async запускается при возникновении следующего IRQ (я мог бы обработать этот случай по-другому, чтобы непотерять сообщения, так что это не большая проблема.)
  • При включенном USB-устройстве я запускаю программу с помощью SCHED_RR и

    • приоритет = 10 для основного потока
    • приоритет = 10 для потока чтения SPI
    • приоритет = 4 для потока опроса USB / Laser

    затем я теряю 40% сообщений, потому что IRQ запускается снова до вызова метода обратного вызова spi! (Я все еще мог бы найти обходной путь, но проблема в том, что мне нужно быстрое время отклика, которое в этом случае больше не может быть достигнуто). Мне нужно использовать планирование потоков и лазерное устройство, поэтому я ищу способ решить этот случай.

Вопрос 1:

Я предполагал, что обработчики IRQ и обратные вызовы, запускаемые spi_async в пространстве ядра, имеют более высокий приоритет, чем любой поток, запущенный в пространстве пользователя (независимо от того, SCHED_RR или SCHED_OTHER). Это означало бы, что обращение к SCHED_RR в моем приложении не должно замедлять передачу SPI, но это кажется очень неправильным. Так ли это?

Вопрос 2:

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

—— РЕДАКТИРОВАТЬ:

Я сделал следующее наблюдение:

Обратный вызов wake_up_interruptible(amp;mydata->readq); spi_async вызывает (с wait_queue_head_t readq; ). Из пользовательского пространства (мое приложение) Я вызываю функцию, которая приводит к poll_wait(file, amp;mydata->readq, wait); тому, что опрос возвращает вызовы пользовательского пространства read() .

  • Когда мое приложение запускается с SCHED_OTHER , я вижу, что метод обратного вызова сначала завершается до read() ввода метода в моем модуле ядра.
  • Когда мое приложение запускается с SCHED_RR чтением, вводится перед выходом из обратного вызова.

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

Комментарии:

1. Что делают ваши потоки, когда нечего делать? (т. Е. Они что-то вращают / опрашивают или как-то блокируют? Если они где-то крутятся, вы будете потреблять тонну процессора, а задержка будет стремительно расти при использовании планировщика реального времени)

2. основной поток блокируется по завершении обработки (обычно 0,5 мс), лазерный поток блокируется, когда нет данных о последовательном соединении, а потоки spi блокируются, когда нет новых сообщений SPI. Загрузка процессора составляет <50%.

3. Единственный способ возиться с приоритетом отложенной работы — это изменить главный драйвер spi.

Ответ №1:

Не все потоки ядра имеют приоритет RT. Представьте, что периодически просыпающийся поток, который должен выполнять некоторую фоновую работу, просыпается. Вы не хотите, чтобы этот поток вытеснял ваш поток RT. Итак, я предполагаю, что ваше первое предположение неверно.

На основе ваших других вопросов :

  • ваш основной цикл обработки получает данные SPI через очередь
  • поток обработки spi загружает основную очередь обработки

Кажется, ваш основной поток обработки мешает потоку драйвера spi, отвечающему за передачу данных spi.

Вот что происходит :

  • запускается IRQ
  • вызывается spi_async, что означает, что передача данных ставится в очередь, которая будет подхвачена потоком, созданным главным драйвером spi.
  • главный поток spi конкурирует с вашим основным потоком обработки, потоком laser, но этот поток ядра не имеет приоритета RT, поэтому он проигрывает каждый раз, когда выполняется один из потоков RR.

Что вы можете сделать, так это вернуться к обычному планированию, играя с различными параметрами CONFIG_PREEMPT_. Или возитесь с основным драйвером spi, чтобы гарантировать, что любая отложенная работа ставится в очередь с достаточным приоритетом. Или даже вообще не ставится в очередь.

Комментарии:

1. В документации для spi_sync говорится: «Этот вызов может использоваться только из контекста, который может спать», что не относится к IRQ, верно?

2. Хорошо, текущий API ядра полностью асинхронный, с некоторой оболочкой синхронизации.

3. Вы можете использовать request_threaded_irq и вызывать функции, которые могут находиться в режиме ожидания в обработчике irq.