에서 이 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의 임베디드 시스템, UART 포트 0은 i/o용 38400 보드, 16바이트 FIFO로 구성됩니다. 이 중 어느 것도 설정에서 변경할 수 없습니다.
인쇄할 때매우UART를 통해 콘솔에 과부하가 걸리면 내부 4kB 버퍼( UART_XMIT_SIZE
)가 채워지고노점버퍼가 비워질 때까지 사용자 공간 프로세스를 수행합니다(38400보드에서 1초 소요). 그러면 이런 행동이 반복됩니다. 이는 n_tty_write()
버퍼가 가득 차면 함수가 Sleep 상태가 되고, 위의 문제로 인해 오랫동안 깨어나지 않기 때문입니다.
이 검사를 간단히 제거하면 더 자연스럽고 효율적이라고 생각합니다. 그런 다음 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를 사용하는 경우 어쨌든 그것은 일반적으로 사실입니다.