about:tracing फ़्लैग के साथ अपने WebGL गेम की प्रोफ़ाइल बनाना

लिली थॉम्पसन
लिली थॉम्पसन

अगर आप इसे माप नहीं सकते, तो इसमें सुधार नहीं कर सकते.

लॉर्ड केल्विन

अपने HTML5 गेम को तेज़ी से चलाने के लिए, पहले आपको परफ़ॉर्मेंस में रुकावटों का पता लगाना होगा, लेकिन यह मुश्किल हो सकता है. फ़्रेम प्रति सेकंड (FPS) डेटा का मूल्यांकन करना एक शुरुआती प्रक्रिया है, लेकिन पूरी जानकारी देखने के लिए, आपको Chrome की गतिविधियों की बारीकियों को समझना होगा.

इसके बारे में:ट्रेसिंग टूल से आपको ऐसी अहम जानकारी मिलती है जिससे परफ़ॉर्मेंस को बेहतर बनाने के मकसद से, जल्द से जल्द समाधान खोजने में मदद मिलती है. हालांकि, यह सिर्फ़ ऐसे ही काम के लिए किया जाता है जिनके बारे में सोच-समझकर अनुमान लगाया जाता है. इससे आपका बहुत समय और ऊर्जा बचेगी, आपको इस बात की सटीक जानकारी मिलेगी कि Chrome हर फ़्रेम के साथ क्या कर रहा है, और इस जानकारी का इस्तेमाल अपने गेम को ऑप्टिमाइज़ करने के लिए करें.

ट्रेसिंग के बारे में नमस्ते

Chrome का about:tracing टूल, एक तय समय के दौरान Chrome की सभी गतिविधियों की जानकारी देता है. इसमें इतनी बारीकी से जानकारी दी जाती है कि पहली बार में आपको यह काफ़ी मुश्किल लग सकता है. Chrome के कई फ़ंक्शन बहुत अलग तरीके से ट्रेस करने के लिए तैयार किए गए हैं. इसलिए, बिना कोई मैन्युअल तरीके से किए भी परफ़ॉर्मेंस को ट्रैक करने के लिए, about:tracing का इस्तेमाल किया जा सकता है. (अपने JS को मैन्युअल तरीके से चलाने के बारे में बाद का सेक्शन देखें)

ट्रेसिंग व्यू देखने के लिए बस Chrome की खोज वाली पट्टी (पता बार) में "about:tracing" लिखें.

Chrome खोज बार
Chrome की खोज वाली पट्टी में "about:tracing" टाइप करें

ट्रेसिंग टूल की मदद से, रिकॉर्डिंग शुरू की जा सकती है, गेम को कुछ सेकंड तक चलाया जा सकता है, और फिर ट्रेस डेटा को देखा जा सकता है. यहां एक उदाहरण दिया गया है कि डेटा कैसा दिख सकता है:

ट्रेस करने का आसान नतीजा
ट्रेसिंग का आसान नतीजा

हां, इससे भ्रम की स्थिति पैदा होती है. चलिए, इसे पढ़ने के तरीके पर बात करते हैं.

हर लाइन, प्रोफ़ाइल करने वाली प्रोसेस को दिखाती है. बाईं ओर से दायां ऐक्सिस समय को दिखाता है, और हर रंग वाला बॉक्स, इंस्ट्रुमेंटेड फ़ंक्शन कॉल होता है. इसमें कई अलग-अलग तरह के संसाधनों के लिए लाइनें होती हैं. गेम प्रोफ़ाइलिंग के लिए जो सबसे दिलचस्प हैं वे हैं CrGpuMain, जो दिखाता है कि Graphics प्रोसेसिंग यूनिट (GPU) और CrRendererMain. क्या कर रहा है. ट्रेस पीरियड के दौरान, खुले हुए हर टैब के लिए हर ट्रेस में CrRendererMain लाइनें होती हैं (इसमें about:tracing टैब भी शामिल है).

ट्रेस डेटा पढ़ते समय आपका पहला काम यह तय करना है कि कौनसी CrRendererMain पंक्ति आपके गेम से जुड़ी है.

ट्रेस करने के आसान नतीजे को हाइलाइट किया गया
डेटा को ट्रेस करने के आसान नतीजे को हाइलाइट किया गया

इस उदाहरण में, ये दो उम्मीदवार हैं: 2216 और 6516. माफ़ करें, फ़िलहाल अपने ऐप्लिकेशन को चुनने का कोई बेहतर तरीका नहीं है. सिर्फ़ उस लाइन को ढूंढने का कोई तरीका है जिसमें समय-समय पर बहुत ज़्यादा अपडेट किए जा रहे हों (या अगर आपने मैन्युअल रूप से अपने कोड को ट्रेस पॉइंट के साथ जोड़ा है, तो उस लाइन को खोजें जिसमें आपका ट्रेस डेटा शामिल है). इस उदाहरण में, ऐसा लगता है कि अपडेट की फ़्रीक्वेंसी के हिसाब से, 6516 मुख्य लूप चला रहा है. अगर आप ट्रेस शुरू करने से पहले ही दूसरे सभी टैब बंद कर देते हैं, तो सही CrRendererManager का पता लगाना आसान हो जाएगा. हालांकि, आपके गेम के अलावा दूसरी प्रोसेस के लिए भी CrRendererMain की लाइनें हो सकती हैं.

फ़्रेम ढूंढना

अपने गेम के लिए ट्रेस करने वाले टूल में सही लाइन का पता लगाने के बाद, अगला चरण मुख्य लूप ढूंढना है. ट्रेसिंग डेटा में मुख्य लूप, दोहराए जाने वाले पैटर्न जैसा दिखता है. W, A, S, D बटन का इस्तेमाल करके, ट्रेस किए जा सकने वाले डेटा को नेविगेट किया जा सकता है: A और D बटन का इस्तेमाल करके डेटा को ज़ूम इन और ज़ूम आउट किया जा सकता है. ऐसा करने के लिए, W, A, S, और D बटन को बाईं या दाईं ओर ले जाया जाता है. अगर आपका गेम 60 हर्ट्ज़ पर चल रहा है, तो आपको मुख्य लूप ऐसा पैटर्न माना जाएगा जो हर 16 मिलीसेकंड में दोहराया जाएगा.

प्रोग्राम चलाने के तीन फ़्रेम की तरह लग रहा है
एक्ज़ीक्यूशन तीन फ़्रेम की तरह दिखता है

गेम की हार्टबीट का पता लगाने के बाद, यह पता लगाया जा सकता है कि हर फ़्रेम पर, आपका कोड असल में क्या कर रहा है. W, A, S, D का इस्तेमाल करके ज़ूम इन करें. ऐसा तब तक करें, जब तक फ़ंक्शन बॉक्स में मौजूद टेक्स्ट को पढ़ा न जा सके.

एक्ज़ीक्यूशन फ़्रेम में जाएं
एक्ज़ीक्यूशन फ़्रेम में जाएं

बॉक्स का यह कलेक्शन, फ़ंक्शन कॉल की सीरीज़ दिखाता है. हर कॉल को एक रंगीन बॉक्स के ज़रिए दिखाया जाता है. हर फ़ंक्शन को ऊपर दिए गए बॉक्स से कॉल किया गया था. इसलिए, इस मामले में आप देख सकते हैं कि MessageLoop::RunTask, RenderWidget::OnSwapBufferscomplete कहा जाता है. इसके हिसाब से, RenderWidget::DoDephraseUpdate वगैरह कहा जाता है. इस डेटा को पढ़कर, यह पता लगाया जा सकता है कि हर प्रोसेस को लागू करने में कितना समय लगा और किस तरह की गतिविधियां हुई.

हालांकि, यहां से थोड़ी स्टिकी हो जाती है. about:tracing के ज़रिए दिखाई गई जानकारी, Chrome सोर्स कोड के रॉ फ़ंक्शन कॉल है. नाम से यह अंदाज़ा लगाया जा सकता है कि हर फ़ंक्शन क्या कर रहा है, लेकिन यह जानकारी उपयोगकर्ता के लिए आसान नहीं है. फ़्रेम के पूरे फ़्लो को देखना मददगार होता है, लेकिन यह पता लगाने के लिए कि ऐसा क्या हो रहा है, आपको किसी ऐसी चीज़ की ज़रूरत है जिसे लोग आसानी से पढ़ सकें.

ट्रेस टैग जोड़ना

अच्छी बात यह है कि ट्रेस डेटा बनाने के लिए, अपने कोड में मैन्युअल इंस्ट्रुमेंटेशन जोड़ने का एक अच्छा तरीका दिया गया है: console.time और console.timeEnd.

console.time("update");
update();
console.timeEnd("update");
console.time("render");
update();
console.timeEnd("render");

ऊपर दिया गया कोड तय किए गए टैग के साथ ट्रेसिंग व्यू के नाम में नए बॉक्स बनाता है, इसलिए अगर आप ऐप्लिकेशन को फिर से चलाते हैं, तो आपको "अपडेट" और "रेंडर" बॉक्स दिखाई देंगे, जो हर टैग के लिए कॉल शुरू और खत्म करने के बीच बीता समय दिखाते हैं.

टैग मैन्युअल तौर पर जोड़े गए
मैन्युअल तरीके से टैग जोड़े गए

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

जीपीयू या सीपीयू?

हार्डवेयर एक्सेलरेटेड ग्राफ़िक के साथ, प्रोफ़ाइलिंग के दौरान आपसे सबसे अहम सवाल पूछे जाते हैं: क्या यह कोड जीपीयू बाउंड है या सीपीयू बाउंड है? हर फ़्रेम के साथ आपको रेंडरिंग का कुछ काम जीपीयू पर और कुछ लॉजिक को सीपीयू पर करना होगा. यह समझने के लिए कि आपके गेम की वजह क्यों धीमी है, आपको यह देखना होगा कि दोनों संसाधनों के बीच काम किस तरह से काम करता है.

सबसे पहले, CrGPUMain नाम की ट्रेसिंग व्यू पर लाइन ढूंढें. इससे पता चलता है कि जीपीयू किसी खास समय पर व्यस्त है या नहीं.

जीपीयू और सीपीयू ट्रेस

देखा जा सकता है कि आपके गेम के हर फ़्रेम की वजह से, CrRendererMain के साथ-साथ जीपीयू पर भी सीपीयू काम करता है. ऊपर दिया गया ट्रेस, इस्तेमाल का बहुत आसान उदाहरण दिखाता है. इसमें हर 16 मि॰से॰ के ज़्यादातर फ़्रेम में सीपीयू और जीपीयू का इस्तेमाल नहीं किया जाता.

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

console.time("update");
doExtraWork();
update(Math.min(50, now - time));
console.timeEnd("update");

console.time("render");
render();
console.timeEnd("render");

अब आपको ऐसा ट्रेस दिखेगा:

जीपीयू और सीपीयू ट्रेस

इस ट्रेस से हमें क्या पता चलता है? हम देख सकते हैं कि तस्वीर में दिखाया गया फ़्रेम 2270 मि॰से॰ से लेकर 2320 मि॰से॰ तक का है. इसका मतलब है कि हर फ़्रेम करीब 50 मि॰से॰ (20 हर्ट्ज़ का फ़्रेम रेट) ले रहा है. आपको अपडेट बॉक्स के बगल में, रंगीन बॉक्स के स्लिवर्स दिख सकते हैं. ये बॉक्स, रेंडर फ़ंक्शन को दिखाते हैं. हालांकि, अपडेट में ही फ़्रेम पूरी तरह से दिख रहा है.

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

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

#ifdef GL_ES
precision highp float;
#endif
void main(void) {
  for(int i=0; i<9999; i++) {
    gl_FragColor = vec4(1.0, 0, 0, 1.0);
  }
}

उस शेडर का इस्तेमाल करके बनाए गए कोड का ट्रेस कैसा दिखता है?

धीमे जीपीयू कोड का इस्तेमाल करते समय, जीपीयू और सीपीयू ट्रेस होते हैं
धीमे जीपीयू कोड का इस्तेमाल करने पर, जीपीयू और सीपीयू ट्रेस होते हैं

फिर से, फ़्रेम की अवधि नोट करें. यहां बार-बार होने वाला पैटर्न 2750 मि॰से॰ से लेकर 2950 मि॰से॰ तक, 200 मि॰से॰ (करीब 5 हर्ट्ज़ की फ़्रेम रेट) की अवधि तक जाता है. CrRendererMain लाइन पूरी तरह से खाली होती है. इसका मतलब है कि ज़्यादातर समय सीपीयू बंद रहता है, जबकि जीपीयू ओवरलोड होता है. यह इस बात का संकेत है कि आपके शेड बहुत भारी हैं.

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

असल उदाहरण

आइए, अब देखते हैं कि किसी असली गेम से ट्रेस किया जा रहा डेटा कैसा दिखता है. ओपन वेब तकनीकों के साथ बनाए गए गेम के बारे में सबसे बढ़िया चीज़ों में से एक यह है कि आप देख सकते हैं कि आपके पसंदीदा प्रॉडक्ट में क्या चल रहा है. अगर आपको प्रोफ़ाइल बनाने वाले टूल को आज़माना है, तो Chrome Web Store से अपना पसंदीदा WebGL शीर्षक चुनें और उसे about:tracing की मदद से प्रोफ़ाइल कर दें. यह एक उदाहरण है, जिसे WebGL गेम के शानदार स्किड रेसर गेम से लिया गया है.

असली गेम की जानकारी हासिल करना
किसी असली गेम को ट्रेस करना

ऐसा लगता है कि हर फ़्रेम को करीब 20 मि॰से॰ का समय लगता है. इसका मतलब है कि फ़्रेम रेट करीब 50 FPS (फ़्रेम प्रति सेकंड) है. आपके पास यह देखने का विकल्प है कि सीपीयू और जीपीयू के बीच संतुलन बना रहता है, लेकिन जीपीयू ही ऐसा संसाधन है जिसकी मांग सबसे ज़्यादा है. अगर आपको यह देखना है कि WebGL गेम के असली उदाहरणों को प्रोफ़ाइल बनाना कैसा है, तो WebGL के साथ बनाए गए कुछ Chrome Web Store टाइटल के साथ खेलने की कोशिश करें, जिनमें ये शामिल हैं:

नतीजा

अगर आपको अपना गेम 60 हर्ट्ज़ पर चलाना है, तो हर फ़्रेम के लिए आपकी सभी कार्रवाइयां 16 मि॰से॰ सीपीयू और 16 मि॰से॰ जीपीयू के हिसाब से होनी चाहिए. आपके पास दो ऐसे संसाधन हैं जिनका साथ-साथ इस्तेमाल किया जा सकता है. परफ़ॉर्मेंस को बेहतर करने के लिए, उनके बीच काम को शिफ़्ट किया जा सकता है. Chrome का about:tracing व्यू एक ऐसा शानदार टूल है जिससे यह समझने में मदद मिलती है कि आपका कोड असल में क्या कर रहा है. यह सही समस्याओं को हल करके, डेवलपमेंट के अपने समय का ज़्यादा से ज़्यादा फ़ायदा पाने में आपकी मदद करेगा.

आगे क्या करना है?

जीपीयू के अलावा, Chrome रनटाइम के अन्य हिस्सों को भी ट्रेस किया जा सकता है. Chrome का शुरुआती वर्शन, Chrome कैनरी, IO, IndexedDB और कई अन्य गतिविधियों को ट्रेस करने के लिए तैयार किया गया है. ट्रेस किए जा रहे इवेंट की मौजूदा स्थिति को ज़्यादा समझने के लिए, आपको Chromium का यह लेख पढ़ना चाहिए.

अगर आप वेब गेम डेवलपर हैं, तो नीचे दिया गया वीडियो देखना न भूलें. GDC 2012 में, Google की गेम डेवलपर एडवोकेट टीम की तरफ़ से एक प्रज़ेंटेशन दिया गया था. इस प्रज़ेंटेशन में, Chrome गेम की परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के बारे में बताया गया था: