डाइनैमिक एक्ज़ीक्यूशन, Bazel की एक सुविधा है. इसमें एक ही कार्रवाई को स्थानीय और रिमोट, दोनों जगहों पर एक साथ शुरू किया जाता है. इसमें, सबसे पहले पूरा होने वाले ब्रांच के आउटपुट का इस्तेमाल किया जाता है और दूसरी ब्रांच को रद्द कर दिया जाता है. यह रिमोट बिल्ड सिस्टम की एक्ज़ीक्यूशन पावर और/या बड़ी शेयर की गई कैश मेमोरी को लोकल एक्ज़ीक्यूशन की कम लेटेन्सी के साथ जोड़ता है. इससे, क्लीन और इंक्रीमेंटल बिल्ड, दोनों के लिए सबसे अच्छा विकल्प मिलता है.
इस पेज पर, डाइनैमिक एक्ज़ीक्यूशन की सुविधा को चालू करने, उसे बेहतर बनाने, और डीबग करने का तरीका बताया गया है. अगर आपने लोकल और रिमोट, दोनों तरह के एक्ज़ीक्यूशन सेट अप किए हैं और आपको बेहतर परफ़ॉर्मेंस के लिए Bazel की सेटिंग में बदलाव करना है, तो यह पेज आपके लिए है. अगर आपने पहले से रिमोट एक्ज़ीक्यूशन सेट अप नहीं किया है, तो सबसे पहले Bazel के रिमोट एक्ज़ीक्यूशन की खास जानकारी पर जाएं.
क्या डाइनैमिक एक्ज़ीक्यूशन की सुविधा चालू है?
डाइनैमिक एक्ज़ीक्यूशन मॉड्यूल, Bazel का हिस्सा है. हालांकि, डाइनैमिक एक्ज़ीक्यूशन का इस्तेमाल करने के लिए, आपके पास एक ही Bazel सेटअप से स्थानीय और रिमोट, दोनों जगहों पर कंपाइल करने की सुविधा होनी चाहिए.
डाइनैमिक एक्ज़ीक्यूशन मॉड्यूल चालू करने के लिए, Bazel को --internal_spawn_scheduler
फ़्लैग पास करें. इससे dynamic
नाम की नई रणनीति जुड़ जाती है. अब इसका इस्तेमाल, उन नेमोनिक के लिए रणनीति के तौर पर किया जा सकता है जिन्हें आपको डाइनैमिक तरीके से चलाना है. जैसे, --strategy=Javac=dynamic
. अगले सेक्शन में देखें कि किन निमोनिक के लिए डाइनैमिक एक्ज़ीक्यूशन की सुविधा चालू करनी है.
डाइनैमिक रणनीति का इस्तेमाल करने वाले किसी भी नेमोनिक के लिए, रिमोट एक्सीक्यूशन की रणनीतियां --dynamic_remote_strategy
फ़्लैग से ली जाती हैं. वहीं, लोकल रणनीतियां --dynamic_local_strategy
फ़्लैग से ली जाती हैं. --dynamic_local_strategy=worker,sandboxed
पास करने पर, डाइनैमिक एक्ज़ीक्यूशन की लोकल ब्रांच के लिए डिफ़ॉल्ट सेटिंग सेट हो जाती है. इससे वर्कर या सैंडबॉक्स किए गए एक्ज़ीक्यूशन के साथ उस क्रम में कोशिश की जा सकती है. --dynamic_local_strategy=Javac=worker
को पास करने पर, सिर्फ़ Javac के लिए डिफ़ॉल्ट सेटिंग बदल जाती है. रिमोट वर्शन भी इसी तरह काम करता है. दोनों फ़्लैग को एक से ज़्यादा बार तय किया जा सकता है. अगर कोई कार्रवाई स्थानीय तौर पर नहीं की जा सकती, तो उसे सामान्य तरीके से रिमोटली किया जाता है. इसके उलट, अगर कोई कार्रवाई रिमोटली नहीं की जा सकती, तो उसे स्थानीय तौर पर किया जाता है.
अगर आपके रिमोट सिस्टम में कैश मेमोरी है, तो --dynamic_local_execution_delay
फ़्लैग, रिमोट सिस्टम के कैश मेमोरी हिट होने का संकेत देने के बाद, लोकल एक्सीक्यूशन में मिलीसेकंड की देरी जोड़ता है. इससे ज़्यादा कैश हिट होने की संभावना होने पर, लोकल एक्ज़ीक्यूशन को चलाने से बचा जा सकता है. डिफ़ॉल्ट वैल्यू 1000 मि॰से॰ होती है. हालांकि, इसे इस तरह से ट्यून किया जाना चाहिए कि यह आम तौर पर कैश हिट में लगने वाले समय से थोड़ा ज़्यादा हो. असल समय, रिमोट सिस्टम और राउंड-ट्रिप में लगने वाले समय, दोनों पर निर्भर करता है. आम तौर पर, किसी रिमोट सिस्टम के सभी उपयोगकर्ताओं के लिए वैल्यू एक जैसी होती है. हालांकि, अगर कुछ उपयोगकर्ता इतनी दूर हैं कि राउंडट्रिप में लगने वाला समय बढ़ जाता है, तो वैल्यू अलग हो सकती है. Bazel की प्रोफ़ाइलिंग की सुविधाओं का इस्तेमाल करके, यह देखा जा सकता है कि आम तौर पर कैश हिट होने में कितना समय लगता है.
डाइनैमिक एक्सीक्यूशन का इस्तेमाल, लोकल सैंडबॉक्स रणनीति के साथ-साथ परसिस्टेंट वर्कर के साथ भी किया जा सकता है. डाइनैमिक एक्ज़ीक्यूशन के साथ इस्तेमाल किए जाने पर, परसिस्टेंट वर्कर सैंडबॉक्सिंग के साथ अपने-आप चलेंगे. साथ ही, वे मल्टीप्लेक्स वर्कर का इस्तेमाल नहीं कर सकते. Darwin और Windows सिस्टम पर, सैंडबॉक्स वाली रणनीति धीमी हो सकती है. इन सिस्टम पर सैंडबॉक्स बनाने का ओवरहेड कम करने के लिए, --reuse_sandbox_directories
पास किया जा सकता है.
डाइनैमिक एक्ज़ीक्यूशन, standalone
रणनीति के साथ भी काम कर सकता है. हालांकि, standalone
रणनीति को एक्ज़ीक्यूट करना शुरू करते समय आउटपुट लॉक करना होता है. इसलिए, यह रिमोट रणनीति को पहले पूरा होने से रोकता है. --experimental_local_lockfree_output
फ़्लैग की मदद से, इस समस्या को हल किया जा सकता है. यह फ़्लैग, लोकल एक्ज़ीक्यूशन को सीधे तौर पर आउटपुट में लिखने की अनुमति देता है. हालांकि, अगर रिमोट एक्ज़ीक्यूशन पहले पूरा हो जाता है, तो लोकल एक्ज़ीक्यूशन को बंद कर दिया जाता है.
अगर डाइनैमिक तरीके से कोड चलाने की सुविधा की कोई ब्रांच पहले पूरी हो जाती है, लेकिन वह काम नहीं करती है, तो पूरा ऐक्शन काम नहीं करेगा. ऐसा जान-बूझकर किया गया है, ताकि लोकल और रिमोट एक्ज़ीक्यूशन के बीच के अंतर को अनदेखा न किया जा सके.
डाइनैमिक एक्ज़ीक्यूशन और इसके लॉक होने के तरीके के बारे में ज़्यादा जानने के लिए, जूलियो मेरिनो की बेहतरीन ब्लॉग पोस्ट पढ़ें
मुझे डाइनैमिक एक्ज़ीक्यूशन का इस्तेमाल कब करना चाहिए?
डाइनैमिक एक्ज़ीक्यूशन के लिए, किसी तरह के रिमोट एक्ज़ीक्यूशन सिस्टम की ज़रूरत होती है. फ़िलहाल, सिर्फ़ कैश मेमोरी वाले रिमोट सिस्टम का इस्तेमाल नहीं किया जा सकता. ऐसा इसलिए, क्योंकि कैश मेमोरी में मौजूद न होने वाले डेटा को कार्रवाई पूरी न होने की वजह माना जाएगा.
सभी तरह की कार्रवाइयों को रिमोट ऐक्सेस से नहीं किया जा सकता. सबसे अच्छे उम्मीदवार वे होते हैं जो स्थानीय तौर पर तेज़ी से काम करते हैं. उदाहरण के लिए, परसिस्टेंट वर्कर का इस्तेमाल करके. इसके अलावा, वे उम्मीदवार भी अच्छे होते हैं जो इतनी तेज़ी से काम करते हैं कि रिमोट एक्ज़ीक्यूशन का ओवरहेड, एक्ज़ीक्यूशन के समय पर हावी हो जाता है. स्थानीय तौर पर की जाने वाली हर कार्रवाई के लिए, सीपीयू और मेमोरी के कुछ संसाधनों को लॉक कर दिया जाता है. इसलिए, इन कैटगरी में न आने वाली कार्रवाइयों को चलाने से, इन कैटगरी में आने वाली कार्रवाइयों को पूरा होने में ज़्यादा समय लगता है.
रिलीज़ 5.0.0-pre.20210708.4 के बाद से, परफ़ॉर्मेंस प्रोफ़ाइलिंग में वर्कर के एक्ज़ीक्यूशन से जुड़ा डेटा शामिल होता है. इसमें डाइनैमिक एक्ज़ीक्यूशन रेस हारने के बाद, काम के अनुरोध को पूरा करने में लगने वाला समय भी शामिल होता है. अगर आपको दिखता है कि डाइनैमिक एक्ज़ीक्यूशन वर्कर थ्रेड, संसाधनों को हासिल करने में ज़्यादा समय लगा रही हैं या async-worker-finish
में ज़्यादा समय लग रहा है, तो हो सकता है कि कुछ लोकल कार्रवाइयों की वजह से वर्कर थ्रेड में देरी हो रही हो.
ऊपर दी गई प्रोफ़ाइल में, आठ Javac वर्कर का इस्तेमाल किया गया है. इसमें हम देखते हैं कि कई Javac वर्कर, रेस हार गए हैं और async-worker-finish
थ्रेड पर अपना काम पूरा कर रहे हैं. ऐसा इसलिए हुआ, क्योंकि नॉन-वर्कर नेमोनिक ने वर्कर को डिले करने के लिए काफ़ी संसाधन लिए.
डाइनैमिक एक्ज़ीक्यूशन के साथ सिर्फ़ Javac चलाने पर, काम शुरू करने वाले सिर्फ़ आधे वर्कर, काम शुरू करने के बाद रेस हार जाते हैं.
पहले सुझाया गया --experimental_spawn_scheduler
फ़्लैग अब काम नहीं करता.
यह डाइनैमिक एक्ज़ीक्यूशन को चालू करता है और सभी
नियमों के लिए dynamic
को डिफ़ॉल्ट रणनीति के तौर पर सेट करता है. इससे अक्सर इस तरह की समस्याएं होती हैं.
परफ़ॉर्मेंस
डाइनैमिक एक्ज़ीक्यूशन के तरीके में यह माना जाता है कि स्थानीय और रिमोट तौर पर, ज़रूरत के मुताबिक संसाधन उपलब्ध हैं. इसलिए, कुल परफ़ॉर्मेंस को बेहतर बनाने के लिए, कुछ अतिरिक्त संसाधन खर्च किए जा सकते हैं. हालांकि, संसाधनों का ज़्यादा इस्तेमाल करने से Bazel या उस मशीन की स्पीड कम हो सकती है जिस पर यह चलता है. इसके अलावा, इससे रिमोट सिस्टम पर ज़रूरत से ज़्यादा दबाव पड़ सकता है. डाइनैमिक एक्ज़ीक्यूशन के व्यवहार को बदलने के लिए, कई विकल्प उपलब्ध हैं:
--dynamic_local_execution_delay
, रिमोट ब्रांच के शुरू होने के बाद, लोकल ब्रांच को शुरू होने में कुछ मिलीसेकंड की देरी करता है. हालांकि, ऐसा सिर्फ़ तब होता है, जब मौजूदा बिल्ड के दौरान रिमोट कैश हिट हुआ हो. इससे रिमोट कैशिंग से फ़ायदा पाने वाले बिल्ड, स्थानीय संसाधनों को बर्बाद नहीं करते. ऐसा तब होता है, जब ज़्यादातर आउटपुट कैश में मिल सकते हैं. कैश की क्वालिटी के आधार पर, इसे कम करने से बिल्ड की स्पीड बेहतर हो सकती है. हालांकि, इससे ज़्यादा लोकल रिसॉर्स इस्तेमाल करने पड़ सकते हैं.
--experimental_dynamic_local_load_factor
, संसाधन मैनेज करने का एक बेहतर विकल्प है. फ़िलहाल, इसे आज़माया जा रहा है. इसकी वैल्यू 0 से 1 के बीच होती है. 0 का मतलब है कि यह सुविधा बंद है.
इस विकल्प को 0 से ज़्यादा वैल्यू पर सेट करने पर, Bazel स्थानीय तौर पर शेड्यूल की गई कार्रवाइयों की संख्या को अडजस्ट करता है. ऐसा तब होता है, जब शेड्यूल की जाने वाली कार्रवाइयों की संख्या ज़्यादा होती है. इसे 1 पर सेट करने से, सीपीयू की उपलब्धता (--local_cpu_resources
के मुताबिक) के आधार पर ज़्यादा से ज़्यादा कार्रवाइयों को शेड्यूल किया जा सकता है. कम वैल्यू सेट करने पर, शेड्यूल की गई कार्रवाइयों की संख्या कम हो जाती है, क्योंकि कार्रवाइयों की ज़्यादा संख्या उपलब्ध होती है. यह बात आपको अजीब लग सकती है, लेकिन अच्छे रिमोट सिस्टम के साथ, कई कार्रवाइयां एक साथ करने पर लोकल एक्ज़ीक्यूशन से ज़्यादा फ़ायदा नहीं मिलता. साथ ही, लोकल सीपीयू का इस्तेमाल रिमोट ऐक्शन को मैनेज करने के लिए बेहतर तरीके से किया जा सकता है.
--experimental_dynamic_slow_remote_time
, रिमोट ब्रांच के कम से कम इतने समय से चलने पर, स्थानीय ब्रांच शुरू करने को प्राथमिकता देता है. आम तौर पर, हाल ही में शेड्यूल किए गए ऐक्शन को प्राथमिकता मिलती है, क्योंकि इसके रेस जीतने की संभावना सबसे ज़्यादा होती है. हालांकि, अगर रिमोट सिस्टम कभी-कभी हैंग हो जाता है या ज़्यादा समय लेता है, तो इससे बिल्ड को आगे बढ़ने में मदद मिल सकती है. यह सुविधा डिफ़ॉल्ट रूप से चालू नहीं होती, क्योंकि इससे रिमोट सिस्टम की ऐसी समस्याएं छिप सकती हैं जिन्हें ठीक किया जाना चाहिए. इस विकल्प को चालू करने पर, रिमोट सिस्टम की परफ़ॉर्मेंस पर नज़र रखें.
--experimental_dynamic_ignore_local_signals
का इस्तेमाल, रिमोट ब्रांच को तब चालू करने के लिए किया जा सकता है, जब कोई लोकल स्पॉन किसी सिग्नल की वजह से बंद हो जाता है. यह सुविधा, वर्कर रिसॉर्स की सीमाओं के साथ इस्तेमाल करने पर ज़्यादा फ़ायदेमंद होती है. इसके बारे में जानने के लिए, --experimental_worker_memory_limit_mb
, --experimental_worker_sandbox_hardening
, और --experimental_sandbox_memory_limit_mb
देखें. ऐसा तब होता है, जब वर्कर प्रोसेस बहुत ज़्यादा संसाधनों का इस्तेमाल करती हैं.
JSON ट्रेस प्रोफ़ाइल में परफ़ॉर्मेंस से जुड़े कई ग्राफ़ होते हैं. इनसे परफ़ॉर्मेंस और संसाधन के इस्तेमाल के बीच बेहतर तालमेल बिठाने के तरीके पता लगाए जा सकते हैं.
समस्या का हल
डाइनैमिक एक्ज़ीक्यूशन से जुड़ी समस्याएं, बहुत कम दिखती हैं और इन्हें डीबग करना मुश्किल होता है. ऐसा इसलिए, क्योंकि ये समस्याएं सिर्फ़ लोकल और रिमोट एक्ज़ीक्यूशन के कुछ खास कॉम्बिनेशन में दिख सकती हैं.
--debug_spawn_scheduler
, डाइनैमिक एक्ज़ीक्यूशन सिस्टम से अतिरिक्त आउटपुट जोड़ता है. इससे इन समस्याओं को डीबग करने में मदद मिल सकती है. समस्याओं को आसानी से दोहराने के लिए, --dynamic_local_execution_delay
फ़्लैग और रिमोट बनाम लोकल नौकरियों की संख्या को भी अडजस्ट किया जा सकता है.
अगर आपको standalone
रणनीति का इस्तेमाल करके डाइनैमिक एक्ज़ीक्यूशन में समस्याएं आ रही हैं, तो --experimental_local_lockfree_output
के बिना रन करने की कोशिश करें या स्थानीय कार्रवाइयों को सैंडबॉक्स में रन करें. इससे, हो सकता है कि आपका बिल्ड थोड़ा धीमा हो जाए. अगर आपको Mac या Windows पर यह समस्या आ रही है, तो ऊपर दिया गया तरीका देखें. हालांकि, इससे गड़बड़ियों की कुछ संभावित वजहें दूर हो जाती हैं.