처리 대기 중인 문자가 256개가 넘는 경우 8250 UART 드라이버가 TTY를 깨울 수 없는 이유는 무엇입니까?

처리 대기 중인 문자가 256개가 넘는 경우 8250 UART 드라이버가 TTY를 깨울 수 없는 이유는 무엇입니까?

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년 5월)부터 존재했으며 대부분의 UART 드라이버에서 반복됩니다.

배경: 사용자 정의 Linux 3.4.91, ARMv7의 임베디드 시스템, 38400 전송 속도로 구성된 UART 포트 0, I/O용 16바이트 FIFO. 우리 설정에서는 이를 변경할 수 없습니다.

printf 할 때매우UART를 통해 콘솔에서 내부 4kB 버퍼( UART_XMIT_SIZE)가 채워지고마구간버퍼가 플러시될 때까지 사용자 공간 프로세스를 수행합니다(38400보드에서 1초가 소요됩니다!). 그런 다음 동작이 반복됩니다. n_tty_write()앞서 언급한 의심스러운 상황으로 인해 버퍼가 가득 차면 해당 기능이 절전 모드로 들어가고 오랜 시간 동안 깨어나지 않기 때문입니다 .

이 검사를 간단히 제거하면 더 자연스럽고 효율적이라고 생각합니다. 그러면 printfs는 가능한 빨리 버퍼를 채울 것입니다.그런 다음 버퍼 비우기 속도로 계속 진행합니다., 내가 관찰하고 있는 버스트 처리보다는

내 환경에서는 잘 작동하지만 분명히 뭔가 빠졌거나 오해하고 있습니다. 현재 구현에는 이유가 있어야 합니다. 이 상태를 없애면 부작용이 있나요?

부가 질문으로: printf가 항상 즉시 반환되도록 하고 버퍼가 가득 차면 출력을 삭제하는 등 이 동작을 조정하는 구성 옵션이 있습니까?

답변1

이는 효율성 측정입니다. CPU는 직렬 포트보다 훨씬 빠르게 실행되며, 버퍼에 약간의 공간이 있을 때마다 커널이 사용자 공간 프로세스를 실행하도록 허용하면 결국 모든 데이터 바이트에 대해 사용자 공간으로 왕복하게 됩니다. 이는 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

위의 테스트는 실제 장치를 읽고 쓰는 것도 아닙니다. 전체 시간 차이는 시스템이 사용자 공간과 커널 공간 사이를 얼마나 자주 점프하는지입니다.

사용자 공간이 차단되기를 원하지 않으면 비차단 I/O를 사용하거나 호출을 사용하여 select()장치에 쓸 공간이 있는지 확인할 수 있습니다. 그렇지 않은 경우 나머지를 다음 공간에 덤프할 수 있습니다. 자체 버퍼를 사용하고 처리를 계속합니다. 물론, 이제 플러시해야 하는 버퍼가 있기 때문에 상황이 복잡해집니다. 하지만 이는 일반적으로 stdio를 사용하는 경우에 해당됩니다.

관련 정보