बिल्ड परफ़ॉर्मेंस का विश्लेषण

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

क्लीन बिल्ड बनाम इंक्रीमेंटल बिल्ड

क्लीन बिल्ड में, सब कुछ शुरुआत से बनाया जाता है. वहीं, इंक्रीमेंटल बिल्ड में, पहले से पूरा किए गए कुछ काम को फिर से इस्तेमाल किया जाता है.

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

बिल्ड को कैटगरी में बांटने के लिए, BEP में CumulativeMetrics.num_analyses फ़ील्ड का इस्तेमाल किया जा सकता है. अगर num_analyses <= 1 है, तो यह क्लीन बिल्ड है. इसके अलावा, इसे मोटे तौर पर इंक्रीमेंटल बिल्ड के तौर पर कैटगरी में बांटा जा सकता है. ऐसा इसलिए, क्योंकि हो सकता है कि उपयोगकर्ता ने अलग-अलग फ़्लैग या अलग-अलग टारगेट पर स्विच किया हो. इससे, बिल्ड असल में क्लीन बिल्ड बन गया हो. इंक्रीमेंटल बिल्ड की ज़्यादा सटीक परिभाषा, अनुमान के तौर पर दी जा सकती है. उदाहरण के लिए, लोड किए गए पैकेज की संख्या (PackageMetrics.packages_loaded) देखना.

बिल्ड की परफ़ॉर्मेंस के लिए, डिटरमिनिस्टिक बिल्ड मेट्रिक का इस्तेमाल करना

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

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

हम इस समस्या को बिल्ड के अलग-अलग चरणों में बांट सकते हैं. साथ ही, हर चरण में किए गए काम के लिए, इन मेट्रिक का इस्तेमाल प्रॉक्सी मेट्रिक के तौर पर कर सकते हैं:

  1. PackageMetrics.packages_loaded: लोड किए गए पैकेज की संख्या. अगर यहां कोई समस्या होती है, तो इसका मतलब है कि लोडिंग के चरण में, हर अतिरिक्त BUILD फ़ाइल को पढ़ने और पार्स करने के लिए ज़्यादा काम करना होगा.

    • ऐसा अक्सर डिपेंडेंसी जोड़ने और उनके ट्रांज़िटिव क्लोज़र को लोड करने की वजह से होता है.
    • यह पता करने के लिए कि नई डिपेंडेंसी कहां जोड़ी गई हैं, क्वेरी / cquery का इस्तेमाल करें.
  2. TargetMetrics.targets_configured: बिल्ड में कॉन्फ़िगर किए गए टारगेट और पहलुओं की संख्या. अगर यहां कोई समस्या होती है, तो इसका मतलब है कि कॉन्फ़िगर किए गए टारगेट ग्राफ़ को बनाने और ट्रैवर्स करने में ज़्यादा काम करना होगा.

    • ऐसा अक्सर डिपेंडेंसी जोड़ने और उनके ट्रांज़िटिव क्लोज़र का ग्राफ़ बनाने की वजह से होता है.
    • यह पता करने के लिए कि नई डिपेंडेंसी कहां जोड़ी गई हैं, cqueryका इस्तेमाल करें.
  3. ActionSummary.actions_created: बिल्ड में बनाई गई कार्रवाइयां. अगर यहां कोई समस्या होती है, तो इसका मतलब है कि कार्रवाई का ग्राफ़ बनाने में ज़्यादा काम करना होगा. ध्यान दें कि इसमें ऐसी कार्रवाइयां भी शामिल हैं जिनका इस्तेमाल नहीं किया गया है और जिन्हें शायद एक्ज़ीक्यूट न किया गया हो.

    • समस्याओं को डीबग करने के लिए, aquery का इस्तेमाल करें; हमारा सुझाव है कि --skyframe_state का इस्तेमाल करके ज़्यादा जानकारी पाने से पहले, --output=summary से शुरुआत करें.
  4. ActionSummary.actions_executed: एक्ज़ीक्यूट की गई कार्रवाइयों की संख्या. अगर यहां कोई समस्या होती है, तो इसका मतलब है कि इन कार्रवाइयों को एक्ज़ीक्यूट करने में ज़्यादा काम करना होगा.

    • BEP, कार्रवाई के आंकड़े ActionData दिखाता है. इससे पता चलता है कि सबसे ज़्यादा बार किस तरह की कार्रवाइयां एक्ज़ीक्यूट की गई हैं. डिफ़ॉल्ट रूप से, यह सबसे ज़्यादा बार एक्ज़ीक्यूट की गई 20 तरह की कार्रवाइयों का डेटा इकट्ठा करता है. हालांकि, --experimental_record_metrics_for_all_mnemonics पास करके, एक्ज़ीक्यूट की गई सभी तरह की कार्रवाइयों का डेटा इकट्ठा किया जा सकता है.
    • इससे आपको यह पता करने में मदद मिलेगी कि किस तरह की कार्रवाइयां (अतिरिक्त तौर पर) एक्ज़ीक्यूट की गई हैं.
  5. BuildGraphSummary.outputArtifactCount: एक्ज़ीक्यूट की गई कार्रवाइयों से बनाए गए आर्टफ़ैक्ट की संख्या.

    • अगर एक्ज़ीक्यूट की गई कार्रवाइयों की संख्या नहीं बढ़ी है, तो इसका मतलब है कि नियम के लागू होने में बदलाव किया गया है.

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

हमने देखा है कि इनमें से किसी भी मेट्रिक में समस्या होने पर, वॉल टाइम, सीपीयू समय, और मेमोरी के इस्तेमाल में भी समस्याएं हो सकती हैं.

लोकल संसाधनों का इस्तेमाल

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

बिताया गया समय

शायद, समय ऐसी मेट्रिक है जिस पर शोर का सबसे ज़्यादा असर पड़ता है. साथ ही, यह बिल्ड के हिसाब से अलग-अलग हो सकती है. खास तौर पर, वॉल टाइम, सीपीयू समय, और सिस्टम टाइम. इन मेट्रिक के लिए बेंचमार्क पाने के लिए, bazel-bench का इस्तेमाल किया जा सकता है. साथ ही, --runs की संख्या बढ़ाकर, मेज़रमेंट की सांख्यिकीय अहमियत को बढ़ाया जा सकता है.

  • वॉल टाइम का मतलब है, असल में बीता हुआ समय.

    • अगर सिर्फ़ वॉल टाइम में समस्या होती है, तो हमारा सुझाव है कि JSON ट्रेस प्रोफ़ाइल इकट्ठा करें और अंतर देखें. इसके अलावा, समस्याओं वाली अन्य मेट्रिक की जांच करना ज़्यादा कारगर हो सकता है, क्योंकि इनसे वॉल टाइम पर असर पड़ सकता है.
  • सीपीयू समय का मतलब है, सीपीयू ने उपयोगकर्ता के कोड को एक्ज़ीक्यूट करने में जितना समय बिताया.

    • अगर दो प्रोजेक्ट कमिट के बीच, सीपीयू समय में समस्या होती है, तो हमारा सुझाव है कि Starlark सीपीयू प्रोफ़ाइल इकट्ठा करें. आपको शायद --nobuild का इस्तेमाल भी करना चाहिए, ताकि बिल्ड को सिर्फ़ विश्लेषण के चरण तक सीमित किया जा सके. ऐसा इसलिए, क्योंकि सीपीयू पर ज़्यादा लोड डालने वाला ज़्यादातर काम इसी चरण में होता है.
  • सिस्टम टाइम का मतलब है, सीपीयू ने कर्नल में जितना समय बिताया.

    • अगर सिस्टम टाइम में समस्या होती है, तो यह ज़्यादातर I/O से जुड़ा होता है. ऐसा तब होता है, जब Bazel आपकी फ़ाइल सिस्टम से फ़ाइलें पढ़ता है.

सिस्टम-वाइड लोड प्रोफ़ाइलिंग

Bazel 6.0 में जोड़े गए --experimental_collect_load_average_in_profiler फ़्लैग का इस्तेमाल करके, JSON ट्रेस प्रोफ़ाइलर, इनवोकेशन के दौरान सिस्टम लोड का औसत इकट्ठा करता है.

ऐसी प्रोफ़ाइल जिसमें सिस्टम लोड का औसत शामिल हो

पहली इमेज. ऐसी प्रोफ़ाइल जिसमें सिस्टम लोड का औसत शामिल है.

Bazel इनवोकेशन के दौरान ज़्यादा लोड होने का मतलब है कि Bazel, आपकी मशीन के लिए, समानांतर में बहुत ज़्यादा लोकल कार्रवाइयां शेड्यूल करता है. आपको अडजस्ट करने के बारे में सोचना चाहिए --local_cpu_resources और --local_ram_resources. खास तौर पर, कंटेनर एनवायरमेंट में. कम से कम तब तक, जब तक #16512 को मर्ज नहीं किया जाता.

Bazel के मेमोरी के इस्तेमाल की निगरानी करना

Bazel के मेमोरी के इस्तेमाल की जानकारी पाने के दो मुख्य सोर्स हैं: Bazel info और the BEP.

  • bazel info used-heap-size-after-gc: System.gc() को कॉल करने के बाद, इस्तेमाल की गई मेमोरी की मात्रा (बाइट में).

    • Bazel bench इस मेट्रिक के लिए बेंचमार्क भी उपलब्ध कराता है.
    • इसके अलावा, peak-heap-size, max-heap-size, used-heap-size और committed-heap-size भी उपलब्ध हैं. ज़्यादा जानकारी के लिए, दस्तावेज़ देखें. हालांकि, ये कम काम के हैं.
  • BEP का MemoryMetrics.peak_post_gc_heap_size: GC के बाद, पीक JVM हीप साइज़ की मात्रा (बाइट में). इसके लिए, --memory_profile सेट करना ज़रूरी है. इससे, पूरा GC करने की कोशिश की जाती है.

मेमोरी के इस्तेमाल में समस्या होने की वजह आम तौर पर, बिल्ड के अनुरोध के साइज़ की मेट्रिक में समस्या होती है. ऐसा अक्सर डिपेंडेंसी जोड़ने या नियम के लागू होने में बदलाव करने की वजह से होता है.

Bazel के मेमोरी फ़ुटप्रिंट का ज़्यादा बारीकी से विश्लेषण करने के लिए, हमारा सुझाव है कि नियमों के लिए, बिल्ट-इन मेमोरी प्रोफ़ाइलर का इस्तेमाल करें.

पर्सिस्टेंट वर्कर की मेमोरी प्रोफ़ाइलिंग

हालांकि, लगातार काम करने वाले वर्कर बिल्ड की स्पीड को काफ़ी हद तक बढ़ा सकते हैं. खास तौर पर, इंटरप्रेट की गई भाषाओं के लिए. हालांकि, इनकी मेमोरी फ़ुटप्रिंट में समस्याएं हो सकती हैं. Bazel, अपने वर्कर की मेट्रिक इकट्ठा करता है. खास तौर पर, WorkerMetrics.WorkerStats.worker_memory_in_kb फ़ील्ड से पता चलता है कि वर्कर, नेमोनिक के हिसाब से कितनी मेमोरी इस्तेमाल करते हैं.

JSON ट्रेस प्रोफ़ाइलर इनवोकेशन के दौरान पर्सिस्टेंट वर्कर की मेमोरी के इस्तेमाल की जानकारी भी इकट्ठा करता है. इसके लिए, --experimental_collect_system_network_usage फ़्लैग (Bazel 6.0 में नया) पास करना होता है.

ऐसी प्रोफ़ाइल जिसमें वर्कर के मेमोरी इस्तेमाल करने की जानकारी शामिल हो

दूसरी इमेज. ऐसी प्रोफ़ाइल जिसमें वर्कर की मेमोरी के इस्तेमाल की जानकारी शामिल है.

--worker_max_instances की वैल्यू (डिफ़ॉल्ट 4) कम करने से, पर्सिस्टेंट वर्कर के इस्तेमाल की जाने वाली मेमोरी की मात्रा को कम करने में मदद मिल सकती है. हम Bazel के रिसॉर्स मैनेजर और शेड्यूलर को बेहतर बनाने के लिए काम कर रहे हैं, ताकि आने वाले समय में इस तरह की फ़ाइन ट्यूनिंग की ज़रूरत कम पड़े.

रिमोट बिल्ड के लिए नेटवर्क ट्रैफ़िक की निगरानी करना

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

अगर अपने बिल्ड के लिए रिमोट एक्ज़ीक्यूशन का इस्तेमाल किया जा रहा है, तो BEP से NetworkMetrics.SystemNetworkStats प्रोटो का इस्तेमाल करके, इनवोकेशन के दौरान नेटवर्क ट्रैफ़िक की निगरानी की जा सकती है. इसके लिए, --experimental_collect_system_network_usage पास करना ज़रूरी है.

इसके अलावा, JSON ट्रेस प्रोफ़ाइल की मदद से, बिल्ड के दौरान सिस्टम-वाइड नेटवर्क के इस्तेमाल की जानकारी देखी जा सकती है. इसके लिए, --experimental_collect_system_network_usage फ़्लैग (Bazel 6.0 में नया) पास करना होता है.

ऐसी प्रोफ़ाइल जिसमें पूरे सिस्टम में नेटवर्क के इस्तेमाल की जानकारी शामिल हो

तीसरी इमेज. ऐसी प्रोफ़ाइल जिसमें सिस्टम-वाइड नेटवर्क के इस्तेमाल की जानकारी शामिल है.

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

डाउनलोड बैंडविड्थ बचाने के लिए, लोकल डिस्क कैश को कॉन्फ़िगर करने का भी विकल्प है.