LINUX.ORG.RU

copy_to_user из прерывания

 


1

3

В дополнение к моей предыдущей теме, возникло непонимание, которое пока не сильно устранилось чтением LDD и SO. Требуется реализовать blocking read, по этому есть темы как в LDD так и на SO, сам механизм blocking read не вызвал затруднений.

Я выделил DMA буфер на 256 Кбайт, через MMIO передаю адрес этого буфера и он успешно заполняется, после чего приходит прерывание, в котором можно инициировать чтение следующего блока. Скорость около 170 Мбайт/с (если запросить гигабайт).

Возникла проблема при реализации char device, а именно операции read. Если осуществить copy_to_user в самом этом вызове то всё успешно читается на стороне userspace (cat, dd). Однако в обработчике прерывания copy_to_user не работает, хотя бы потому что он может сам уходить в sleep, что очевидно недопустимо для ISR.

Как же тогда быть? Допустим я запросил прочитать мегабайт из устройства, а буфер 256К - нужно при получении прерывания проснуться и вернуть лишь 256К а пользователь будет затем повторять запросы чтения четыре раза с разным offset (у char-то устройства)? Например dd bs=1M count=1 не повторит.

Нужно выделить буфер в драйвере на мегабайт и затем после его заполнения уже просыпаться и делать copy_to_user всего мегабайта? Получается двойное копирование.

slapin tailgunner ebantrop Andrey_Utkin :)

Ответ на: комментарий от I-Love-Microsoft

ну как тебе сказать...

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

Если ты данные извлекаешь в прерывании, то тебе необходима буферизация. Иначе ты заводишь кернеловый тред, который периодически будишь для копирования. И данные ты должен куда-то сложить всё-равно, так как юзерспейс может их почитать чуть позже. Если ты согласен дропать данные, пока их никто не читает, то можно делать вычитывание железа прямо из read. То есть тут вопрос структуры данных - если у тебя пакетная структура, то тебе нужен буфер на пакет, можешь написать свой драйвер как драйвер сетевухи, тогда ядро эти нужные 2 копирования сделает за тебя. Но в этом случае непрочитанные пакеты будут также дропаться.

Если у тебя просто байтовый поток и ты согасен дропать данные, можешь вычитывать данные прямо в .read по запросу userspace. Из прерывания в таком случае просто через event разблокируем read если что-то пришло, а в read читаем прямо из железки. fifo не используем. Скорость достижения байтами конечного назначения тут будет выше за счет отсутствия буферизации, но дойдут ли байты - зависит от удачи, но я знавал случаи успешного применения данной схемы.

Если нужно, чтобы данные не терялись и флкутуации в userspace не приводили к потерям, я бы советовал использовать kfifo. Но скорость достижения конкретным байтом точки назначения может быть ниже за счёт буферизации.

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

Если ты данные извлекаешь в прерывании, то тебе необходима буферизация. Иначе ты заводишь кернеловый тред, который периодически будишь для копирования.

Зачем? Железка заполняет буфер через DMA, а обработчик прерывания просто извлекает заполненные буферы из очереди и сообщает железке о новых.

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

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

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

Не важно кто делает копирование, важно, что оно есть.

Ну речь шла о нити ядра, которая (по крайней мере, без kfifo) не нужна. А вместо копирования можно просто мапить заполненный DMA буфер в юзерспейс, но это, конечно, мало кому нужно.

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

Мапить заполненный буфер не так просто, не факт что в итоге быстрее получится, тут надо больше знать о том, что с данными потом делать надо будет. Китайцы вон, камерами через /dev/mem рулят, и ничего... только тормозит... немного :) Если нет критической необходимости выжать максимум я за kfifo. mmap - это контекст-свитчи, синхронизация, фу. Особенно если это просто поток байт.

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

Мапить заполненный буфер не так просто, не факт что в итоге быстрее получится

Получится.

mmap - это контекст-свитчи, синхронизация

Эээ... щито? Нет там ни переключений контекста, ни синхронизации.

Особенно если это просто поток байт.

Если просто поток байт - конечно. Но, по-меому, у ТС не совсем поток байт.

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

kfifo чтобы положить в буфер не требует нить ядра, так как не спит и не требует блокировок.

Короче, я вижу недопонимание по поводу kfifo

https://lwn.net/Articles/237850/

То есть мы заполняем kfifo с помощью DMA а извлекаем в character device. То есть мы дополнительно не копируем из буфера DMA в kfifo.

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

Если там пакеты, и здоровые, то есть выигрыш от mmap. Если мы отдаём кэшируемую память обычную, и заново зааллоцированную, то возникает необходимость освободить буфер после обработки userspace. Также трудности бывают, если эта память непосредственно не работает с DMA (так как берётся из userspace map'а), приходится использовать bouncer. Тут стоит посмотреть на менеджмент буферов в video4linux. И городить всю эту радость стоит только если это очень нужно. Можно аллоцировать в ядре а потом перемапливать в userspace, но это тоже медленно. А если не перемапливать, тогда совсем беда. Если пакеты маленькие, не стоит этим заниматься.

ТС, что у тебя за данные вообще?

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

С другой стороны можно использовать механизм DMABUFs, зааллоцированных userspace, думаю вот это может быть эффективно. Наверное это годный солюшн для ТС в случае пакетного протокола (если пакеты не по 10 байт).

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

kfifo чтобы положить в буфер не требует нить ядра, так как не спит и не требует блокировок.

А кому она требуется?

https://lwn.net/Articles/237850/

Ну вот как раз здесь есть и синхронизация, и сон.

Я не против kfifo, но, судя по названию, оно сделано для потока байтов, а у ТС чуть ли не блочный девайс

Если мы отдаём кэшируемую память обычную, и заново зааллоцированную, то возникает необходимость освободить буфер после обработки userspace

Не понял, причем тут кэшируемость и аллоцируемость, но, естественно, юзерспейс отдает память обратно драйверу - вызовом munmap. У драйвера есть пул страниц, устройство заполняет часть из них, драйвер помечает заполненные одной DMA-транзакцией страницы как мапабельные и позволяет юзерспейсу из мапить (вместо чтения). Когда юзерспейс обработал данные, он их отмапливает и драйвер возвращает их в свой пул.

И городить всю эту радость стоит только если это очень нужно.

Это да.

Можно аллоцировать в ядре а потом перемапливать в userspace, но это тоже медленно.

Почему? У меня это работало гораздо быстрее, чем read (который копировал данные из ядра в юзерспейс).

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

То есть мы заполняем kfifo с помощью DMA а извлекаем в character device. То есть мы дополнительно не копируем из буфера DMA в kfifo.

У меня на неделю нет доступа устройству в связи с отъездом, изучаю теоретическую матчасть. Да, я обратил внимание на DMA-возможности этого kfifo. И сразу мысль - что если сразу в него будут данные падать.

Но я понял свою ошибку - раз у меня char device то я могу работать как я и написал в первом посте, не обращая внимание на то как это будет работать с dd. В самом деле, cat запрашивает 32 килобайта (ну такой там объем по дефолту), если нет новых данных - я инициирую передачу из устройства и засыпаю, а если есть - то оставшиеся 7 обращений будут без засыпания выдавать данные по 32К (всего например 256К).

Что за данные и каков их формат? Пока тупо поток байт, которые надо переместить из устройства в программа максимально быстро, без потерь. ПЛИС генерирует паттер, по которому легко понять были ли потери и разрывы данных. Какое это будет устройство - станет ясно потом, а пока - чисто академический интерес.

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