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

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

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