void serial8250_tx_chars(struct uart_8250_port *up)
のこのif条件の動機は何ですか?
_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は38400ボー、16バイトFIFO for i/o用に構成されています。これは、セットアップで変更できます。
UARTを介してコンソールでveryを大量に印刷すると、内部4kBバッファ(_UART_XMIT_SIZE
_)がいっぱいになり、stallsユーザースペースプロセスがバッファが空になります(38400ボーで1秒かかります!)。その後、この動作が繰り返されます。これは、関数n_tty_write()
がバッファがいっぱいになるとスリープ状態になり、上記の疑わしい状態のために長時間ウェイクアップされないためです。
このチェックを単純に削除すると、より自然で効率的になります。次に、printfsは可能な限り迅速にバッファをいっぱいにし、その後、バッファが空になる速度で続行します、私が観察しているバースト処理ではありません。
それは私の環境ではうまく機能しますが、確かに私は何かを見逃しているか誤解しています。現在の実装には理由があるはずです。その状態を取り除くと副作用はありますか?
副次的な質問として:この動作を調整するための構成オプションはありますか? printfが常にすぐに戻り、バッファがいっぱいになった場合に出力を破棄するようにするには?
これは効率の尺度です。 CPUはシリアルポートよりもはるかに高速に実行されるため、カーネルがバッファに少しのスペースがあるたびにユーザースペースプロセスを実行させると、データの1バイトごとにユーザースペースに移動して戻ることになります。これは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を使用している場合は、とにかく一般的に当てはまります。