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

समस्या की शिकायत करें स्रोत देखें

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

इस पेज पर, डाइनैमिक एक्ज़ीक्यूशन को चालू करने, ट्यून करने, और डीबग करने का तरीका बताया गया है. अगर आपने लोकल और रिमोट, दोनों फ़ॉर्मैट में एक्ज़ीक्यूशन सेट अप किया है और आपको बेहतर परफ़ॉर्मेंस के लिए 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 मेनेमोनिक के लिए डिफ़ॉल्ट सेटिंग लागू होती है. रिमोट वर्शन भी इसी तरह से काम करता है. दोनों फ़्लैग एक से ज़्यादा बार तय किए जा सकते हैं. अगर कोई कार्रवाई स्थानीय रूप से नहीं की जा सकती, तो उसे सामान्य तरीके से रिमोट तरीके से किया जाता है. इसी तरह, अगर कोई कार्रवाई स्थानीय तौर पर नहीं की जा सकती है, तो उसे किसी दूसरी जगह से भी किया जाता है.

अगर आपके रिमोट सिस्टम में कैश मेमोरी है, तो --dynamic_local_execution_delay फ़्लैग, रिमोट सिस्टम से कैश हिट का संकेत मिलने के बाद लोकल एक्ज़ीक्यूशन में मिलीसेकंड में देरी जोड़ देता है. इससे, कैश मेमोरी के ज़्यादा हिट मिलने की संभावना होने पर, लोकल एक्ज़ीक्यूशन नहीं चलाया जाता. डिफ़ॉल्ट मान 1000ms है, लेकिन आम तौर पर कैश हिट से ज़्यादा समय लगता है. असल समय, रिमोट सिस्टम पर और दोतरफ़ा यात्रा में लगने वाला समय, दोनों पर निर्भर करता है. आम तौर पर, किसी भी रिमोट सिस्टम के सभी उपयोगकर्ताओं के लिए वैल्यू एक जैसी रहेगी. हालांकि, ऐसा तब तक होगा, जब तक दोनों सिस्टम में दोतरफ़ा यात्रा का समय बढ़ाने के लिए काफ़ी दूर न हो. 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 को सभी याददाश्त के लिए डिफ़ॉल्ट रणनीति के तौर पर सेट करता है. इस वजह से अक्सर इस तरह की समस्याएं हो सकती हैं.

परफ़ॉर्मेंस

डाइनैमिक एक्ज़ीक्यूशन के इस तरीके को अपनाकर, यह माना जाता है कि स्थानीय और कहीं से भी ऐसे काफ़ी संसाधन उपलब्ध हैं कि परफ़ॉर्मेंस को बेहतर बनाने के लिए कुछ और संसाधन भी खर्च हो सकते हैं. हालांकि, संसाधनों का बहुत ज़्यादा इस्तेमाल करने से, 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 का इस्तेमाल कर रहे हैं, तो ऊपर देखें), लेकिन यह काम न करने की कुछ संभावित वजहों को हटा देता है.