डाइनैमिक एक्सीक्यूशन Bazel की एक सुविधा है जो वर्शन 0.21 से उपलब्ध है. इसमें, एक ही ऐक्शन को लोकल और रिमोट, दोनों तरह से एक साथ चलाया जाता है. इसके लिए, पहले पूरा होने वाले ब्रांच का आउटपुट इस्तेमाल किया जाता है और दूसरे ब्रांच को रद्द कर दिया जाता है. यह सुविधा, रिमोट बिल्ड सिस्टम की एक्सीक्यूशन पावर और/या बड़े शेयर किए गए कैश मेमोरी को, लोकल एक्सीक्यूशन की कम लेटेन्सी के साथ जोड़ती है. इससे, साफ़ और इंक्रीमेंटल, दोनों तरह के बिल्ड के लिए बेहतर परफ़ॉर्मेंस मिलती है.
इस पेज पर, डाइनैमिक एक्सीक्यूशन को चालू, ट्यून, और डीबग करने का तरीका बताया गया है. अगर आपने लोकल और रिमोट, दोनों तरह के एक्सीक्यूशन सेट अप किए हैं और बेहतर परफ़ॉर्मेंस के लिए 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 नेमोनिक के लिए डिफ़ॉल्ट सेटिंग बदल जाती है. रिमोट वर्शन भी इसी तरह काम करता है. दोनों फ़्लैग को एक से ज़्यादा बार तय किया जा सकता है. अगर कोई ऐक्शन लोकल तौर पर नहीं चलाया जा सकता, तो उसे सामान्य तरीके से रिमोट तौर पर चलाया जाता है. इसके उलट भी ऐसा ही होता है.
अगर आपके रिमोट सिस्टम में कैश मेमोरी है, तो --local_execution_delay फ़्लैग, रिमोट सिस्टम के कैश मेमोरी हिट होने का संकेत देने के बाद, लोकल एक्सीक्यूशन में मिलीसेकंड में देरी जोड़ता है. इससे, कैश मेमोरी हिट होने की ज़्यादा संभावना होने पर, लोकल एक्सीक्यूशन नहीं चलाया जाता. डिफ़ॉल्ट वैल्यू 1000 मिसेकंड होती है. हालांकि, इसे कैश मेमोरी हिट होने में लगने वाले समय से थोड़ा ज़्यादा होना चाहिए. असल समय, रिमोट सिस्टम और राउंड-ट्रिप में लगने वाले समय, दोनों पर निर्भर करता है. आम तौर पर, किसी दिए गए रिमोट सिस्टम के सभी उपयोगकर्ताओं के लिए वैल्यू एक ही होगी. हालांकि, अगर कुछ उपयोगकर्ता इतनी दूरी पर हैं कि राउंडट्रिप लेटेन्सी जुड़ जाए, तो वैल्यू अलग हो सकती है. आम तौर पर, कैश मेमोरी हिट होने में कितना समय लगता है, यह देखने के लिए
Bazel की प्रोफ़ाइलिंग सुविधाओं
का इस्तेमाल किया जा सकता है.
डाइनैमिक एक्सीक्यूशन का इस्तेमाल, लोकल सैंडबॉक्स वाली रणनीति के साथ-साथ
पर्सिस्टेंट वर्कर के साथ भी किया जा सकता है. डाइनैमिक एक्सीक्यूशन के साथ इस्तेमाल करने पर, पर्सिस्टेंट वर्कर अपने-आप सैंडबॉक्सिंग के साथ चलेंगे. साथ ही, वे
मल्टीप्लेक्स वर्कर का इस्तेमाल नहीं कर सकते.
Darwin और Windows सिस्टम पर, सैंडबॉक्स वाली रणनीति धीमी हो सकती है. इन सिस्टम पर सैंडबॉक्स बनाने का ओवरहेड कम करने के लिए, --reuse_sandbox_directories पास किया जा सकता है.
डाइनैमिक एक्सीक्यूशन को standalone रणनीति के साथ भी चलाया जा सकता है. हालांकि, standalone रणनीति को एक्सीक्यूशन शुरू करते समय, आउटपुट लॉक लेना होता है. इसलिए, यह रिमोट रणनीति को पहले पूरा होने से रोकती है. --experimental_local_lockfree_output फ़्लैग, इस समस्या से बचने का एक तरीका उपलब्ध कराता है. इससे, लोकल एक्सीक्यूशन सीधे आउटपुट में लिख सकता है. हालांकि, अगर रिमोट एक्सीक्यूशन पहले पूरा होता है, तो उसे रद्द कर दिया जाता है.
अगर डाइनैमिक एक्सीक्यूशन के ब्रांच में से कोई एक पहले पूरा होता है, लेकिन वह फ़ेल हो जाता है, तो पूरा ऐक्शन फ़ेल हो जाता है. यह जान-बूझकर किया गया है, ताकि लोकल और रिमोट एक्सीक्यूशन के बीच के अंतर को नज़रअंदाज़ न किया जा सके.
डाइनैमिक एक्सीक्यूशन और उसके लॉकिंग के काम करने के तरीके के बारे में ज़्यादा जानने के लिए, Julio Merino's बेहतरीन ब्लॉग पोस्ट देखें
मुझे डाइनैमिक एक्सीक्यूशन का इस्तेमाल कब करना चाहिए?
डाइनैमिक एक्सीक्यूशन के लिए, किसी तरह के रिमोट एक्सीक्यूशन सिस्टम की ज़रूरत होती है. फ़िलहाल, सिर्फ़ कैश मेमोरी वाले रिमोट सिस्टम का इस्तेमाल नहीं किया जा सकता. ऐसा इसलिए, क्योंकि कैश मेमोरी मिस होने को फ़ेल हुआ ऐक्शन माना जाएगा.
सभी तरह के ऐक्शन, रिमोट एक्सीक्यूशन के लिए सही नहीं होते. सबसे सही उम्मीदवार वे हैं जो लोकल तौर पर तेज़ी से काम करते हैं. जैसे, पर्सिस्टेंट वर्कर का इस्तेमाल करने वाले ऐक्शन. इसके अलावा, वे ऐक्शन भी सही उम्मीदवार हैं जो इतनी तेज़ी से काम करते हैं कि रिमोट एक्सीक्यूशन का ओवरहेड, एक्सीक्यूशन के समय पर हावी हो जाता है. लोकल तौर पर चलाए गए हर ऐक्शन से, सीपीयू और मेमोरी के कुछ संसाधन लॉक हो जाते हैं. इसलिए, उन कैटगरी में न आने वाले ऐक्शन को चलाने से, उन कैटगरी में आने वाले ऐक्शन के एक्सीक्यूशन में देरी होती है.
वर्शन
5.0.0-pre.20210708.4के बाद,
परफ़ॉर्मेंस प्रोफ़ाइलिंग
में वर्कर एक्सीक्यूशन के बारे में डेटा शामिल होता है. इसमें, डाइनैमिक एक्सीक्यूशन रेस हारने के बाद, काम के
अनुरोध को पूरा करने में लगने वाला समय भी शामिल होता है. अगर आपको दिखता है कि डाइनैमिक एक्सीक्यूशन वर्कर थ्रेड, संसाधन हासिल करने में ज़्यादा समय ले रहे हैं या async-worker-finish में ज़्यादा समय ले रहे हैं, तो हो सकता है कि आपके पास कुछ ऐसे लोकल ऐक्शन हों जो वर्कर थ्रेड में देरी कर रहे हों.
ऊपर दी गई प्रोफ़ाइल में, आठ Javac वर्कर का इस्तेमाल किया गया है. इसमें, हमें कई Javac वर्कर रेस हारते हुए और async-worker-finish थ्रेड पर अपना काम पूरा करते हुए दिखते हैं. ऐसा इसलिए हुआ, क्योंकि वर्कर के अलावा किसी दूसरे नेमोनिक ने वर्कर में देरी करने के लिए, ज़रूरत से ज़्यादा संसाधन ले लिए थे.
जब सिर्फ़ Javac को डाइनैमिक एक्सीक्यूशन के साथ चलाया जाता है, तो काम शुरू करने के बाद, शुरू किए गए वर्कर में से सिर्फ़ आधे ही रेस हारते हैं.
पहले सुझाया गया --experimental_spawn_scheduler फ़्लैग, अब काम नहीं करता.
इससे डाइनैमिक एक्सीक्यूशन चालू हो जाता है और सभी नेमोनिक के लिए डिफ़ॉल्ट रणनीति के तौर पर dynamic सेट हो जाती है. इससे अक्सर इस तरह की समस्याएं होती थीं.
समस्या का हल
डाइनैमिक एक्सीक्यूशन से जुड़ी समस्याएं, बहुत कम और डीबग करने में मुश्किल हो सकती हैं. ऐसा इसलिए, क्योंकि ये समस्याएं, लोकल और रिमोट एक्सीक्यूशन के कुछ खास कॉम्बिनेशन में ही दिख सकती हैं.
--debug_spawn_scheduler फ़्लैग, डाइनैमिक एक्सीक्यूशन सिस्टम से अतिरिक्त आउटपुट जोड़ता है. इससे इन समस्याओं को डीबग करने में मदद मिल सकती है. समस्याओं को आसानी से दोहराने के लिए, --local_execution_delay फ़्लैग और रिमोट बनाम लोकल जॉब की संख्या में भी बदलाव किया जा सकता है.
अगर आपको standalone रणनीति का इस्तेमाल करके, डाइनैमिक एक्सीक्यूशन में समस्याएं आ रही हैं, तो --experimental_local_lockfree_output के बिना चलाएं या अपने लोकल ऐक्शन को सैंडबॉक्स में चलाएं. इससे आपके बिल्ड की स्पीड थोड़ी कम हो सकती है (अगर आपके पास Mac या Windows है, तो ऊपर देखें). हालांकि, इससे फ़ेल होने की कुछ संभावित वजहें खत्म हो जाती हैं.