Какова мотивация этого условия 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, это в любом случае верно.