1. खास जानकारी
क्लाइंट ऐप्लिकेशन और फ़्रंटएंड वेब डेवलपर, अपने कोड की परफ़ॉर्मेंस को बेहतर बनाने के लिए, आम तौर पर Android Studio CPU Profiler या Chrome में शामिल प्रोफ़ाइलिंग टूल जैसे टूल का इस्तेमाल करते हैं. हालांकि, बैकएंड सेवाओं पर काम करने वाले लोगों के लिए, इस तरह की तकनीकें उतनी आसानी से उपलब्ध नहीं हैं और न ही वे इनका इस्तेमाल करते हैं. Cloud Profiler, सेवा डेवलपर को ये सुविधाएं देता है. इससे कोई फ़र्क़ नहीं पड़ता कि उनका कोड Google Cloud Platform पर चल रहा है या किसी और प्लैटफ़ॉर्म पर.

यह टूल, आपके प्रोडक्शन ऐप्लिकेशन से सीपीयू के इस्तेमाल और मेमोरी के बंटवारे की जानकारी इकट्ठा करता है. यह जानकारी को ऐप्लिकेशन के सोर्स कोड से जोड़ता है. इससे आपको यह पता चलता है कि ऐप्लिकेशन के कौनसे हिस्से सबसे ज़्यादा संसाधनों का इस्तेमाल कर रहे हैं. साथ ही, इससे कोड की परफ़ॉर्मेंस की विशेषताओं के बारे में भी पता चलता है. इस टूल में डेटा इकट्ठा करने की तकनीकों का इस्तेमाल कम होता है. इसलिए, इसे प्रोडक्शन एनवायरमेंट में लगातार इस्तेमाल किया जा सकता है.
इस कोडलैब में, आपको Go प्रोग्राम के लिए Cloud Profiler को सेट अप करने का तरीका बताया जाएगा. साथ ही, आपको यह भी पता चलेगा कि यह टूल, ऐप्लिकेशन की परफ़ॉर्मेंस के बारे में किस तरह की अहम जानकारी दे सकता है.
आपको क्या सीखने को मिलेगा
- Cloud Profiler की मदद से प्रोफ़ाइलिंग के लिए, Go प्रोग्राम को कॉन्फ़िगर करने का तरीका.
- Cloud Profiler की मदद से, परफ़ॉर्मेंस डेटा को इकट्ठा, देखा, और उसका विश्लेषण कैसे करें.
आपको इन चीज़ों की ज़रूरत होगी
- Google Cloud Platform प्रोजेक्ट
- कोई ब्राउज़र, जैसे कि Chrome या Firefox
- Vim, EMACs या Nano जैसे स्टैंडर्ड Linux टेक्स्ट एडिटर के बारे में जानकारी होना
इस ट्यूटोरियल का इस्तेमाल कैसे किया जाएगा?
Google Cloud Platform को इस्तेमाल करने के अपने अनुभव को आप क्या रेटिंग देंगे?
2. सेटअप और ज़रूरी शर्तें
अपने हिसाब से एनवायरमेंट सेट अप करना
- Cloud Console में साइन इन करें. इसके बाद, नया प्रोजेक्ट बनाएं या किसी मौजूदा प्रोजेक्ट का फिर से इस्तेमाल करें. अगर आपके पास पहले से कोई Gmail या Google Workspace खाता नहीं है, तो आपको एक खाता बनाना होगा.



प्रोजेक्ट आईडी याद रखें. यह सभी Google Cloud प्रोजेक्ट के लिए एक यूनीक नाम होता है. ऊपर दिया गया नाम पहले ही इस्तेमाल किया जा चुका है. इसलिए, यह आपके लिए काम नहीं करेगा. माफ़ करें! इस कोड लैब में इसे बाद में PROJECT_ID के तौर पर दिखाया जाएगा.
- इसके बाद, Google Cloud संसाधनों का इस्तेमाल करने के लिए, आपको Cloud Console में बिलिंग चालू करनी होगी.
इस कोडलैब को पूरा करने में ज़्यादा खर्च नहीं आएगा. "सफ़ाई करना" सेक्शन में दिए गए निर्देशों का पालन करना न भूलें. इसमें बताया गया है कि संसाधनों को कैसे बंद किया जाए, ताकि इस ट्यूटोरियल के बाद आपको बिलिंग न करनी पड़े. Google Cloud के नए उपयोगकर्ताओं को, मुफ़्त में आज़माने के लिए 300 डॉलर का क्रेडिट मिलता है.
Google Cloud Shell
Google Cloud को अपने लैपटॉप से रिमोटली ऐक्सेस किया जा सकता है. हालांकि, इस कोडलैब में सेटअप को आसान बनाने के लिए, हम Google Cloud Shell का इस्तेमाल करेंगे. यह क्लाउड में चलने वाला कमांड लाइन एनवायरमेंट है.
Cloud Shell चालू करें
- Cloud Console में, Cloud Shell चालू करें
पर क्लिक करें.

अगर आपने पहले कभी Cloud Shell का इस्तेमाल नहीं किया है, तो आपको एक इंटरमीडिएट स्क्रीन दिखेगी. इसमें Cloud Shell के बारे में जानकारी दी गई होगी. अगर ऐसा है, तो जारी रखें पर क्लिक करें. इसके बाद, आपको यह स्क्रीन कभी नहीं दिखेगी. एक बार दिखने वाली स्क्रीन ऐसी दिखती है:

Cloud Shell से कनेक्ट होने में कुछ ही सेकंड लगेंगे.

इस वर्चुअल मशीन में, डेवलपमेंट के लिए ज़रूरी सभी टूल पहले से मौजूद होते हैं. यह 5 जीबी की होम डायरेक्ट्री उपलब्ध कराता है और Google Cloud में चलता है. इससे नेटवर्क की परफ़ॉर्मेंस और पुष्टि करने की प्रोसेस बेहतर होती है. इस कोडलैब में ज़्यादातर काम, सिर्फ़ ब्राउज़र या Chromebook की मदद से किया जा सकता है.
Cloud Shell से कनेक्ट होने के बाद, आपको दिखेगा कि आपकी पुष्टि पहले ही हो चुकी है और प्रोजेक्ट को आपके प्रोजेक्ट आईडी पर पहले ही सेट कर दिया गया है.
- पुष्टि करें कि आपने Cloud Shell में पुष्टि कर ली है. इसके लिए, यह कमांड चलाएं:
gcloud auth list
कमांड आउटपुट
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- यह पुष्टि करने के लिए कि gcloud कमांड को आपके प्रोजेक्ट के बारे में पता है, Cloud Shell में यह कमांड चलाएं:
gcloud config list project
कमांड आउटपुट
[core] project = <PROJECT_ID>
अगर ऐसा नहीं है, तो इस कमांड का इस्तेमाल करके इसे सेट किया जा सकता है:
gcloud config set project <PROJECT_ID>
कमांड आउटपुट
Updated property [core/project].
3. Cloud Profiler पर जाएं
Cloud Console में, बाईं ओर मौजूद नेविगेशन बार में "Profiler" पर क्लिक करके, Profiler के यूज़र इंटरफ़ेस (यूआई) पर जाएं:

इसके अलावा, Cloud Console के खोज बार का इस्तेमाल करके, Profiler के यूज़र इंटरफ़ेस (यूआई) पर जाया जा सकता है: बस "Cloud Profiler" टाइप करें और खोज के नतीजों में मिला आइटम चुनें. दोनों ही मामलों में, आपको नीचे दिए गए उदाहरण की तरह, "दिखाने के लिए कोई डेटा नहीं है" मैसेज के साथ Profiler का यूज़र इंटरफ़ेस (यूआई) दिखेगा. प्रोजेक्ट नया है. इसलिए, इसमें अब तक कोई प्रोफ़ाइलिंग डेटा इकट्ठा नहीं किया गया है.

अब किसी आइटम की प्रोफ़ाइल बनाने का समय आ गया है!
4. मानदंड की प्रोफ़ाइल बनाना
हम एक सामान्य सिंथेटिक Go ऐप्लिकेशन का इस्तेमाल करेंगे. यह Github पर उपलब्ध है. Cloud Shell टर्मिनल में, यह कमांड चलाएं. यह टर्मिनल अब भी खुला होना चाहिए. साथ ही, Profiler के यूज़र इंटरफ़ेस (यूआई) में "दिखाने के लिए कोई डेटा नहीं है" मैसेज अब भी दिख रहा हो:
$ go get -u github.com/GoogleCloudPlatform/golang-samples/profiler/...
इसके बाद, ऐप्लिकेशन डायरेक्ट्री पर जाएं:
$ cd ~/gopath/src/github.com/GoogleCloudPlatform/golang-samples/profiler/hotapp
इस डायरेक्ट्री में "main.go" फ़ाइल मौजूद है. यह एक सिंथेटिक ऐप्लिकेशन है, जिसमें प्रोफ़ाइलिंग एजेंट चालू है:
main.go
...
import (
...
"cloud.google.com/go/profiler"
)
...
func main() {
err := profiler.Start(profiler.Config{
Service: "hotapp-service",
DebugLogging: true,
MutexProfiling: true,
})
if err != nil {
log.Fatalf("failed to start the profiler: %v", err)
}
...
}
प्रोफ़ाइलिंग एजेंट, डिफ़ॉल्ट रूप से सीपीयू, हीप, और थ्रेड प्रोफ़ाइल इकट्ठा करता है. यहां दिया गया कोड, म्यूटेक्स (इसे "कंटेंशन" भी कहा जाता है) प्रोफ़ाइलों को इकट्ठा करने की सुविधा चालू करता है.
अब प्रोग्राम चलाएं:
$ go run main.go
प्रोग्राम के चलने के दौरान, प्रोफ़ाइलिंग एजेंट, कॉन्फ़िगर किए गए पांच टाइप की प्रोफ़ाइलें समय-समय पर इकट्ठा करेगा. समय के साथ कलेक्शन को रैंडमाइज़ किया जाता है. हर टाइप के लिए, हर मिनट में एक प्रोफ़ाइल का औसत रेट होता है. इसलिए, हर टाइप को इकट्ठा करने में तीन मिनट तक लग सकते हैं. प्रोग्राम, प्रोफ़ाइल बनाने के समय आपको इसकी सूचना देता है. ऊपर दिए गए कॉन्फ़िगरेशन में, DebugLogging फ़्लैग की मदद से मैसेज चालू किए जाते हैं. ऐसा न करने पर, एजेंट साइलेंट मोड में काम करता है:
$ go run main.go 2018/03/28 15:10:24 profiler has started 2018/03/28 15:10:57 successfully created profile THREADS 2018/03/28 15:10:57 start uploading profile 2018/03/28 15:11:19 successfully created profile CONTENTION 2018/03/28 15:11:30 start uploading profile 2018/03/28 15:11:40 successfully created profile CPU 2018/03/28 15:11:51 start uploading profile 2018/03/28 15:11:53 successfully created profile CONTENTION 2018/03/28 15:12:03 start uploading profile 2018/03/28 15:12:04 successfully created profile HEAP 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:04 successfully created profile THREADS 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:25 successfully created profile HEAP 2018/03/28 15:12:25 start uploading profile 2018/03/28 15:12:37 successfully created profile CPU ...
पहली प्रोफ़ाइल इकट्ठा होने के बाद, यूज़र इंटरफ़ेस (यूआई) अपने-आप अपडेट हो जाएगा. इसके बाद, यह अपने-आप अपडेट नहीं होगा. इसलिए, नया डेटा देखने के लिए, आपको Profiler के यूज़र इंटरफ़ेस (यूआई) को मैन्युअल तरीके से रीफ़्रेश करना होगा. इसके लिए, टाइम इंटरवल पिकर में मौजूद 'अभी' बटन पर दो बार क्लिक करें:

यूज़र इंटरफ़ेस रीफ़्रेश होने के बाद, आपको कुछ ऐसा दिखेगा:

प्रोफ़ाइल टाइप चुनने वाले टूल में, पांच तरह की प्रोफ़ाइलें दिखती हैं:

आइए, अब हर तरह की प्रोफ़ाइल और यूज़र इंटरफ़ेस (यूआई) की कुछ अहम सुविधाओं की समीक्षा करें. इसके बाद, कुछ एक्सपेरिमेंट करें. इस चरण में, आपको Cloud Shell टर्मिनल की ज़रूरत नहीं है. इसलिए, CTRL-C दबाकर और "exit" टाइप करके इसे बंद किया जा सकता है.
5. प्रोफ़ाइलर डेटा का विश्लेषण करना
अब जब हमने कुछ डेटा इकट्ठा कर लिया है, तो आइए इस पर ज़्यादा बारीकी से नज़र डालें. हम एक सिंथेटिक ऐप्लिकेशन का इस्तेमाल कर रहे हैं. इसका सोर्स Github पर उपलब्ध है. यह ऐप्लिकेशन, प्रोडक्शन में परफ़ॉर्मेंस से जुड़ी अलग-अलग समस्याओं के बारे में बताता है.
सीपीयू का ज़्यादा इस्तेमाल करने वाला कोड
सीपीयू प्रोफ़ाइल का टाइप चुनें. यूज़र इंटरफ़ेस (यूआई) के लोड होने के बाद, आपको फ़्लेम ग्राफ़ में load फ़ंक्शन के लिए चार लीफ़ ब्लॉक दिखेंगे. ये सभी ब्लॉक, सीपीयू के इस्तेमाल के लिए ज़िम्मेदार होते हैं:

इस फ़ंक्शन को खास तौर पर, सीपीयू के ज़्यादा साइकल इस्तेमाल करने के लिए लिखा गया है. इसके लिए, यह फ़ंक्शन एक टाइट लूप चलाता है:
main.go
func load() {
for i := 0; i < (1 << 20); i++ {
}
}
इस फ़ंक्शन को busyloop() से चार कॉल पाथ के ज़रिए, परोक्ष रूप से कॉल किया जाता है: busyloop → {foo1, foo2} → {bar, baz} → load. फ़ंक्शन बॉक्स की चौड़ाई, कॉल पाथ की तुलनात्मक लागत दिखाती है. इस मामले में, चारों पाथ की लागत लगभग एक जैसी है. किसी प्रोग्राम में, आपको उन कॉल पाथ को ऑप्टिमाइज़ करने पर फ़ोकस करना चाहिए जो परफ़ॉर्मेंस के हिसाब से सबसे ज़्यादा अहम हैं. फ़्लेम ग्राफ़ में, ज़्यादा समय लेने वाले पाथ को बड़े बॉक्स के साथ विज़ुअली हाइलाइट किया जाता है. इससे इन पाथ की पहचान करना आसान हो जाता है.
डेटा को और बेहतर तरीके से दिखाने के लिए, प्रोफ़ाइल डेटा फ़िल्टर का इस्तेमाल किया जा सकता है. उदाहरण के लिए, "स्टैक दिखाएं" फ़िल्टर जोड़कर देखें. इसके लिए, फ़िल्टर स्ट्रिंग के तौर पर "baz" का इस्तेमाल करें. आपको नीचे दिए गए स्क्रीनशॉट जैसा कुछ दिखेगा. इसमें load() पर कॉल करने के चार रास्तों में से सिर्फ़ दो दिख रहे हैं. ये दोनों ऐसे पाथ हैं जो ऐसे फ़ंक्शन से होकर गुज़रते हैं जिनके नाम में "baz" स्ट्रिंग मौजूद है. इस तरह से फ़िल्टर करने की सुविधा तब काम आती है, जब आपको किसी बड़े प्रोग्राम के किसी उप-भाग पर फ़ोकस करना हो. उदाहरण के लिए, ऐसा इसलिए हो सकता है, क्योंकि आपके पास उसका सिर्फ़ एक हिस्सा है.

मेमोरी का ज़्यादा इस्तेमाल करने वाला कोड
अब "Heap" प्रोफ़ाइल टाइप पर स्विच करें. पक्का करें कि आपने पिछले एक्सपेरिमेंट में बनाए गए सभी फ़िल्टर हटा दिए हों. अब आपको एक फ़्लेम ग्राफ़ दिखेगा. इसमें allocImpl को alloc ने कॉल किया है. साथ ही, इसे ऐप्लिकेशन में मेमोरी का मुख्य इस्तेमाल करने वाले फ़ंक्शन के तौर पर दिखाया गया है:

फ़्लेम ग्राफ़ के ऊपर मौजूद खास जानकारी वाली टेबल से पता चलता है कि ऐप्लिकेशन में इस्तेमाल की गई कुल मेमोरी का औसत ~57.4 MiB है. इसमें से ज़्यादातर मेमोरी, allocImpl फ़ंक्शन ने इस्तेमाल की है. इस फ़ंक्शन को लागू करने के तरीके को देखते हुए, इसमें कोई हैरानी नहीं है:
main.go
func allocImpl() {
// Allocate 64 MiB in 64 KiB chunks
for i := 0; i < 64*16; i++ {
mem = append(mem, make([]byte, 64*1024))
}
}
यह फ़ंक्शन एक बार चलता है और 64 MiB को छोटे-छोटे हिस्सों में बांटता है. इसके बाद, उन हिस्सों के पॉइंटर को ग्लोबल वैरिएबल में सेव करता है, ताकि उन्हें गार्बेज कलेक्शन से बचाया जा सके. ध्यान दें कि प्रोफ़ाइलर के इस्तेमाल की गई मेमोरी की मात्रा, 64 MiB से थोड़ी अलग होती है: Go हीप प्रोफ़ाइलर एक स्टैटिस्टिकल टूल है. इसलिए, मेज़रमेंट में कम ओवरहेड होता है, लेकिन यह बाइट के हिसाब से सटीक नहीं होता. इस तरह का ~10% अंतर दिखने पर हैरान न हों.
IO-इंटेंसिव कोड
अगर प्रोफ़ाइल टाइप सिलेक्टर में "Threads" चुना जाता है, तो डिसप्ले फ़्लेम ग्राफ़ पर स्विच हो जाएगा. इसमें ज़्यादातर चौड़ाई wait और waitImpl फ़ंक्शन लेते हैं:

फ़्लेम ग्राफ़ के ऊपर मौजूद खास जानकारी में, यह देखा जा सकता है कि 100 गोरूटीन ऐसे हैं जिनका कॉल स्टैक, wait फ़ंक्शन से बढ़ता है. यह बिलकुल सही है, क्योंकि इन इंतज़ार को शुरू करने वाला कोड ऐसा दिखता है:
main.go
func main() {
...
// Simulate some waiting goroutines.
for i := 0; i < 100; i++ {
go wait()
}
इस प्रोफ़ाइल टाइप से यह समझने में मदद मिलती है कि प्रोग्राम, इंतज़ार में कितना समय बिताता है. जैसे, I/O. ऐसे कॉल स्टैक को आम तौर पर सीपीयू प्रोफ़ाइलर से सैंपल नहीं किया जाता, क्योंकि ये सीपीयू के समय का कोई खास हिस्सा इस्तेमाल नहीं करते. आपको अक्सर थ्रेड प्रोफ़ाइलों के साथ "स्टैक छिपाएं" फ़िल्टर का इस्तेमाल करना होगा. उदाहरण के लिए, gopark, को कॉल करने वाले सभी स्टैक को छिपाने के लिए, क्योंकि वे अक्सर आइडल गोरूटीन होते हैं और I/O पर इंतज़ार करने वाले स्टैक की तुलना में कम दिलचस्प होते हैं.
थ्रेड प्रोफ़ाइल टाइप से, प्रोग्राम में उन पॉइंट की पहचान करने में भी मदद मिल सकती है जहां थ्रेड, प्रोग्राम के किसी दूसरे हिस्से के मालिकाना हक वाले म्यूटेक्स के लिए लंबे समय तक इंतज़ार कर रही हैं. हालांकि, इसके लिए नीचे दिया गया प्रोफ़ाइल टाइप ज़्यादा फ़ायदेमंद है.
Contention-intensive Code
Contention प्रोफ़ाइल टाइप से, प्रोग्राम में सबसे ज़्यादा "ज़रूरी" लॉक की पहचान होती है. यह प्रोफ़ाइल टाइप, Go प्रोग्राम के लिए उपलब्ध है. हालांकि, इसे साफ़ तौर पर चालू करना होगा. इसके लिए, एजेंट कॉन्फ़िगरेशन कोड में "MutexProfiling: true" डालना होगा. यह कलेक्शन, "Contentions" मेट्रिक के तहत काम करता है. इसमें यह रिकॉर्ड किया जाता है कि किसी लॉक को goroutine A से अनलॉक करते समय, कितनी बार goroutine B को लॉक के अनलॉक होने का इंतज़ार करना पड़ा. यह "Delay" मेट्रिक के तहत, उस समय को भी रिकॉर्ड करता है जब ब्लॉक की गई goroutine ने लॉक के लिए इंतज़ार किया था. इस उदाहरण में, एक ही कंटेंशन स्टैक है और लॉक के लिए इंतज़ार करने का कुल समय 10.5 सेकंड था:

इस प्रोफ़ाइल को जनरेट करने वाले कोड में, चार गोरूटीन होते हैं. ये सभी एक म्यूटेक्स के लिए आपस में प्रतिस्पर्धा करते हैं:
main.go
func contention(d time.Duration) {
contentionImpl(d)
}
func contentionImpl(d time.Duration) {
for {
mu.Lock()
time.Sleep(d)
mu.Unlock()
}
}
...
func main() {
...
for i := 0; i < 4; i++ {
go contention(time.Duration(i) * 50 * time.Millisecond)
}
}
6. खास जानकारी
इस लैब में, आपने सीखा कि Cloud Profiler के साथ इस्तेमाल करने के लिए, Go प्रोग्राम को कैसे कॉन्फ़िगर किया जा सकता है. आपने यह भी सीखा कि इस टूल की मदद से, परफ़ॉर्मेंस डेटा को कैसे इकट्ठा किया जाता है, देखा जाता है, और उसका विश्लेषण किया जाता है. अब अपनी नई स्किल को, Google Cloud Platform पर चल रही सेवाओं पर लागू किया जा सकता है.
7. बधाई हो!
आपने Cloud Profiler को कॉन्फ़िगर करने और इस्तेमाल करने का तरीका जान लिया है!
ज़्यादा जानें
- Cloud Profiler: https://cloud.google.com/profiler/
- Go runtime/pprof पैकेज, जिसका इस्तेमाल Cloud Profiler करता है: https://golang.org/pkg/runtime/pprof/
लाइसेंस
इस काम के लिए, Creative Commons एट्रिब्यूशन 2.0 जेनेरिक लाइसेंस के तहत लाइसेंस मिला है.