Pourquoi le pilote 8250 UART ne réveille-t-il pas le TTY si plus de 256 caractères sont en attente?

8

Quelle est la motivation de cette condition si void serial8250_tx_chars(struct uart_8250_port *up)?

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

Il existe depuis Linux 1.1.13 (mai 1994) et se répète dans la plupart des pilotes UART.

Contexte: Linux 3.4.91 personnalisé, système embarqué sur ARMv7, le port UART 0 est configuré pour 38400 bauds, FIFO 16 octets pour les E / S. Rien de tout cela ne peut être modifié dans notre configuration.

Lorsque vous imprimez très lourdement sur la console via UART, le tampon interne de 4 Ko ( UART_XMIT_SIZE) se remplit puis bloque le processus de l'espace utilisateur jusqu'à ce que le tampon soit vidé (ce qui prend une seconde à 38 400 bauds!). Ensuite, ce comportement se répète. En effet, la fonction se n_tty_write()met en veille lorsque le tampon est plein et n'est pas réveillée pendant une longue période en raison de la condition discutable ci-dessus.

Je trouverais cela plus naturel et efficace si ce chèque était simplement supprimé. Ensuite, les printfs rempliraient le tampon le plus rapidement possible, puis continueraient à la vitesse à laquelle le tampon est vidé , plutôt que le traitement par rafale que j'observe.

Cela fonctionne bien dans mon environnement, mais je manque sûrement quelque chose ou je me méprends. Il doit y avoir une raison à la mise en œuvre actuelle. Y a-t-il des effets secondaires si je supprime cette condition?

Comme question secondaire: existe-t-il des options de configuration pour régler ce comportement, par exemple pour que printf revienne toujours immédiatement et rejette la sortie si le tampon est plein?

Hans W. Heckel
la source
Sans en savoir trop à ce sujet, mon intuition est la suivante: il s'agit d'une configuration de console série Linux ordinaire. J'ai travaillé avec ceux sur le matériel x86 standard. Pour les connexions série directes, j'ai toujours dû utiliser le contrôle de flux matériel. Ça pourrait être une idée.
vasquez
1
Il y a probablement une différence d'efficacité. Pourquoi ne pas simplement définir WAKEUP_CHARS sur quelque chose comme UART_XMIT_SIZE - 128?
James Youngman
@JamesYoungman En fait, c'est ce que j'ai fini par faire aussi. À votre santé!
Hans W.Heckel

Réponses:

2

C'est une mesure d'efficacité. Le processeur s'exécute tellement plus rapidement que le port série que si le noyau laissait le processus de l'espace utilisateur s'exécuter à chaque fois qu'il y avait un peu de place dans le tampon, il finirait par faire un voyage dans l'espace utilisateur et revenir pour chaque octet de données. C'est très gaspillant du temps 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

Le test ci-dessus n'est même pas en train de lire et d'écrire un véritable appareil: la différence de temps totale est la fréquence à laquelle le système rebondit entre l'espace utilisateur et l'espace noyau.

Si l'espace utilisateur ne veut pas être bloqué, il peut utiliser des E / S non bloquantes, ou il peut vérifier utiliser un select()appel pour voir s'il y a de la place pour écrire sur le périphérique ... et s'il n'y en a pas, il peut vider le reste dans une mémoire tampon et continuer le traitement. Certes, cela complique les choses, puisque maintenant vous avez un tampon que vous devez vider ... mais si vous utilisez stdio, c'est généralement vrai de toute façon.

Jander
la source
Cela prend en charge le commentaire de @James sur l'efficacité ci-dessus. Maintenant, cela a beaucoup plus de sens pour moi. Merci aussi pour les chiffres!
Hans W. Heckel
Il convient de noter que depuis le noyau 2.6, cette question fait référence au code qui apparaît souvent dans les pilotes de couche inférieure (par exemple un pilote UART). Ces pilotes fournissent à la couche supérieure, serial_core, les moyens d'interagir avec le matériel. C'est le noyau série qui interagit réellement avec l'espace utilisateur (sauf si le pilote matériel implémente ses propres ioctls ou quelque chose de similaire). Je crois que la réponse des répondants est toujours valable.
Andrew Falanga