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

समस्या की शिकायत करें सोर्स देखें

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

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

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

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

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

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

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

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

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

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

    • ऐसा अक्सर डिपेंडेंसी जुड़ने और उनके ट्रांज़िकटिव क्लोज़र को लोड करने की वजह से होता है.
    • query / 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 ट्रेस प्रोफ़ाइल इकट्ठा करें और अंतर ढूंढें. ऐसा न करने पर, अन्य मेट्रिक की जांच करना ज़्यादा असरदार हो सकता है, क्योंकि उनसे वॉल टाइम पर असर पड़ सकता है.
  • सीपीयू समय, वह समय है जो सीपीयू (CPU) की ओर से उपयोगकर्ता कोड को लागू करने में लगता है.

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

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

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

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

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

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

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

Bazel मेमोरी के इस्तेमाल पर नज़र रखना

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

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

    • Bazel बेंच इस मेट्रिक के लिए भी मानदंड मुहैया कराता है.
    • इसके अलावा, इनमें 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 फ़ील्ड से यह पता चलता है कि Memonic की मदद से वर्कर कितनी मेमोरी इस्तेमाल करते हैं.

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

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

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

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

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

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

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

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

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

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

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

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