डाइनैमिक एक्ज़ीक्यूशन

डाइनैमिक एक्ज़ीक्यूशन, Bazel के 0.21 के बाद के वर्शन की एक सुविधा है. इसमें, एक ही कार्रवाई को लोकल और रिमोट तौर पर शुरू किया जाता है. इसमें, खत्म होने वाली पहली ब्रांच के आउटपुट का इस्तेमाल किया जाता है और दूसरी ब्रांच को रद्द कर दिया जाता है. इसमें रिमोट बिल्ड सिस्टम की एक्ज़ीक्यूशन पावर और/या बड़े शेयर की गई कैश मेमोरी को, लोकल एक्ज़ीक्यूशन की कम इंतज़ार के समय के साथ इस्तेमाल किया जाता है. इससे, क्लीन और इंक्रीमेंटल बिल्ड, दोनों के लिए बेहतरीन सुविधाएं मिलती हैं.

इस पेज पर, डाइनैमिक एक्ज़ीक्यूशन को चालू करने, ट्यून करने, और डीबग करने का तरीका बताया गया है. अगर आपने लोकल और रिमोट, दोनों फ़ॉर्मैट में एक्ज़ीक्यूशन सेट अप किया है और आपको बेहतर परफ़ॉर्मेंस के लिए Bazel की सेटिंग में बदलाव करना है, तो यह पेज आपके लिए है. अगर आपने पहले से रिमोट तरीके से एक्ज़ीक्यूट करने की सुविधा सेट अप नहीं की है, तो सबसे पहले Bazel रिमोट एक्ज़ीक्यूशन की खास जानकारी पर जाएं.

क्या आपको डाइनैमिक एक्ज़ीक्यूशन की सुविधा चालू करनी है?

डाइनैमिक एक्ज़ीक्यूशन मॉड्यूल, Bazel का हिस्सा है, लेकिन डाइनैमिक एक्ज़ीक्यूशन का इस्तेमाल करने के लिए, आपके पास एक ही Bazel सेटअप से लोकल और रिमोट तरीके से , दोनों कोड कंपाइल करने की सुविधा पहले से होनी चाहिए.

डाइनैमिक एक्ज़ीक्यूशन मॉड्यूल चालू करने के लिए, --internal_spawn_scheduler फ़्लैग को Bazel को पास करें. इससे लागू करने की एक नई रणनीति जुड़ जाती है, जिसे dynamic कहते हैं. अब इसका इस्तेमाल उन मेमोरी के लिए अपनी रणनीति के तौर पर किया जा सकता है जिन्हें आपको डाइनैमिक तौर पर चलाना है, जैसे कि --strategy=Javac=dynamic. अगला सेक्शन देखें और जानें कि डाइनैमिक एक्ज़ीक्यूशन की सुविधा किसको चालू करनी है.

डाइनैमिक रणनीति का इस्तेमाल करके याद रखने की किसी भी रणनीति के लिए, रिमोट एक्ज़ीक्यूशन की रणनीतियों को --dynamic_remote_strategy फ़्लैग से और स्थानीय रणनीतियों को --dynamic_local_strategy फ़्लैग से लिया जाता है. पासिंग --dynamic_local_strategy=worker,sandboxed, डाइनैमिक एक्ज़ीक्यूशन की लोकल ब्रांच के लिए डिफ़ॉल्ट रूप से सेट करता है, ताकि इस क्रम में वर्कर या सैंडबॉक्स वाले एक्ज़ीक्यूशन की मदद से आज़माया जा सके. --dynamic_local_strategy=Javac=worker को पास करने पर, सिर्फ़ Javac मेनेमोनिक के लिए डिफ़ॉल्ट सेटिंग लागू होती है. रिमोट वर्शन भी इसी तरह से काम करता है. दोनों फ़्लैग एक से ज़्यादा बार तय किए जा सकते हैं. अगर कोई कार्रवाई स्थानीय रूप से नहीं की जा सकती, तो उसे सामान्य तरीके से रिमोट तरीके से किया जाता है. इसी तरह, अगर कोई कार्रवाई स्थानीय तौर पर नहीं की जा सकती है, तो उसे किसी दूसरी जगह से भी किया जाता है.

अगर आपके रिमोट सिस्टम में कैश मेमोरी का इस्तेमाल किया गया है, तो --local_execution_delay फ़्लैग, रिमोट सिस्टम से कैश हिट होने का संकेत देने के बाद, लोकल एक्ज़ीक्यूशन में मिलीसेकंड में देरी जोड़ता है. इससे ज़्यादा कैश हिट होने की संभावना होने पर, लोकल एक्ज़ीक्यूशन नहीं चलाया जाता. डिफ़ॉल्ट वैल्यू 1000 मिलीसेकंड है, लेकिन आम तौर पर कैश हिट से थोड़ा ज़्यादा समय लेती है. असल समय, रिमोट सिस्टम और दोतरफ़ा यात्रा में लगने वाले समय पर निर्भर करता है. आम तौर पर, किसी भी रिमोट सिस्टम के सभी उपयोगकर्ताओं के लिए यह वैल्यू एक ही रहेगी. ऐसा तब तक होगा, जब तक कि उनमें से कुछ, दोतरफ़ा यात्रा का समय बढ़ाने के लिए काफ़ी न हों. Bazel प्रोफ़ाइलिंग सुविधाओं का इस्तेमाल करके, यह देखा जा सकता है कि आम तौर पर, कैश मेमोरी में सेव होने वाले हिट को कितना समय लगता है.

डाइनैमिक एक्ज़ीक्यूशन का इस्तेमाल, स्थानीय सैंडबॉक्स रणनीति के साथ-साथ नियमित तौर पर काम करने वाले कर्मचारियों के साथ किया जा सकता है. डाइनैमिक एक्ज़ीक्यूशन के साथ इस्तेमाल करने पर, स्थायी वर्कर अपने-आप सैंडबॉक्सिंग की मदद से चलेंगे. साथ ही, मल्टीप्लेक्स वर्कर का इस्तेमाल नहीं कर सकते. डार्विन और Windows सिस्टम पर, सैंडबॉक्स की गई रणनीति धीमी हो सकती है. इन सिस्टम पर सैंडबॉक्स बनाने का खर्च कम करने के लिए, --reuse_sandbox_directories को पास किया जा सकता है.

डाइनैमिक एक्ज़ीक्यूशन को standalone रणनीति के साथ भी चलाया जा सकता है. हालांकि, जब standalone रणनीति लागू करना शुरू करती है, तब आउटपुट लॉक की ज़रूरत होती है. इसलिए, यह रिमोट रणनीति को पहले खत्म होने से असरदार तरीके से ब्लॉक करती है. --experimental_local_lockfree_output फ़्लैग की मदद से इस समस्या को हल किया जा सकता है. इसके लिए, लोकल एक्ज़ीक्यूशन को आउटपुट में सीधे डेटा लिखने की अनुमति देता है. हालांकि, पहले इसे रिमोट एक्ज़ीक्यूशन के बाद रद्द किया जा सकता है.

अगर डाइनैमिक एक्ज़ीक्यूशन की कोई एक ब्रांच पहले खत्म हो जाती है, लेकिन वह फ़ेल हो जाता है, तो पूरी कार्रवाई फ़ेल हो जाती है. यह लोकल और रिमोट ऐक्सेस के बीच के फ़र्क़ को रोकने के लिए, एक सोच-समझकर चुना गया है.

डाइनैमिक एक्ज़ीक्यूशन और इसके लॉकिंग के काम करने के तरीके के बारे में ज़्यादा जानने के लिए, जूलियो मेरिनो की ब्लॉग पोस्ट देखें

मुझे डाइनैमिक एक्ज़ीक्यूशन का इस्तेमाल कब करना चाहिए?

डाइनैमिक तरीके से चलाने के लिए, किसी रिमोट एक्ज़ीक्यूशन सिस्टम की ज़रूरत होती है. फ़िलहाल, सिर्फ़ कैश मेमोरी वाले किसी रिमोट सिस्टम का इस्तेमाल नहीं किया जा सकता, क्योंकि कैश मेमोरी में सेव न हो पाने को असफल कार्रवाई माना जाएगा.

रिमोट तौर पर एक्ज़ीक्यूशन के लिए, सभी तरह की कार्रवाइयां सही नहीं होती हैं. सबसे अच्छे कैंडिडेट वे होते हैं जो स्थानीय स्तर पर तेज़ी से काम करते हैं. उदाहरण के लिए, नियमित तौर पर काम करने वाले कर्मचारियों का इस्तेमाल करके या ऐसे लोग जो इतनी तेज़ी से चलते हैं कि ऑफ़िस से दूर रहकर एक्ज़ीक्यूशन का काम बहुत ज़्यादा समय तक होता है. स्थानीय तौर पर लागू की गई हर कार्रवाई, कुछ सीपीयू और मेमोरी रिसॉर्स को लॉक करती है. इसलिए, जो कार्रवाइयां इन कैटगरी में नहीं आती हैं उन्हें चलाने में सिर्फ़ देरी होती है.

रिलीज़ के समय तक 5.0.0-pre.20210708.4, परफ़ॉर्मेंस प्रोफ़ाइल इसमें वर्कर के एक्ज़ीक्यूशन के बारे में डेटा शामिल होता है. इसमें, डाइनैमिक एक्ज़ीक्यूशन रेस हारने के बाद, काम के अनुरोध को पूरा करने में लगने वाला समय भी शामिल होता है. अगर आपको डाइनैमिक एक्ज़ीक्यूशन के लिए बने थ्रेड दिखते हैं, जिनमें संसाधन पाने में काफ़ी समय लग रहा है या async-worker-finish में बहुत ज़्यादा समय लग रहा है, तो हो सकता है कि लोकल ऐक्शन से होने वाली कार्रवाइयों की वजह से, वर्कर थ्रेड में देरी हो रही हो.

खराब डाइनैमिक एक्ज़ीक्यूशन परफ़ॉर्मेंस के साथ डेटा की प्रोफ़ाइल बनाना

ऊपर दी गई प्रोफ़ाइल में, 8 Javac वर्कर इस्तेमाल किए जाते हैं. इसमें हमें दिखता है कि कई Javac वर्कर, रेस हार गए हैं और async-worker-finish थ्रेड पर अपना काम पूरा कर रहे हैं. इसकी वजह यह थी कि उनके काम को किसी की याद में न कराने वाला व्यक्ति, कामगारों को देरी से ले जाने के लिए ज़रूरी संसाधन ले लेता था.

बेहतर डाइनैमिक एक्ज़ीक्यूशन परफ़ॉर्मेंस के साथ डेटा की प्रोफ़ाइल बनाना

जब सिर्फ़ Javac को डाइनैमिक एक्ज़ीक्यूशन के साथ चलाया जाता है, तो शुरू किए गए सिर्फ़ आधे कर्मचारी ही अपना काम शुरू करने के बाद रेस में हार जाते हैं.

पहले सुझाया गया --experimental_spawn_scheduler फ़्लैग अब काम नहीं करता. यह डाइनैमिक एक्ज़ीक्यूशन को चालू करता है और dynamic को सभी याददाश्त के लिए डिफ़ॉल्ट रणनीति के तौर पर सेट करता है. इस वजह से अक्सर इस तरह की समस्याएं हो सकती हैं.

समस्या हल करना

डाइनैमिक एक्ज़ीक्यूशन की समस्याओं को डीबग करना आसान और मुश्किल हो सकता है, क्योंकि ये स्थानीय और रिमोट एक्ज़ीक्यूशन के कुछ खास कॉम्बिनेशन के तहत ही दिख सकती हैं. --debug_spawn_scheduler, डाइनैमिक एक्ज़ीक्यूशन सिस्टम से अतिरिक्त आउटपुट जोड़ता है जो इन समस्याओं को डीबग करने में मदद कर सकता है. समस्याओं को आसानी से हल करने के लिए, --local_execution_delay फ़्लैग और रिमोट बनाम लोकल जॉब की संख्या में भी बदलाव किया जा सकता है.

अगर आपको standalone रणनीति का इस्तेमाल करके, डाइनैमिक एक्ज़ीक्यूशन में समस्या आ रही है, तो --experimental_local_lockfree_output के बिना चलाएं या सैंडबॉक्स किए गए अपने लोकल ऐक्शन चलाएं. इससे आपके बिल्ड की प्रोसेस थोड़ी धीमी हो सकती है (अगर आप Mac या Windows का इस्तेमाल कर रहे हैं, तो ऊपर देखें), लेकिन यह काम न करने की कुछ संभावित वजहों को हटा देता है.