- Linux gerçek zamanlı önalma desteği, yaklaşık 20 yıldır mainline’a girmeyi bekleyen bir çalışma ve Thomas Gleixner, 2023 Linux Plumbers Conference’ta son büyük engelin
printk()olduğunu söyledi - Hedef, en yüksek öncelikli sürecin öngörülebilir derecede kısa gecikmeyle çalışmasını sağlamak; bunun için çekirdeğin birçok temel bölümü uzun süre boyunca yeniden yazıldı
printk(), herhangi bir bağlamda çağrılabildiği için basit bir günlük çıktısından çok daha zorlu ve mevcut eşzamanlı çıktı yapısı gerçek zamanlı gecikme hedefleriyle çakışıyor- 2018’den bu yana yaklaşık 300 yama upstream’e girdi ya da linux-next’te bekliyor; geriye kalan işler acil mesaj handover’ı ve konsol sürücüsü güvenliğinin ele alınması
printk()düzenlemesi biter ve kalan gerçek zamanlı kod linux-next’te hazır olursa, aynı merge window içinde birleştirme de mümkün olabilir; ancak Gleixner artık tamamlanma zamanı için tahminde bulunmayacağını söylüyor
Yaklaşık 20 yıldır süren gerçek zamanlı önalma çalışması
- Linux gerçek zamanlı desteği LWN’de ilk kez 2004’te gündeme geldi ve uzun süre “biraz daha kaldı” gibi göründü
- LWN, 2009’da da the realtime preemption endgame başlığını kullanmıştı, ancak 2023 Linux Plumbers Conference’ta Gleixner artık gerçekten sona yaklaşıldığını düşündüğünü söyledi
- Gleixner’ın şahsen baktığında bu neredeyse 25 yıllık bir çalışma
- 1999’da Linux gerçek zamanlı destek çalışmasına başladı
- Projenin kendisi de neredeyse 20 yıldır sürüyor
- Çalışma bittiğinde “a big party” olacağını söyledi, ancak son büyük engel olarak
printk()duruyor
Gerçek zamanlı önalmanın azaltmaya çalıştığı gecikme
- Gerçek zamanlı önalmanın amacı, en yüksek öncelikli sürecin her zaman en düşük ve öngörülebilir gecikmeyle çalışabilmesini sağlamak
- Bunun için çekirdek mümkün olduğunca çok durumda önalınabilir olmalı ve istisnalar dar, net tanımlı bir kapsamla sınırlanmalı
- Temel çalışma biçimi uzun zaman önce oturdu, ancak ayrıntı sorunlarını çözmek uzun sürdü
- Bu süreçte çekirdeğin birçok temel bölümü yeniden yazıldı ve bunun faydaları gerçek zamanlı kullanım senaryolarının ötesine geçerek çekirdeğin geneline yayıldı
printk() neden son engel
- Çekirdek kodunun konsola ve günlüklere mesaj göndermesi gerektiğinde
printk()ya da onun üzerine kurulu işlevler çağrılıyor - Basit bir çıktı gibi görünse de
printk()neredeyse her bağlamda çalışmak zorunda- non-maskable interrupt işleyicisinde de çağrılabilir
- başka bir
printk()çağrısının içinden yeniden çağrılabilir - Sistem çökmesi durumunda çıktı bilgisi önemli olabileceği için çağrı bağlamını kısıtlamak zordur
- Bu gereksinimler yüzünden
printk()içinde eşzamanlılık, kilitleme ve sürücü işleme sorunları karmaşık biçimde iç içe geçmiş durumda - Çekirdekteki mevcut
printk()tamamen eşzamanlı bir yapı- Çağrı, mesaj yapılandırılmış tüm hedeflere gönderilene kadar dönmüyor
- Gleixner bu yapıyı “stupid” diye nitelendiriyor
- Özellikle önyükleme sırasında çıktının çoğu basit bir gürültü olsa bile, hepsi gönderilene kadar bekleniyor
- Bu bekleme süresi, gerçek zamanlı çalışmanın azaltmak istediği gecikmeyle doğrudan çatışıyor
- Gerçek zamanlı geliştiriciler uzun zamandır
printk()çıktısını ayrı bir iş parçacığına taşıyarak asenkron hale getiriyordu, ancak bu kod temel bir çözümden çok çeşitli hack’lere yakındı
2018’den bu yana printk() yeniden işleniyor
printk()sorunu 2018’den itibaren ciddi biçimde ele alındı ve yaklaşık 300 yama upstream’e girdi ya da linux-next’te bekliyor- Şu anda işi bitirmek için son 3 yama seti üzerinde çalışılıyor
- En zorlu ayrıntılı görevlerden biri handover mekanizması
- Çekirdeğin çökme gibi acil mesajlar yazması gerektiğinde, düşük öncelikli mesajları yazmakta olan konsolun denetimini devralması gerekebilir
- Bunu her bağlamda güvenli şekilde yapmak kolay değil
- Bir başka görev de belirli bağlamlarda güvenle kullanılamayan konsol sürücülerini işaretlemek
- Örneğin non-maskable interrupt sırasında mesaj yazdırmak gerekirken video modu ayarı gerekiyorsa bu çalışamaz
- Gleixner, son 1 yıl içinde temel kavramsal bir değişiklik olmadığını söyledi
- Çekirdekte düzeltilmesi gereken 76 konsol sürücüsü var
- handover kodu, tüm sürücüleri bir kerede düzeltmek yerine sürücülerin tek tek güncellenebilmesine olanak verecek şekilde değiştirildi
- Son dönemdeki ek
printk()tartışmaları şu yazıda yer alıyor
Asenkron çıktı ve mainline’a birleştirme koşulları
- Masami Hiramatsu, hangi çekirdek mesajlarının eşzamanlı yazdırılması gerektiğini sorunca, Gleixner neredeyse her şeyin asenkron hale getirilmesi gerektiğini söyledi
- Asenkron çıktı,
printk()çağrılarının doğurduğu gecikmeyi azaltıyor ve her konsol için ayrı bir çekirdek iş parçacığına izin veriyor- Böylece hızlı konsollar, en yavaş konsolu beklemeden kendi hızlarında çalışabiliyor
- Önemli mesajlarda kod, ilk satır yazdırılmadan önce mesajın mesaj tamponuna tamamen kopyalanmasını sağlayacak şekilde değiştirildi
- Bu, hatalı bir konsol sürücüsünün tüm sistemi bozması ihtimaline karşı alınmış bir önlem
- Daha güvenli bir çıktı sırası için önce güvenli olduğu bilinen konsollara yazılıyor
- Örneğin persistent-memory store varsa, fiziksel cihaza gönderilmeden önce mesaj önce oraya kaydediliyor
- Bu yöntem, hatalı bir sürücü sistemi çökertse bile çıktı içeriğini korumayı amaçlıyor
- Gleixner, işin yaklaştığını ancak
printk()’ın öngörülmesi zor olduğunu, bu yüzden tamamlanma zamanı hakkında artık konuşmayacağını söyledi - Yine de kalan gerçek zamanlı önalma kodunun 2024 sonundaki 20. yıl dönümünden önce mainline’a girmesini umduğunu belirtti
- Clark Williams,
printk()yamaları upstream olduktan sonra kalan gerçek zamanlı kodun aynı merge window içinde girip girmeyeceğini sorunca, Gleixner koşullu bir “yes” yanıtı verdi- Tüm kod linux-next’te staged durumdaysa ve hazır görünüyorsa bunun denenebileceğini söyledi
1 yorum
Hacker News yorumları
QNX onlarca yıl önce bu kısmı doğru yapmıştı. Mikrokernelin yaptığı her işin bir üst sınırı var ve kodu da yalnızca on binlerce satırdan ibaret.
Mikrokernel yalnızca bellek ayırma, CPU dispatch ve süreçler arası mesaj iletimi yapar. Sürücüler ve logger dahil geri kalan her şey kullanıcı alanındadır ve daha yüksek öncelikli thread’ler tarafından preempt edilebilir.
QNX kernel’i string’lerle uğraşmaz. Parsing yok, formatting yok, mesaj yok. Linux gerçek zamanlı kullanım için fazla şişkin hale geldi; milyonlarca satırlık kernel kodunun tamamını preempt edilebilir yapmak gerektiğinden, mimarisi zaten gerçek zamana uygun değil. Bu yüzden düzeltmek 20 yıl sürdü.
Kernel tasarımına en büyük katkısı muhtemelen capability’leri genel olarak kullanarak kontrolü güvenli ama esnek biçimde kullanıcı alanına aktarması.
Kernel’in şişmesi tek başına beni çok kaygılandırmıyor. Linux’a çok fazla geliştirme zamanı yatırılıyor; masaüstü sunucular kadar yüksek öncelikli olmasa bile, taşınabilir cihazlar gibi alanlarda yüksek performanslı bir kernel yapmak için yapılan çalışmalar masaüstü kullanıcılarına da yarar sağlayacaktır.
mainfonksiyonuna benziyor.mainyalnızca diğer fonksiyon çağrılarını koordine eder; burada QNX kernel’inin daha az başlatma yapması gibi bir fark olsa da büyük kavram benzer.Kernel geliştiricisi değilim ama bunu bu kadar basit tutma yaklaşımı iyi görünüyor.
Ölmekte olan bir sistemde bile kernel’in log mesajlarını bir şekilde dışarı çıkarmaya çalıştığını ve bunun gerçek dağıtım ortamlarında nasıl kullanıldığını gösteren bir örnek var.
https://netflixtechblog.com/kubernetes-and-kernel-panics-ed6...
Bu sorun düzeltilirse, gerçek zamanlı kullanım için yapılmış bazı donanım/yazılım kombinasyonlarının oldukça yerini alıp alamayacağını merak ediyorum. Artık ucuz, düşük güç tüketimli ve yüksek saat hızlı çok sayıda ARM ve x86 çip seçeneği var.
Saat hızları çok yüksek olduğundan, bazı kaçırmalar olsa bile bolca boş çevrim bulunduğu için kusursuz gerçek zamanlılık çoğu zaman daha az önemli hale gelebilir. Bunun zarif ya da verimli olmadığını biliyorum ama bazen ticari kullanıma hazır genel ürünler doğruluğu yenebiliyor.
Kötü yazılmış tek bir iş kernel’i meşgul edip yararlı iş yapmasını engelleyebilir. Hard real-time’ın özü, “bu önemli işin çalışmasını hiçbir şey engelleyemez” ilkesidir. Otomotiv veya havacılık-uzay alanlarında kontrol sistemleri her koşulda çalışmak zorundadır.
Gerçekten gerçek zamana ihtiyaç varsa gerçekten ihtiyaç vardır; “yeterince yakın” diye bir şey yoktur. Yine de bu, dışarıdan biri olarak izlenimim.
İşletim sistemi, RTOS olsa bile, fazlasıyla araya girer. Bu değişikliğin neyi değiştireceğini bilmiyorum. Yine de uygulamaya göre değişir; “neredeyse gerçek zamanlı” düzeyinde gereksinim duyan çok durum var, bu kullanım için faydalı olabilir.
Buradaki tartışma “hard” gerçek zamanlı uygulamalar ile “soft” gerçek zamanlı uygulamalar arasındaki ayrıma odaklanıyor. Hard real-time’da Linux gibi genel amaçlı bir işletim sistemini zaten kullanmak istememe olasılığınız yüksek; görüntülü konferans veya ses çalma gibi soft real-time’da ise ara sıra takılma ya da birkaç frame düşmesi büyük felaket değildir.
Mantık şu: RT Linux bu tür soft real-time kullanım alanları için güçlü bir çözüm olacak. Ancak önerilen soft kullanım alanları bugün de gömülü Linux ile mümkün. Düşük gecikmeli yazılımsal video ya da ses oynatma imkânsız değildi; 20 yıl önce de mümkündü.
Sorun, yoğun bir sistemde preempt edilemeyen I/O’nun sık sık araya girmesiyle ortaya çıkar; gömülü ortamlarda ise bu nadirdir. Kernel’i tamamen preempt edilebilir hale getirmek ve zamanlama üzerinde daha fazla kontrol vermek için ikna edici nedenler var, ancak bunun Linux’un minimal gerçek zamanlı işletim sistemlerinin veya bare-metal kodun yerini alması gerektiğiyle pek ilgisi yok.
Bu daha çok iyi bir hijyen uygulamasına benziyor ve gerçek zamanlı olmayan uygulamalarda da yük altındayken daha iyi çalışan bir işletim sistemi ortaya çıkarıyor.
İyi haber, ancak Linux çekirdeği gerçek zamanlı hale gelse bile donanımın, önbellek ve CPU içindeki karmaşık sihir yüzünden gerçek zamanlı olmama ihtimali yüksek
Büyük ve karmaşık donanımlar gerçek anlamda gerçek zamanlılığa uygun değil. Bu yüzden AbsInt ve en kötü durum çalışma süresi (WCET) araçları çoğunlukla basit CPU mimarileriyle ilgilenir. 8051 gerçekten sonsuza kadar yaşayacak. Bu arada Zephyr RTOS da var
Hiç önbellek isabeti olmadığı ve maksimum yük altında olunduğu gibi durumları varsaymak yeterli. Geçen süreye bir üst sınır koyabiliyorsanız sorun yok
Zamanlayıcılar kuadratur enkoder girişini alıp taşma olduğunda yalnızca kesme gönderebilir ya da GPIO sistemi DMA’ya bağlanarak CPU müdahalesi olmadan belleği çıkış pinlerine akıtabilir. DAC’ye akış yapmak veya ADC’den belleğe DMA aktarımı yapmak da mümkün. Bunlar öngörülebilir gecikme için çoğu zaman önbelleği bypass eder
Gerçekte pek çok gerçek zamanlı sistem, sürekli artan sensör verilerini işlemek ve toplamak zorunda olduğu için giderek daha güçlü hale geliyor
Kariyerimin başlarında, görüşmecilerin gerçek zamanlının gerçekte ne olduğunu bilmediği sinir bozucu derecede çok mülakat yaşadım. Yazıda geçen “ve öngörülebilir gecikme” kavramını kaçıran çok kişi vardı; gerçek zamanlıyı sadece “hızlı” anlamına geliyor sanıyor gibiydiler
Bir otomobil fren sistemini kontrol ediyorsanız “ortalama gecikme 50 ms ama maksimum 80 ms” kabul edilebilir olabilir; ancak “ortalama gecikme 1 ms ama keyfi biçimde uzayabilir ve birkaç saniye sürebilir” kabul edilemez
Senkron logging yine sorun çıkarmış. Şirkette GLOG (Google logging kütüphanesi) yüzünden benzer bir şey yaşadık; örneğin stdout bir dosyaysa disk I/O’da bloklanabilir
Servisimiz 100 ms’den uzun süre durduğunda nedenin %90–99’u GLOG’du
“Mutlaka loglamanız gerekiyor ama loglayamıyorsanız ne yapacaksınız?” Son zamanlarda sadece CAP teoremini işaret edip logging’in de diğer dağıtık sistemlerle aynı olduğunu söylüyorum. Üçgen çizimi ve “teorem” kelimesi geçen bir Vikipedi sayfası olduğundan olsa gerek, insanlar bunu kabul etme eğiliminde
Sonrasında UDP aktarımına geçtik. Çünkü üretimin tamamını kaybetmektense logların bir kısmını kaybetmek daha iyiydi
$MSFTlogging kütüphanesinde de “logging kütüphanesi her şeyi bozuyor” türünden bir sorun vardı. Her biri 300 MB’lık logging buffer’ına sahip 100 thread hayal edinDoğal olarak belleği mahvetti ve Azure App Service’in en pahalı SKU’sunda bile sunucu çöktü
Eski günler birden aklıma geldi. 17–18 yıl kadar önce, daha sıkı zamanlama gerektiren bilimsel bir cihazda kullanmak için Debian çekirdeğini RT_PREEMPT ile derlemiştim
Gecikme ve jitter çok etkileyiciydi. O zamandan beri pek düşünmedim ama Raspberry Pi ile gömülü uygulama geliştirirken RTOS kullanan mikrodenetleyicilere geçmek istemediğiniz durumlarda kullanılabileceği çok yer var gibi geliyor
Daha önce de Linux’un bir RTOS görevi olarak çalıştırılabileceğine dair bir öneri görmüştüm; bu yüzden özellikle ilgimi çekti. Hard real-time deadline gerektiren şeyler RTOS üzerinde çalışır ve sanal bellek sisteminin yol açabileceği gecikmelerden etkilenmez. Bunun sadece bir fikir mi olduğunu yoksa gerçekten uygulanıp uygulanmadığını hatırlamıyorum; RpiOS’un RTOS üzerinde olduğuna dair ifadeyi de yalnızca bir kez gördüğüm için merak ediyorum
Bunun sıradan kullanıcılar için ne anlama geldiğini merak ediyorum. Yalnızca çok belirli durumlarda açılan bir özellik mi, yoksa genel kitleye de daha tepkisel bir sistem sağlayabilir mi?
Her görev X adlı bir bütçe alır ve bunun dışına çıkmamalıdır. En iyi durumda hızlı ama en kötü durumda yavaşsa, sistemin her zaman en kötü durumu varsayması gerektiği anlamına gelir.
Senkron
printk()çağrılarından kaçınma örneği tam da buna iyi bir örnek; RT açılmasa bile yük altındayken gecikmeyi iyileştirmesi gerekir. Tamamen upstream’e alınmış bir RT çekirdeğinin, gerçekten RT süreçleri çalıştırılmadığı sürece normal çekirdekten farklı davranmayacağını düşünüyorum. Upstream’e alınmasının uzun sürmesinin nedeni, RT’yi mümkün kılmak için bazı ödünler gerekmesiydi; yazıya göre artık bu ödünlerden pek fazla kalmamış.Çünkü gerçek zamanlı zamanlama gerektiğinde bile en güncel mainline çekirdeği kullanabilecekler.
Xenomai[1] hakkında ne düşündüğünüzü merak ediyorum. Yıllardır sorunsuz kullanıyorum.
BeagleBone Black’te genellikle birkaç yüz nanosaniye düzeyinde jitter elde ediliyor ve bunu “hard” gerçek zamanlı sayıyorum. Onlarca mikrosaniye ölçeğinde periyodik işleri zamanlayabiliyor ve bir kez bile kaçırmıyor.
Real-Time Linux’un Linux’un kendisini preemptible hale getirmeye çalışmasının aksine, Xenomai özünde kendi çekirdeği olan ve Linux’u bunun üzerinde bir görev olarak çalıştıran bir yapı. Kullanıcının yazdığı görevleri Linux ile yan yana ya da daha yüksek öncelikle çalıştırmak için bir ABI sağlıyor. Örneğin
printk()sorununu aşabiliyor; Xenomai bunu umursamaz ve kullanıcının görevini çalıştırmak içinprintkiçinden memnuniyetle context switch yapar.Dezavantajı, Xenomai bağlamında normal sistem çağrılarını yapamamanız. Yapabilirsiniz, ama elbette gerçek zamanlı modeli bozarsınız. Örneğin bir Xenomai görevi içinde
printf()veyamalloc()çağırırsanız preemptible olmaz. Xenomai ABI, sistem çağrıları tarafında ihtiyaç duyabileceğiniz şeyleri mümkün olduğunca kopyalar; heap tahsisini doğrudan yönetmekten memnunsanız çok iyi çalışır.[1]: https://xenomai.org/