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

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

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

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

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

बिल्ड को कैटगरी में बांटने के लिए, बीईपी में 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: चलाई गई कार्रवाइयों की संख्या दिखाता है. गिरावट का मतलब है कि इन कार्रवाइयों को चलाने में ज़्यादा काम करना पड़ता है.

    • बीईपी, कार्रवाई के आंकड़े 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 और बीईपी.

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

    • Bazel bench इस मेट्रिक के लिए बेंचमार्क भी उपलब्ध कराता है.
    • इसके अलावा, peak-heap-size, max-heap-size, used-heap-size और committed-heap-size भी उपलब्ध हैं (दस्तावेज़ देखें). हालांकि, ये कम काम की हैं.
  • बीईपी का 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 प्रोटो का इस्तेमाल करें. इसके लिए, बीईपी से --experimental_collect_system_network_usage पास करना ज़रूरी है.

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

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

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

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

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