CPython 3.15 का JIT फिर से सही राह पर
(blog.python.org)मुख्य उपलब्धियां
| प्लेटफ़ॉर्म | JIT प्रदर्शन सुधार (टेल-कॉलिंग इंटरप्रेटर की तुलना में) |
|---|---|
| macOS AArch64 | +11~12% |
| x86_64 Linux | +5~6% |
बेंचमार्क रेंज: 20% धीमा होने से लेकर 100% से अधिक तेज़ होने तक (
unpack_sequenceमाइक्रोबेंचमार्क को छोड़कर)
- लक्ष्य हासिल: 3.15 का लक्ष्य (5% सुधार) 1 साल से भी पहले हासिल
- free-threading सपोर्ट: अभी अधूरा है, 3.15/3.16 को लक्ष्य बनाकर काम जारी
मुख्य सीख
-
स्पॉन्सर का हटना = संकट → कम्युनिटी-ड्रिवन बदलाव
Faster CPython टीम का मुख्य स्पॉन्सर 2025 में हट गया, फिर भी कम्युनिटी के स्वैच्छिक योगदान से योगदानकर्ताओं की संख्या बढ़ी और ठोस नतीजे मिले। -
जटिल समस्याओं को छोटे हिस्सों में तोड़ें
JIT जैसे ऊंची एंट्री-बैरियर वाले प्रोजेक्ट में भी, काम को छोटे यूनिट में बांटना और स्पष्ट गाइड देना ऐसा साबित हुआ कि C प्रोग्रामिंग अनुभव रखने वाले गैर-विशेषज्ञ भी योगदान दे सके। -
bus factor कम होना स्वस्थ प्रोजेक्ट की निशानी है
मिडल स्टेज (optimizer) में योगदानकर्ता 2 से बढ़कर 4 हो गए, और non-core डेवलपर भी मुख्य योगदानकर्ता बनकर उभरे। -
मापन इन्फ्रास्ट्रक्चर डेवलपमेंट की गति बदल देता है
हर दिन JIT प्रदर्शन रिपोर्ट करने वाली प्रणाली(doesjitgobrrr.com) ने regression को जल्दी पकड़ने और टीम की प्रेरणा बनाए रखने, दोनों में निर्णायक भूमिका निभाई। -
कम्युनिटियों के बीच आदान-प्रदान तकनीकी क्षमता बढ़ाता है
PyPy टीम के साथ संवाद और compiler डेवलपर्स के साथ अनौपचारिक बातचीत ने वास्तविक तकनीकी प्रगति में मदद की।
पृष्ठभूमि और उपलब्धियां
[IMG] JIT प्रदर्शन ग्राफ़ (17 मार्च 2026 तक, जितना कम उतना इंटरप्रेटर से तेज़)
(17 मार्च 2026 तक का JIT प्रदर्शन। जितना कम, उतना इंटरप्रेटर की तुलना में तेज़। छवि स्रोत: doesjitgobrrr.com)
अच्छी खबर है। macOS AArch64 पर CPython JIT ने लक्ष्य से 1 साल से भी पहले, और x86_64 Linux पर कई महीने पहले अपना (काफी मामूली) प्रदर्शन लक्ष्य हासिल कर लिया है। 3.15 alpha JIT, macOS AArch64 पर टेल-कॉलिंग इंटरप्रेटर से लगभग 11~12% तेज़ है, और x86_64 Linux पर स्टैंडर्ड इंटरप्रेटर से 5~6% तेज़ है। ये आंकड़े geometric mean हैं और अभी प्रारंभिक हैं। वास्तविक रेंज 20% धीमा होने से लेकर 100% से अधिक तेज़ होने तक जाती है (unpack_sequence माइक्रोबेंचमार्क को छोड़कर)। अभी सही मायने में free-threading सपोर्ट नहीं है, लेकिन 3.15/3.16 में इसे लक्ष्य बनाया गया है। अब JIT फिर से सही राह पर है।
यह कितना कठिन था, इसे बढ़ा-चढ़ाकर बताना भी कम होगा। एक समय ऐसा भी था जब गंभीर रूप से शक था कि JIT प्रोजेक्ट कोई सार्थक speedup दे भी पाएगा या नहीं। पीछे मुड़कर देखें तो मूल CPython JIT में लगभग कोई प्रदर्शन लाभ नहीं था। 8 महीने पहले मैंने JIT पर एक पुनरावलोकन लेख लिखा था, जिसमें बताया था कि 3.13 और 3.14 का मूल CPython JIT अक्सर इंटरप्रेटर से भी धीमा था। वही वह समय था जब Faster CPython टीम ने अपने मुख्य स्पॉन्सर का समर्थन खो दिया था। मैं स्वयं वॉलंटियर था, इसलिए मुझ पर इसका सीधा असर नहीं पड़ा, लेकिन वहां काम कर रहे साथियों पर ज़रूर पड़ा, और एक समय JIT का भविष्य अनिश्चित लगने लगा था।
तो 3.13 और 3.14 की तुलना में क्या बदला? मैं यह कोई वीरगाथा नहीं सुनाऊंगा कि हमने अपनी बुद्धिमत्ता से JIT को विफलता के मुहाने से बचा लिया। सच कहूं तो, मौजूदा सफलता का बड़ा हिस्सा किस्मत का नतीजा है। सही समय, सही जगह, सही लोग, सही फैसले। मैं गंभीरता से मानता हूं कि अगर मुख्य JIT योगदानकर्ताओं Savannah Ostrowski, Mark Shannon, Diego Russo, Brandt Bucher और मुझमें से कोई एक भी न होता, तो यह संभव नहीं था। अन्य सक्रिय JIT योगदानकर्ताओं का नाम भी लेना चाहूंगा: Hai Zhu, Zheaoli, Tomas Roun, Reiden Ong, Donghee Na, और शायद कुछ नाम छूट भी रहे हों।
मैं JIT के उस हिस्से की बात करना चाहता हूं जिस पर कम चर्चा होती है: लोग, और थोड़ी किस्मत। अगर आपको तकनीकी विवरण चाहिए, तो यहां देख सकते हैं।
भाग 1: कम्युनिटी-ड्रिवन JIT
Faster CPython टीम ने 2025 में अपना मुख्य स्पॉन्सर खो दिया। मैंने तुरंत कम्युनिटी-ड्रिवन stewardship का विचार प्रस्तावित किया। उस समय यह काफी अनिश्चित था कि यह काम करेगा भी या नहीं। JIT प्रोजेक्ट नए योगदानकर्ताओं के लिए आसान नहीं माना जाता है। ऐतिहासिक रूप से इसमें पहले से काफी विशेषज्ञता की जरूरत पड़ती रही है।
Cambridge में हुए CPython core sprint में JIT core टीम मिली और 3.15 तक 5% तेज़ JIT, 3.16 तक 10% तेज़ JIT और free-threading सपोर्ट के लिए एक योजना तैयार की। एक और बात थी जिस पर कम ध्यान गया, लेकिन जो प्रोजेक्ट की सेहत के लिए ज़रूरी थी: bus factor को कम करना। हम चाहते थे कि JIT के तीनों चरणों—frontend का region selector, middle-end का optimizer, और backend का code generator—हर हिस्से में कम से कम 2 सक्रिय मेंटेनर हों।
पहले JIT middle-end में केवल 2 सक्रिय recurring contributor थे। आज JIT middle-end में 4 सक्रिय recurring contributor हैं, और 2 non-core डेवलपर (Hai Zhu और Reiden) सक्षम और मूल्यवान सदस्य बन चुके हैं।
लोगों को जोड़ने में जो तरीका प्रभावी रहा, वह था सामान्य software engineering अभ्यास: जटिल समस्याओं को संभालने लायक हिस्सों में तोड़ना। Brandt ने 3.14 में इसकी शुरुआत की थी। उन्होंने JIT optimization को छोटे कार्यों में बांटने के लिए कई mega issue खोले। उदाहरण के लिए, "JIT में एक ही instruction को optimize करके देखें" जैसी शैली। मैंने Brandt के विचार को आगे बढ़ाया और 3.15 में भी लागू किया। सौभाग्य से मुझे अपेक्षाकृत आसान काम मिला: interpreter instructions को ऐसे रूप में बदलने वाले issue, जिन्हें optimize करना आसान हो। नए योगदानकर्ताओं को प्रोत्साहित करने के लिए मैंने बहुत विस्तृत निर्देश ऐसे व्यवस्थित किए कि उन पर तुरंत काम शुरू किया जा सके। साथ ही, काम की सीमाएं भी स्पष्ट रखीं। लगता है इससे मदद मिली। मुझ सहित 11 योगदानकर्ताओं ने उस issue पर काम किया और लगभग पूरे interpreter को JIT optimizer-friendly रूप में बदल दिया। मुख्य बात यह थी कि JIT को एक अपारदर्शी ब्लॉक की जगह ऐसी चीज़ में बदला गया, जिसमें JIT अनुभव न रखने वाला C प्रोग्रामर भी योगदान दे सके।
अन्य प्रभावी तरीके भी थे: लोगों को प्रोत्साहित करना, और छोटे-बड़े हर उपलब्धि का जश्न मनाना। हर JIT PR का एक स्पष्ट output था, और मुझे लगता है इससे लोगों को दिशा मिली।
कम्युनिटी optimization प्रयासों का असर हुआ। JIT, x86_64 Linux पर 1% तेज़ होने से बढ़कर 3~4% तेज़ हो गया (नीचे नीली रेखा देखें):
[IMG] कम्युनिटी optimization अवधि के दौरान JIT प्रदर्शन बनाम इंटरप्रेटर
(छवि स्रोत: doesjitgobrrr.com)
भाग 2: किस्मत वाले फैसले
Trace Recording
फिर से कहूं तो, मुझे लगता है इसका बड़ा हिस्सा किस्मत का नतीजा है। Cambridge CPython core sprint में Brandt ने मुझे JIT frontend को tracing-style में दोबारा लिखने के लिए राज़ी किया। शुरू में मुझे यह पसंद नहीं आया, लेकिन थोड़ी जिद में मैंने सोचा, "इसे फिर से लिखकर साबित करते हैं कि यह काम नहीं करेगा।"
शुरुआती prototype 3 दिन में चलने लगा, लेकिन उसे test suite पास कराते हुए सही तरीके से JIT करने लायक बनाने में एक महीना लग गया। शुरुआती नतीजे खराब थे। x86_64 Linux पर यह लगभग 6% धीमा था। जब मैं हार मानने ही वाला था, तभी एक सौभाग्यपूर्ण गलती हुई: मैं Mark के सुझाव को गलत समझ बैठा था।
Mark ने सुझाव दिया था कि dispatch table को interpreter में threaded तरीके से जोड़ा जाए, ताकि interpreter में दो dispatch table हों—एक सामान्य interpreter के लिए, और एक tracing के लिए। लेकिन मैंने इसे गलत समझा और उससे भी अधिक चरम संस्करण बना दिया: सामान्य instructions के tracing संस्करण रखने की बजाय, tracing के लिए सिर्फ एक instruction रखा और दूसरी table की सारी entries उसी को point करने लगीं। यह वाकई बहुत अच्छा फैसला साबित हुआ। शुरुआती dual-table तरीका interpreter का आकार दोगुना कर रहा था, जिससे code bloat और स्वाभाविक performance गिरावट हो रही थी। सिर्फ एक instruction और दो table इस्तेमाल करने से interpreter का आकार केवल 1 instruction जितना बढ़ा, और base interpreter बहुत तेज़ बना रहा। हम इस mechanism को प्यार से dual dispatch कहते हैं।
Trace recording कितना महत्वपूर्ण था, यह इस संख्या से समझिए: JIT code coverage 50% बढ़ गई। इसका मतलब है कि भविष्य की हर optimization, आसान शब्दों में कहें तो, 50% कम प्रभावी होती अगर यह न हुआ होता।
Brandt और Mark का धन्यवाद, जिनकी वजह से यह शानदार समाधान संयोग से सामने आया।
Reference Count Elimination
एक और किस्मत वाला फैसला था reference count elimination को आज़माना। यह मूल रूप से Matt Page का CPython bytecode optimizer पर किया गया काम था। मैंने देखा कि bytecode optimizer के काम के बावजूद JIT किए गए code में हर reference count decrement के साथ एक branch बच रही थी। मैंने सोचा, "अगर इस branch को हटा दें तो?" और मुझे बिल्कुल अंदाज़ा नहीं था कि इससे कितना फायदा होगा। सिर्फ एक branch भी असल में काफी महंगी साबित हुई, और जब लगभग हर Python instruction में 1 या उससे अधिक branch हो, तो उनका असर जुड़ता जाता है।
एक और सौभाग्यपूर्ण बात यह थी कि इसे parallelize करना कितना आसान था, और यह interpreter तथा JIT को लोगों को सिखाने का अच्छा माध्यम भी बन गया। यही Python 3.15 JIT में लोगों को सौंपा गया मुख्य optimization था। यह अधिकतर manual refactoring प्रक्रिया थी, लेकिन इससे लोगों को JIT के अहम हिस्सों को बिना भारी लगे सीखने का अवसर मिला।
भाग 3: शानदार टीम
हमारे पास शानदार infrastructure टीम है। सच कहूं तो यह एक ही व्यक्ति है। वास्तव में हमारी "टीम" फिलहाल Savannah की अलमारी में चल रही 4 मशीनों से बनी है। इसके बावजूद Savannah ने JIT के लिए पूरी infrastructure टीम जितना काम कर दिखाया। अगर प्रदर्शन आंकड़े रिपोर्ट करने का कोई तरीका न होता, तो JIT इतनी तेज़ी से आगे नहीं बढ़ पाता। हर दिन आने वाले JIT रन के नतीजे feedback loop में game changer साबित हुए। इससे JIT प्रदर्शन की regression पकड़ने में मदद मिली, और यह पुष्टि भी हुई कि हमारी optimization वाकई काम कर रही हैं।
Mark तकनीकी रूप से शानदार हैं। मुझे लगता है इंटरनेट पहले ही उनकी काफी तारीफ कर चुका है, इसलिए मैं इससे ज्यादा कुछ नहीं कहूंगा :).
Diego भी शानदार हैं। वे ARM hardware पर JIT का काम संभालते हैं, और हाल में उन्होंने JIT को profiler-friendly बनाने का काम शुरू किया है। यह समस्या कितनी कठिन है, इसे बढ़ा-चढ़ाकर बताना भी कम होगा।
Brandt ने machine code backend की मूल नींव रखी। अगर यह न होता, तो नए योगदानकर्ताओं को assembler लिखना पड़ता, और शायद इससे और भी अधिक लोग दूर हो जाते।
भाग 4: लोगों से बात करना
मैं लोगों से बात करने और विचार साझा करने के महत्व पर ज़ोर देना चाहता हूं।
CF Bolz-Tereick का धन्यवाद, जिन्होंने मुझे PyPy के बारे में बहुत कुछ सिखाया। मैंने कई महीनों तक PyPy source code को देखा, और मुझे लगता है कि इससे मैं कुल मिलाकर बेहतर JIT डेवलपर बना। जब भी मदद चाहिए होती थी, CF बहुत सहायक रहे।
मैं Max Bernstein के साथ दोस्ताना compiler chat में शामिल रहता हूं, और इसके बिना शायद मैं बहुत पहले ही प्रेरणा खो चुका होता। Max एक prolific लेखक और सहज compiler विशेषज्ञ हैं।
विचार अलग-थलग जगहों में पैदा नहीं होते। मुझे लगता है कि कुछ समय तक compiler डेवलपर्स के साथ मेलजोल रखने से मैं JIT लिखने में बेहतर हुआ। कम से कम, PyPy को देखना मेरे दृष्टिकोण को ज़रूर व्यापक बना गया!
निष्कर्ष
लोग मायने रखते हैं। और अगर थोड़ी किस्मत साथ हो, तो JIT go brrr.
अभी कोई टिप्पणी नहीं है.