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

Lilli Thompson
Lilli Thompson

अगर आप उसे माप नहीं सकते, तो आप उसे बेहतर नहीं बना सकते.

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

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

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

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

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

ट्रेसिंग दृश्य देखने के लिए बस "about:tracing" लिखें टाइप करना शुरू करें.

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

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

ट्रेस करने का आसान नतीजा
ट्रेस करने की आसान प्रक्रिया से जुड़ा नतीजा

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

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

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

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

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

फ़्रेम ढूंढा जा रहा है

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

तीन एक्ज़ीक्यूशन फ़्रेम जैसा लगता है
एक्ज़िक्यूशन फ़्रेम तीन जैसा लगता है

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

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

बॉक्स के इस कलेक्शन में फ़ंक्शन कॉल की एक सीरीज़ दिखती है. हर कॉल को रंगीन बॉक्स से दिखाया जाता है. हर फ़ंक्शन को उसके ऊपर मौजूद बॉक्स से कॉल किया गया था. इसलिए, इस स्थिति में MessageLoop::RunTask को RenderWidget::OnSwapBuffersComplete नाम दिया जाता है, जिसे RenderWidget::DoDeFFedUpdate वगैरह कहा जाता है. इस डेटा को पढ़कर, यह पता किया जा सकता है कि किस प्रोजेक्ट को एक्ज़ीक्यूट करने में कितना समय लगा.

लेकिन यहां वह थोड़ा चिपचिपा हो जाता है. 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 लाइन करीब-करीब पूरी तरह खाली होती है. इसका मतलब है कि सीपीयू के ओवरलोड होने के दौरान, ज़्यादातर समय सीपीयू कुछ समय तक इस्तेमाल में नहीं रहता है. यह इस बात का संकेत है कि आपके शेड बहुत भारी हैं.

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

सही उदाहरण

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

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

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

नतीजा

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

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

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

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