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

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

Какова мотивация этого условия 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, порт UART 0 настроен на 38400 бод, 16-байтовый FIFO для ввода-вывода. Ничего из этого нельзя изменить в нашей настройке.

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

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

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

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

решение1

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

$ 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, это в любом случае верно.

Связанный контент