- Linux में रीयल-टाइम preemption सपोर्ट लगभग 20 साल से mainline में शामिल होने का इंतज़ार कर रहा है, और Thomas Gleixner ने 2023 Linux Plumbers Conference में बताया कि आखिरी बड़ी बाधा
printk()है - लक्ष्य यह है कि सबसे उच्च-प्राथमिकता वाला process पूर्वानुमेय कम latency के साथ चल सके, और इसके लिए kernel के कई core हिस्सों को लंबे समय में फिर से लिखा गया है
printk()किसी भी context में कॉल किया जा सकता है, इसलिए यह साधारण log output से कहीं अधिक जटिल है, और मौजूदा synchronous output रीयल-टाइम latency के लक्ष्य से टकराता है- 2018 के बाद से लगभग 300 patches upstream में जा चुके हैं या linux-next में लंबित हैं, और बचे हुए काम में emergency message handover और console driver safety शामिल हैं
printk()की सफाई पूरी होने और बाकी रीयल-टाइम code के linux-next में तैयार हो जाने पर, उसी merge window में merge भी संभव है, लेकिन Gleixner ने कहा कि वह अब पूरा होने के समय का अनुमान नहीं लगाएंगे
लगभग 20 साल से जारी रीयल-टाइम preemption का काम
- Linux रीयल-टाइम सपोर्ट पहली बार LWN में 2004 में सामने आया, और लंबे समय तक ऐसा लगता रहा कि बस “थोड़ा सा और” बाकी है
- LWN ने 2009 में भी the realtime preemption endgame शीर्षक इस्तेमाल किया था, लेकिन 2023 Linux Plumbers Conference में Gleixner का मानना था कि अब सचमुच अंत करीब है
- Gleixner के लिए व्यक्तिगत रूप से यह लगभग 25 साल लंबा काम है
- उन्होंने 1999 में Linux रीयल-टाइम सपोर्ट पर काम शुरू किया था
- प्रोजेक्ट खुद भी लगभग 20 साल से चल रहा है
- उनका कहना था कि काम पूरा होने पर “a big party” होगी, लेकिन आखिरी बड़ी बाधा के रूप में
printk()अब भी बचा है
रीयल-टाइम preemption किस latency को कम करना चाहता है
- रीयल-टाइम preemption का उद्देश्य यह है कि सबसे उच्च-प्राथमिकता वाला process हमेशा न्यूनतम और पूर्वानुमेय latency के साथ चल सके
- इसके लिए kernel को जितनी अधिक परिस्थितियों में संभव हो preemptible होना चाहिए, और exceptions को सीमित व स्पष्ट दायरे में रखा जाना चाहिए
- मूल काम करने का तरीका बहुत पहले स्थापित हो गया था, लेकिन बारीक समस्याओं को सुलझाने में लंबा समय लगा
- इस प्रक्रिया में core kernel के कई हिस्से दोबारा लिखे गए, और इसका लाभ रीयल-टाइम use cases से आगे बढ़कर पूरे kernel तक पहुँचा
printk() आखिरी बाधा क्यों है
- जब kernel code को console और log में message भेजने होते हैं, तो वह
printk()या उसके ऊपर बनी functions को कॉल करता है - यह साधारण output जैसा दिखता है, लेकिन
printk()को लगभग हर context में काम करना पड़ता है- इसे non-maskable interrupt handler के भीतर भी कॉल किया जा सकता है
- यह दूसरे
printk()call के भीतर फिर से कॉल हो सकता है - system crash की स्थिति में output की जानकारी महत्वपूर्ण हो सकती है, इसलिए call context को सीमित करना मुश्किल है
- इन आवश्यकताओं के कारण
printk()में concurrency, locking और driver handling की समस्याएँ जटिल रूप से जुड़ी हुई हैं - मौजूदा kernel का
printk()पूरी तरह synchronous संरचना पर आधारित है- call तब तक return नहीं करता जब तक message सभी configured destinations तक भेज न दिया जाए
- Gleixner ने इस संरचना को “stupid” कहा
- खासकर boot के दौरान, जब बहुत सा output सिर्फ शोर हो सकता है, तब भी सब कुछ भेजे जाने तक इंतज़ार करना पड़ता है
- यह इंतज़ार समय सीधे उस latency से टकराता है जिसे रीयल-टाइम काम कम करना चाहता है
- रीयल-टाइम developers लंबे समय से
printk()output को अलग thread में ले जाकर asynchronous बनाने की कोशिश करते रहे हैं, लेकिन वह code मूल समाधान की बजाय कई hacks के ज्यादा करीब था
2018 के बाद से printk() का पुनर्गठन
printk()की समस्या पर 2018 से गंभीरता से काम शुरू हुआ, और लगभग 300 patches upstream में जा चुके हैं या linux-next में प्रतीक्षा कर रहे हैं- काम पूरा करने के लिए अब आखिरी 3 patch sets पर काम चल रहा है
- सबसे कठिन बारीक कामों में से एक handover mechanism है
- जब kernel को crash जैसी emergency message print करनी होती है, तो उसे low-priority message print कर रहे console से control लेना पड़ सकता है
- इसे हर context में सुरक्षित रूप से करना आसान नहीं है
- दूसरा काम उन console drivers को चिह्नित करना है जिन्हें कुछ contexts में सुरक्षित रूप से इस्तेमाल नहीं किया जा सकता
- उदाहरण के लिए, अगर non-maskable interrupt के दौरान message print करना हो लेकिन उसके लिए video mode setting चाहिए, तो वह काम नहीं कर सकता
- Gleixner ने कहा कि पिछले एक साल में मूल अवधारणा में कोई बुनियादी बदलाव नहीं आया है
- kernel में ऐसे 76 console drivers हैं जिन्हें ठीक करने की जरूरत है
- handover code को इस तरह बदला गया है कि सभी drivers को एक साथ ठीक करने के बजाय एक-एक करके update किया जा सके
- हाल की अतिरिक्त चर्चा
printk()के काम पर इस लेख में है
asynchronous output और mainline merge की शर्तें
- जब Masami Hiramatsu ने पूछा कि किन kernel messages को synchronous रूप से print करना चाहिए, तो Gleixner ने जवाब दिया कि लगभग हर चीज़ को asynchronous बना देना चाहिए
- asynchronous output
printk()calls से पैदा होने वाली latency को कम करता है और हर console के लिए अलग kernel thread रखने की सुविधा देता है- इससे तेज console सबसे धीमे console का इंतज़ार किए बिना अपनी गति से काम कर सकता है
- महत्वपूर्ण messages के लिए code इस तरह बदला गया है कि पहली line print होने से पहले message पूरी तरह message buffer में copy हो जाए
- यह इस संभावना से बचाव के लिए है कि कोई दोषपूर्ण console driver पूरे system को खराब कर दे
- ज्यादा सुरक्षित output order के लिए पहले उन consoles पर लिखा जाता है जिन्हें सुरक्षित माना जाता है
- उदाहरण के लिए, अगर persistent-memory store मौजूद हो, तो physical device पर भेजने से पहले message को पहले store किया जाता है
- इसका उद्देश्य यह है कि किसी खराब driver के system गिरा देने पर भी output बचा रहे
- Gleixner ने कहा कि काम मंजिल के करीब है, लेकिन
printk()का अनुमान लगाना कठिन है, इसलिए वह अब completion date नहीं बताएंगे - फिर भी उन्होंने उम्मीद जताई कि बाकी रीयल-टाइम preemption code 2024 के अंत में 20वीं वर्षगांठ से पहले mainline में पहुँच जाए
- जब Clark Williams ने पूछा कि
printk()patches के upstream होने के बाद बाकी रीयल-टाइम code को उसी merge window में डाला जाएगा या नहीं, तो Gleixner ने शर्तों के साथ “yes” कहा- अगर सारा code linux-next में staged हो और तैयार दिखे, तो यह कोशिश की जा सकती है
1 टिप्पणियां
Hacker News की रायें
QNX ने यह काम दशकों पहले से सही तरीके से किया हुआ है। microkernel जो भी काम करता है, उनमें हर चीज़ की ऊपरी सीमा तय है, और code भी सिर्फ़ कुछ दसियों हज़ार lines का है
microkernel सिर्फ़ memory allocation, CPU dispatch, और processes के बीच message passing करता है। drivers और loggers समेत बाकी सब user space में है, और higher-priority threads द्वारा preempt किया जा सकता है
QNX kernel strings से निपटता ही नहीं। न parsing, न formatting, न messages। Linux real-time के लिए बहुत फूला हुआ हो गया है, और उसे kernel code की लाखों lines को preemptible बनाना पड़ता है, इसलिए उसकी architecture ही real-time के मुताबिक नहीं है। इसी वजह से इसे ठीक करने में 20 साल लगे
kernel design में इसका सबसे बड़ा योगदान शायद capabilities का व्यापक उपयोग है, जिससे control को safe और flexible तरीके से user space में बाहर दिया जाता है
kernel bloat अपने-आप में मुझे बहुत चिंता की बात नहीं लगती। Linux पर बहुत development time लगाया जा रहा है, और desktop भले ही servers जितना high priority न हो, लेकिन portable devices जैसी जगहों के लिए high-performance kernel बनाने का काम desktop users को भी फायदा देगा
mainfunction जैसा दिखता है।mainसिर्फ़ दूसरे function calls को coordinate करता है, और यहाँ QNX kernel initialization कम करता है—यह अंतर है—फिर भी बड़ा concept काफ़ी मिलता-जुलता हैमैं kernel developer नहीं हूँ, लेकिन इसे इतना simple बनाए रखने का तरीका अच्छा लगता है
मरते हुए system में भी kernel किसी तरह log message बाहर निकालने की कोशिश करता है, और real deployment environment में उसका इस्तेमाल कैसे होता है—इसका एक उदाहरण है
https://netflixtechblog.com/kubernetes-and-kernel-panics-ed6...
सोच रहा हूँ कि अगर यह समस्या ठीक हो जाए, तो क्या real-time के लिए बनाए गए hardware/software combinations के कुछ हिस्सों को काफी हद तक replace किया जा सकेगा। अब सस्ते, कम power वाले और high-clock ARM तथा x86 chips के बहुत विकल्प हैं
clock इतना high है कि कुछ misses हों भी तो अक्सर spare cycles इतने होते हैं कि perfect real-timeness कम महत्वपूर्ण हो सकती है। मुझे पता है यह elegant या efficient नहीं है, लेकिन कभी-कभी commodity चीज़ें correctness को मात दे देती हैं
खराब तरीके से बना एक task kernel को पकड़े रख सकता है और उसे useful काम करने से रोक सकता है। hard real-time का मूल यह है कि “इस critical task को चलने से कोई चीज़ रोक नहीं सकती।” automotive या aerospace क्षेत्रों में control systems को हर परिस्थिति में चलते रहना होता है
अगर सच में real-time चाहिए, तो सच में चाहिए; “काफ़ी करीब” जैसी कोई चीज़ नहीं होती। हालांकि यह एक outsider के तौर पर मेरा impression है
operating system, RTOS भी हो, तो बहुत ज़्यादा interfere करता है। यह बदलाव क्या बदलेगा, मुझे नहीं पता। हालांकि यह application पर निर्भर करता है, और “लगभग real-time” जैसी ज़रूरतें बहुत होती हैं, इसलिए ऐसे use cases के लिए यह उपयोगी हो सकता है
यहाँ चर्चा “hard” real-time applications और “soft” real-time applications के फर्क पर केंद्रित है। hard real-time में Linux जैसे general-purpose operating system का इस्तेमाल करना शुरू से ही शायद नहीं चाहेंगे, और video conferencing या audio playback जैसे soft real-time में कभी-कभार glitch आ जाए या कुछ frames drop हो जाएँ तो कोई बड़ी आफ़त नहीं होती
तर्क यह है कि RT Linux ऐसे soft real-time use cases के लिए एक powerful solution होगा। लेकिन प्रस्तावित soft use cases अभी भी embedded Linux से संभव हैं। low-latency software video या audio playback असंभव नहीं था; 20 साल पहले भी संभव था
समस्या तब आती है जब busy system में non-preemptible I/O बार-बार बीच में आता है, लेकिन embedded environments में ऐसा कम होता है। kernel को पूरी तरह preemptible बनाने और scheduling control ज़्यादा देने के मजबूत कारण हैं, लेकिन इसका Linux द्वारा minimal real-time operating systems या bare-metal code को replace करने की ज़रूरत से कम ही संबंध है
यह बस अच्छी hygiene जैसा है, और इससे non-real-time applications में भी load के दौरान बेहतर काम करने वाला operating system बनता है
यह अच्छी खबर है, लेकिन Linux kernel real-time हो भी जाए, तब भी cache और CPU के अंदरूनी जटिल जादू की वजह से hardware के real-time न होने की संभावना बड़ी है
बड़ा और जटिल hardware असली real-time के लिए ठीक नहीं बैठता। इसलिए AbsInt और worst-case execution time (WCET) tools मुख्यतः सरल CPU architectures से ही निपटते हैं। 8051 सचमुच हमेशा जिंदा रहने वाला है। संदर्भ के लिए Zephyr RTOS भी है
मान सकते हैं कि cache hit बिल्कुल नहीं होंगे और load अधिकतम होगा, आदि। अगर लगने वाले समय की upper bound रखी जा सके तो ठीक है
timer quadrature encoder input ले सकता है और wrap होने पर ही interrupt भेज सकता है, या GPIO system को DMA से जोड़कर CPU की दखल के बिना memory को output pins पर stream किया जा सकता है। DAC पर streaming या ADC से memory में DMA transfer भी संभव है। ऐसी चीज़ें अक्सर predictable latency के लिए cache को bypass करती हैं
असल में कई real-time systems को लगातार बढ़ते sensor data को process और aggregate करना पड़ता है, इसलिए वे और शक्तिशाली होते जा रहे हैं
शुरुआती दिनों में मैंने परेशान कर देने वाली संख्या में ऐसे interviews दिए जहाँ interviewers को real-time का असल मतलब ही पता नहीं था। लेख में आए “और predictable latency” वाले concept को बहुत लोग छोड़ देते थे, और लगता था कि वे real-time को बस “तेज़” मानते हैं
अगर आप car braking system control कर रहे हैं, तो “average latency 50ms है लेकिन maximum 80ms” स्वीकार्य हो सकता है, लेकिन “average latency 1ms है मगर मनमाने ढंग से लंबी हो सकती है और कुछ seconds भी लग सकते हैं” स्वीकार्य नहीं है
synchronous logging ने फिर समस्या पैदा की। कंपनी में GLOG (Google logging library) की वजह से हमारे साथ ऐसा ही हुआ था; उदाहरण के लिए अगर stdout एक file है तो disk I/O में block हो सकता है
जब हमारी service 100ms से ज़्यादा रुकती थी, तो 90–99% मामलों में कारण GLOG था
“जिसे log करना अनिवार्य है, लेकिन log कर पाना संभव नहीं है, तो क्या करेंगे?” आजकल मैं बस CAP theorem की ओर इशारा करता हूँ और कहता हूँ कि logging भी किसी दूसरे distributed system जैसी ही है। शायद इसलिए कि Wikipedia article में triangle diagram और “theorem” शब्द है, लोग इसे मान लेते हैं
उसके बाद हमने UDP transport पर switch कर दिया। पूरे production को खोने से बेहतर है कुछ logs खो देना
$MSFTlogging library में भी “logging library सब कुछ बिगाड़ देती है” वाली किस्म की समस्या थी। कल्पना कीजिए कि 100 threads में से हर एक के पास 300MB का logging buffer होजाहिर है memory चकनाचूर हो गई, और Azure App Service के सबसे महंगे SKU पर भी server crash हो गया
पुरानी यादें ताज़ा हो गईं। करीब 17–18 साल पहले, ज्यादा tight timing की जरूरत वाले scientific equipment में इस्तेमाल के लिए मैंने Debian के लिए kernel को RT_PREEMPT के साथ compile किया था
latency और jitter बहुत प्रभावशाली थे। उसके बाद मैंने इसके बारे में लगभग नहीं सोचा, लेकिन Raspberry Pi से embedded applications बनाते समय, जहाँ RTOS वाले microcontroller पर जाना न चाहें, वहाँ इसके उपयोग की काफी गुंजाइश लगती है
पहले भी मैंने यह प्रस्ताव देखा था कि Linux को RTOS के task के रूप में चलाया जा सकता है, इसलिए यह खास तौर पर दिलचस्प लगा। जिन चीज़ों को hard real-time deadlines चाहिए, उन्हें RTOS पर चलाएँ, ताकि वे virtual memory system से आ सकने वाली delays से प्रभावित न हों। याद नहीं कि यह सिर्फ idea था या सच में implement हुआ था, और RpiOS के RTOS के ऊपर होने का जिक्र भी मैंने सिर्फ एक बार देखा है, इसलिए उत्सुकता है
आम users के लिए इसका क्या मतलब है, यह जानने की उत्सुकता है। क्या यह ऐसी सुविधा है जिसे सिर्फ बहुत खास स्थितियों में चालू किया जाता है, या यह आम जनता को भी ज़्यादा responsive system दे सकती है?
हर task को X नाम का budget मिलता है और उसे उससे बाहर नहीं जाना चाहिए। अगर best case तेज़ है लेकिन worst case धीमा है, तो इसका मतलब है कि system को हमेशा worst case मानकर चलना होगा
synchronous
printk()calls से बचने वाला उदाहरण बिल्कुल वैसा ही है, और RT चालू न होने पर भी load की स्थिति में latency बेहतर होनी चाहिए। पूरी तरह upstream हो चुका RT kernel वास्तव में तब तक सामान्य kernel से अलग व्यवहार नहीं करेगा जब तक आप RT process नहीं चला रहे हों। upstream में इतना समय लगने की वजह यह थी कि RT को संभव बनाने के लिए trade-offs चाहिए थे, और लेख के अनुसार ऐसे trade-offs अब बहुत ज़्यादा नहीं बचे हैंक्योंकि real-time scheduling की जरूरत होने पर भी latest mainline kernel इस्तेमाल किया जा सकेगा
Xenomai[1] के बारे में आपकी क्या राय है, यह जानने की उत्सुकता है। कई सालों से इसे बिना समस्या इस्तेमाल कर रहा हूँ
BeagleBone Black पर आमतौर पर सैकड़ों nanoseconds के स्तर का jitter मिलता है, और इसे “hard” real-time मानता हूँ। दसियों microseconds के interval पर periodic tasks schedule किए जा सकते हैं और कभी miss नहीं होते
Real-Time Linux जहाँ Linux को ही preemptible बनाने की कोशिश करता है, वहीं Xenomai मूल रूप से अपना खुद का kernel है और Linux को उसके ऊपर एक task के रूप में चलाता है। यह ABI देता है जिससे user के बनाए tasks Linux के साथ-साथ या उससे higher priority पर चल सकते हैं। उदाहरण के लिए
printk()वाली समस्या को bypass किया जा सकता है, क्योंकि Xenomai उसकी परवाह नहीं करता और user के task को चलाने के लिएprintkसे context switch करने को तैयार रहता हैनुकसान यह है कि Xenomai context के अंदर सामान्य system calls नहीं कर सकते। कर तो सकते हैं, लेकिन स्वाभाविक रूप से इससे real-time model टूट जाता है। उदाहरण के लिए Xenomai task के अंदर
printf()याmalloc()call करने पर वह preemptible नहीं रहता। Xenomai ABI system calls के मामले में जरूरत पड़ सकने वाली चीज़ों को जितना हो सके replicate कर देता है, और अगर आप खुद heap allocation संभालने से संतुष्ट हैं तो यह बहुत अच्छी तरह काम करता है[1]: https://xenomai.org/