V8 के लिए जावास्क्रिप्ट प्रदर्शन का अनुकूलन

प्रस्तावना


डैनियल क्लिफोर्ड ने Google I / O पर V8 इंजन के लिए जावास्क्रिप्ट कोड को अनुकूलित करने की सुविधाओं के बारे में एक उत्कृष्ट बात की। डैनियल ने हमें और अधिक गति के लिए प्रयास करने के लिए प्रोत्साहित किया, ध्यान से सी ++ और जावास्क्रिप्ट के बीच के अंतरों का विश्लेषण किया और कोड लिखकर याद किया कि दुभाषिया कैसे काम करता है। मैंने इस लेख में डैनियल के प्रदर्शन के सबसे महत्वपूर्ण बिंदुओं का सारांश एकत्र किया है, और मैं इसे इंजन में बदलाव के रूप में अपडेट करूंगा।

सबसे महत्वपूर्ण सलाह


किसी भी प्रदर्शन सुझाव को संदर्भ में देना बहुत महत्वपूर्ण है। अनुकूलन अक्सर एक जुनून बन जाता है, और जंगल में गहरा विसर्जन वास्तव में अधिक महत्वपूर्ण चीजों से ध्यान भंग कर सकता है। आपको वेब एप्लिकेशन प्रदर्शन के समग्र दृष्टिकोण की आवश्यकता है - इन अनुकूलन युक्तियों पर ध्यान देने से पहले, आपको अपने कोड का विश्लेषण करना चाहिए जैसे पेजस्पीड और पहले समग्र परिणाम प्राप्त करना। यह समय से पहले अनुकूलन से बचने में मदद करेगा।

तेज़ वेब एप्लिकेशन बनाने के लिए सबसे अच्छी रणनीति है:


इस रणनीति का पालन करने के लिए, यह समझना महत्वपूर्ण है कि वी 8 जेएस का अनुकूलन कैसे करता है, यह कल्पना करने के लिए कि सब कुछ रनटाइम पर कैसे होता है। सही उपकरण होना भी जरूरी है। अपने भाषण में, डैनियल ने डेवलपर टूल के लिए अधिक समय समर्पित किया; इस लेख में, मैं मुख्य रूप से V8 वास्तुकला की विशेषताओं को देखता हूं।

तो चलिए शुरू करते हैं।

छिपी हुई कक्षाएं


संकलन के चरण में, जावास्क्रिप्ट में प्रकारों के बारे में जानकारी बहुत सीमित है: प्रकार रनटाइम में बदल सकते हैं, इसलिए यह उम्मीद करना स्वाभाविक है कि संकलन के दौरान उनके बारे में धारणा बनाना मुश्किल है। सवाल उठता है - कैसे, ऐसी स्थितियों में, क्या कोई भी C ++ की गति के करीब पहुंच सकता है? हालाँकि, V8 रनटाइम पर ऑब्जेक्ट्स के लिए हिडन क्लासेस बनाने का प्रबंधन करता है। समान वर्ग वाली वस्तुएँ समान अनुकूलित कोड साझा करती हैं।

उदाहरण के लिए:

function Point(x, y) { this.x = x; this.y = y; } var p1 = new Point(11, 22); var p2 = new Point(33, 44); //    p1  p2         p2.z = 55; // !  p1  p2    ! 

जब तक संकलक के अंदर " .z " संपत्ति को p2 , p1 और p2 में जोड़ा गया, तब तक एक ही छिपा हुआ वर्ग था, और V8 दोनों वस्तुओं के लिए एक ही अनुकूलित मशीन कोड का उपयोग कर सकता था। जितनी बार आप छिपे हुए वर्ग को बदलते हैं, उतना ही बेहतर प्रदर्शन होता है।

निष्कर्ष:


संख्या


V8 इस बात पर नज़र रखता है कि आप चर का उपयोग कैसे करते हैं, और प्रत्येक प्रकार के लिए सबसे कुशल प्रतिनिधित्व का उपयोग करता है। प्रकार बदलना काफी महंगा हो सकता है, इसलिए फ्लोटिंग पॉइंट नंबरों और पूर्णांकों को न मिलाने का प्रयास करें। सामान्य तौर पर, पूर्णांक का उपयोग करना बेहतर होता है।

उदाहरण के लिए:

 var i = 42; //  31-    var j = 4.2; //         

निष्कर्ष:


सरणियों


V8 सरणियों के आंतरिक प्रतिनिधित्व के दो प्रकारों का उपयोग करता है:


निष्कर्ष:


इस तरह से:


जावास्क्रिप्ट संकलन


यद्यपि जावास्क्रिप्ट एक गतिशील भाषा है, और मूल रूप से व्याख्या की गई थी, सभी आधुनिक इंजन वास्तव में संकलक हैं। V8 में दो कंपाइलर एक साथ काम करते हैं:


आधार संकलक


V8 में, वह सबसे पहले सभी कोड को प्रोसेस करना शुरू करता है और इसे जल्दी से जल्दी चलाता है। इसके द्वारा उत्पन्न कोड लगभग अनुकूलित नहीं है - बुनियादी संकलक प्रकारों के बारे में लगभग कोई धारणा नहीं बनाता है। निष्पादन के दौरान, संकलक इनलाइन कैश का उपयोग करता है जिसमें कोड के प्रकार-निर्भर अनुभाग संग्रहीत होते हैं। जब इस कोड को पुनः आरंभ किया जाता है, तो संकलक कैश से तैयार कोड के उपयुक्त संस्करण को चुनने से पहले इसमें उपयोग किए गए प्रकारों की जांच करता है। इसलिए, ऑपरेटर जो विभिन्न प्रकारों के साथ काम कर सकते हैं, निष्पादित करने के लिए धीमी हैं।

निष्कर्ष:


एक ऑपरेटर मोनोमोर्फिक है यदि छिपे हुए प्रकार के ऑपरेंड हमेशा समान होते हैं, और पॉलीमोर्फिक अगर यह बदल सकता है। उदाहरण के लिए, add() लिए दूसरा कॉल add() कोड बहुरूपी बनाता है:

 function add(x, y) { return x + y; } add(1, 2); // +  add()  add("a", "b"); // +  add()   

संकलक का अनुकूलन


बुनियादी संकलक के काम के साथ समानांतर में, अनुकूलन करने वाला कंपाइलर कोड के "गर्म" खंडों को फिर से जोड़ देता है जो अक्सर निष्पादित होते हैं। यह इनलाइन कैश में संचित जानकारी का उपयोग करता है।

अनुकूलन करने वाला कंपाइलर कॉल स्थानों में कार्यों को एम्बेड करने की कोशिश करता है, जो निष्पादन को गति देता है (लेकिन मेमोरी की खपत को बढ़ाता है) और अतिरिक्त अनुकूलन के लिए अनुमति देता है। मोनोमोर्फिक फ़ंक्शन और कंस्ट्रक्टर आसानी से पूरी तरह से बनाए जा सकते हैं, और यह एक और कारण है कि आपको उनका उपयोग करने का प्रयास करना चाहिए।

आप देख सकते हैं कि d8 इंजन के स्टैंडअलोन संस्करण का उपयोग करके आपके कोड में वास्तव में क्या अनुकूलित है:

 d8 --trace-opt primes.js 
(अनुकूलित कार्यों के नाम stdout में प्रदर्शित किए जाएंगे)

सभी सुविधाओं को अनुकूलित नहीं किया जा सकता है। विशेष रूप से, अनुकूलन करने वाला कंपाइलर किसी भी फ़ंक्शंस को रोक देता है जिसमें try/catch ब्लॉक होते हैं।

निष्कर्ष:

यदि आपको एक try/catch का उपयोग करने की आवश्यकता है, तो प्रदर्शन-महत्वपूर्ण कोड बाहर रखें। एक उदाहरण:

 function perf_sensitive() { //     } try { perf_sensitive() } catch (e) { //    } 

शायद भविष्य में स्थिति बदल जाएगी, और हम अनुकूलन कंपाइलर द्वारा try/catch ब्लॉक संकलित try/catch सक्षम होंगे। आप यह देख सकते हैं कि d8 शुरू करते समय --trace-bailout को निर्दिष्ट करके किन कार्यों को अनदेखा किया गया है:

 d8 --trace-bailout primes.js 

deoptimization


ऑप्टिमाइज़िंग कंपाइलर द्वारा उत्पन्न कोड हमेशा तेज नहीं होता है। इस मामले में, मूल, गैर-अनुकूलित संस्करण का उपयोग किया जाता है। असफल रूप से अनुकूलित कोड को फेंक दिया जाता है, और बेस कंपाइलर द्वारा बनाए गए कोड में उचित स्थान से निष्पादन जारी रहता है। शायद यह कोड जल्द ही फिर से अनुकूलित हो जाएगा, अगर परिस्थितियाँ अनुमति देती हैं। विशेष रूप से, पहले से ही अनुकूलित कोड के अंदर छिपे हुए वर्गों को बदलने से विकृति हो जाती है।

निष्कर्ष:


आप वास्तव में देख सकते हैं कि कौन से फ़ंक्शंस को d8 --trace-deopt the --trace-deopt साथ चलाकर समाप्त किया जा रहा --trace-deopt :

 d8 --trace-deopt primes.js 

अन्य V8 उपकरण


उपरोक्त कार्यों को स्टार्टअप पर Google Chrome में स्थानांतरित किया जा सकता है:

 /Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --js-flags="--trace-opt --trace-deopt --trace-bailout 

डी 8 में एक प्रोफाइलर भी है:

 d8 primes.js --prof 

डी 8 नमूना प्रोफाइलर हर मिलीसेकंड को स्नैपशॉट लेता है और v8.log को लिखता है।

सारांश


यह समझना महत्वपूर्ण है कि अच्छी तरह से अनुकूलित कोड लिखने के लिए V8 इंजन कैसे काम करता है। और लेख की शुरुआत में वर्णित सामान्य सिद्धांतों के बारे में मत भूलना:


इसका मतलब यह है कि आपको यह सुनिश्चित करना होगा कि पेजस्पीड जैसे टूल का उपयोग करके यह जावास्क्रिप्ट में है। अड़चन की तलाश करने से पहले डोम कॉल से छुटकारा पाने के लायक हो सकता है। मुझे उम्मीद है कि डैनियल की प्रस्तुति (और यह लेख) आपको V8 के संचालन को बेहतर ढंग से समझने में मदद करेगी, लेकिन यह मत भूलो कि एक विशिष्ट इंजन में समायोजित करने के बजाय प्रोग्राम एल्गोरिथ्म को अनुकूलित करने के लिए यह अक्सर अधिक उपयोगी होता है।

संदर्भ:


Source: https://habr.com/ru/post/In154537/


All Articles