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

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

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

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

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

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

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

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