Почему драйвер 8250 UART не активирует TTY, если ожидается более 256 символов?

8

Какова мотивация этого if-условия в void serial8250_tx_chars(struct uart_8250_port *up)?

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
    uart_write_wakeup(port);

Он существует с Linux 1.1.13 (май 1994 г.) и повторяется в большинстве драйверов UART.

Справочная информация: настроенный Linux 3.4.91, встроенная система на ARMv7, порт 0 UART настроен на 38400 бод, 16-байтовый FIFO для ввода-вывода. Ничто из этого не может быть изменено в нашей настройке.

При очень интенсивной печати на консоли через UART внутренний 4kB-buffer ( UART_XMIT_SIZE) заполняется, а затем останавливает процесс пользовательского пространства до тех пор, пока не будет очищен буфер (который занимает одну секунду со скоростью 38400 бод!). Затем это поведение повторяется. Это происходит потому, что функция n_tty_write()переходит в спящий режим, когда буфер заполнен, и долго не просыпается из-за сомнительного условия, описанного выше.

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

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

В качестве дополнительного вопроса: есть ли параметры конфигурации для настройки этого поведения, например, чтобы printf всегда возвращал немедленно и отбрасывал вывод, если буфер заполнен?

Ханс В. Хеккель
источник
Не зная об этом, я догадываюсь, что это обычная настройка последовательной консоли Linux. Я работал с ними на стандартном оборудовании x86. Для прямых последовательных соединений мне всегда приходилось использовать аппаратное управление потоком. Может быть идея.
Васкес
1
Вероятно, есть разница в эффективности. Почему бы просто не установить для WAKEUP_CHARS что-то вроде UART_XMIT_SIZE - 128?
Джеймс Янгман
@JamesYoungman На самом деле, это то, что я тоже делал. Ура!
Ханс В. Хеккель

Ответы:

2

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

$ time dd if=/dev/zero of=/dev/null bs=1 count=10000000
10000000+0 records in
10000000+0 records out
10000000 bytes (10 MB, 9.5 MiB) copied, 5.95145 s, 1.7 MB/s

real    0m5.954s
user    0m1.960s
sys     0m3.992s

$ time dd if=/dev/zero of=/dev/null bs=1000 count=10000
10000+0 records in
10000+0 records out
10000000 bytes (10 MB, 9.5 MiB) copied, 0.011041 s, 906 MB/s

real    0m0.014s
user    0m0.000s
sys     0m0.012s

Вышеупомянутый тест даже не читает и не записывает реальное устройство: разница во времени заключается в том, как часто система отскакивает от пространства пользователя от пространства ядра.

Если пользовательское пространство не хочет удерживаться, оно может использовать неблокирующий ввод-вывод или может проверить использование select()вызова, чтобы увидеть, есть ли место для записи на устройство ... а если нет, оно может сбросить остаток в свой собственный буфер и продолжить обработку. Надо признать, что это усложняет ситуацию, поскольку теперь у вас есть буфер, который вы должны очистить ... но если вы используете stdio, это в общем случае так или иначе.

Jander
источник
Это поддерживает комментарий @James об эффективности выше. Теперь это имеет гораздо больше смысла для меня. Спасибо также за цифры!
Ханс В. Хеккель
Следует отметить, что, начиная с ядра 2.6, этот вопрос ссылается на код, который часто появляется в драйверах нижнего уровня (например, в драйвере UART). Эти драйверы предоставляют более высокий уровень, serial_core, средство взаимодействия с оборудованием. Это последовательное ядро, которое фактически взаимодействует с пространством пользователя (если драйвер оборудования не реализует свои собственные ioctl или что-то подобное). Я считаю, что ответ респондентов по-прежнему имеет место.
Эндрю Фаланга