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

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

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

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

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

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

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

बिल्ड की परफ़ॉर्मेंस को मेज़र करना मुश्किल हो सकता है, क्योंकि कुछ मेट्रिक डिटरमिनिस्टिक नहीं होती हैं. उदाहरण के लिए, 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: जीसी के बाद, पीक जेवीएम हीप साइज़ की मात्रा बाइट में. इसके लिए, --memory_profile सेट करना ज़रूरी है. इससे, पूरा जीसी करने की कोशिश की जाती है.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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