SQPOLL bei io_uring: weniger Latenz, mehr CPU

SQPOLL ist bei io_uring der Modus, in dem ein dedizierter Kernel-Thread namens io_uring-sq die Submit-Queue fortlaufend abfragt, statt auf Interrupts zu warten. Das spart Syscalls und senkt die Latenz, kostet dafür aber dauerhaft CPU. Genauso beschreibt es der Post von gg582 vom 19. September 2026 auf oborona.zip, laut Quelle mit 53 Zugriffen.

Ich hab beim Lesen erstmal gelacht, weil die Überschrift der Quelle SQPOLL mit einer unsicheren Freundin vergleicht, und dann gemerkt, dass die Metapher präziser ist als gedacht. Der Autor spöttelt über den Namen io_uring, erklärt trotzdem jede Queue auf dem Weg und postet das Ganze um 01:51 Uhr, bei Kernel-Themen keine ungewöhnliche Uhrzeit.

Wie läuft io_uring im Normalmodus?

Im Standardmodus arbeitet io_uring interruptgesteuert: Die App legt Arbeitspakete (SQE) in die Submit-Queue (SQ), der Kernel wartet, bis eine SSD per Hardware-Interrupt meldet, dass die Daten fertig sind, und gibt Ergebnisse über die Completion-Queue (CQ) zurück. Jede dieser Abfragen läuft über den Syscall io_uring_enter(), wie die Quelle beschreibt. Nicht kostenlos, aber laut derselben Quelle sparsamer als Dauernachfragen.

Vorher legt io_uring_setup() die Ringe in User- und Kernel-Space an. Fertige Jobs gehen dann an den Hardware-Controller oder an io_wqe, einen Arbeitsthread im Kernel, während die App schon die nächsten in die Queue legt. Klingt ordentlich, bis man realisiert, dass „die werden dann abgearbeitet“ immer noch über io_uring_enter() geht, einen Syscall, der bei hoher Last aufsummiert wird. Die Quelle warnt davor, dass die Annahme, moderne Systeme seien zu schnell für spürbare Wartezeiten, bei Frameworks riskant ist, weil der Overhead nicht klein ist.

Warum vergleicht die Quelle SQPOLL mit einer unsicheren Freundin?

Mit dem Flag IORING_SETUP_SQPOLL erzeugt io_uring_setup() einen Kernel-Thread namens io_uring-sq, der sich ausschließlich auf diesen einen Ring konzentriert und permanent schaut, ob neue SQEs eingereicht wurden. Über IORING_SETUP_SQ_AFF lässt sich der Thread zusätzlich an einen festen Core pinnen. Der Unterschied zum Normalmodus: Statt angerufen zu werden, steht SQPOLL selbst ununterbrochen an der Tür.

Der eigentliche Haken ist dieses ständige Nachschauen. Die Quelle sagt offen, dass zwischen CPU-Verbrauch und Performance-Orientierung in der Praxis weiter überlegt werden will. Ein Thread, der dauerhaft auf einem Core läuft, ist kein Schalter, den man versehentlich anlässt. Umgekehrt spart SQPOLL bei hoher I/O-Last reale Syscall-Runden. Dass dafür keine Messwerte herkommen, ist der größte Schwachpunkt der Meldung: kein Prozentwert, keine Kurve, kein Workload.

Meine Interpretation: Die Freundin-Metapher trifft, weil SQPOLL die Wartezeit vom App auf einen Kernel-Thread verlagert, der für jede Idle-Sekunde bezahlt wird, während der Normalmodus erst anruft, wenn die Hardware fertig ist. Ob sich das rechnet, entscheidet der konkrete Workload, und für solche Entscheidungen fehlen dem Post echte Messungen. Wird der io_uring-sq-Thread in euren Setups je einen ganzen Core für sich beanspruchen, oder schaltet ihr SQPOLL nur für die kritischen Pfade an?

Schreibe einen Kommentar