Por que o driver 8250 UART não acorda o TTY se mais de 256 caracteres estão pendentes?

8

Qual é a motivação desta condição if em void serial8250_tx_chars(struct uart_8250_port *up) ?

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

Ele existe desde o Linux 1.1.13 (maio de 1994) e se repete na maioria dos drivers UART.

Histórico: Linux personalizado 3.4.91, sistema embarcado no ARMv7, a porta UART 0 está configurada para 38400 baud, FIFO de 16 bytes para i / o. Nada disso pode ser alterado em nossa configuração.

Ao imprimir muito muito no console via UART, o buffer interno de 4kB ( UART_XMIT_SIZE ) é preenchido e, em seguida, paralisa o processo de espaço do usuário até o buffer é esvaziado (o que leva um segundo a 38400 baud!). Então este comportamento se repete. Isso ocorre porque a função n_tty_write() entra em suspensão quando o buffer está cheio e não é acordada por um longo tempo devido à condição questionável acima.

Eu acharia mais natural e eficiente se essa verificação fosse simplesmente removida. Em seguida, os printfs preenchiam o buffer o mais rápido possível, e continuam na velocidade em que o buffer está sendo esvaziado , em vez do processamento de estouro que estou observando.

Funciona bem no meu ambiente, mas certamente estou perdendo ou entendendo mal alguma coisa. Deve haver um motivo para a implementação atual. Há algum efeito colateral se eu remover essa condição?

Como pergunta secundária: há opções de configuração para ajustar esse comportamento? ter printf sempre retornar imediatamente e descartar a saída se o buffer estiver cheio?

    
por Hans W. Heckel 04.11.2015 / 15:19

1 resposta

2

É uma medida de eficiência. A CPU roda muito mais rápido que a porta serial, se o kernel permitir que o processo userspace seja executado toda vez que houver um pouco de espaço no buffer, ele acabará fazendo uma viagem ao userspace e retornando para cada byte de dados. Isso é muito desperdício de tempo de CPU:

$ 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

O teste acima não é nem mesmo ler e escrever um dispositivo real: toda a diferença de tempo é a freqüência com que o sistema está pulando entre o userspace e o kernelspace.

Se o espaço do usuário não quiser ser retido, ele poderá usar a E / S sem bloqueio ou poderá usar uma chamada select() para ver se há espaço para gravar no dispositivo ... e se houver não, pode despejar o restante em um buffer próprio e continuar processando. Evidentemente, isso complica as coisas, já que agora você tem um buffer que precisa liberar ... mas se você estiver usando o stdio, isso geralmente é verdade mesmo assim.

    
por 26.04.2016 / 02:16