2012-09-10 16 views
5

प्रलेखन गलत लगता है। क्या कोई मुझे बता सकता है कि कौन सा सच है?स्थानीय फ़ील्ड बनाम ऑब्जेक्ट फ़ील्ड तक पहुंच। क्या डॉक्टर गलत है?

Performance Myths खंड में है:

डिवाइस पर एक JIT बिना, कैशिंग क्षेत्र तक पहुँचता है के बारे में 20% बार-बार क्षेत्र accesssing से तेज है। एक जेआईटी के साथ, स्थानीय पहुंच के समान फ़ील्ड एक्सेस लागत।

Avoid Internal Getters/Setters खंड में है:

एक JIT के बिना, प्रत्यक्ष क्षेत्र का उपयोग एक छोटी सी गेटर लागू की तुलना के बारे में 3x तेज है। जेआईटी (जहां प्रत्यक्ष क्षेत्र का उपयोग स्थानीय तक पहुंचने के रूप में सस्ता है) के साथ, प्रत्यक्ष क्षेत्र का उपयोग लगभग 7x एक मामूली गेटर का आह्वान करने से तेज़ है।

यह स्पष्ट है कि जेआईटी स्थानीय पहुंच के बिना तेज़ है। यह भी स्पष्ट है कि गेटटर से सीधे पहुंचते समय फ़ील्ड का उपयोग तेजी से होता है।

लेकिन पहले मामले प्रदर्शन में 20% बेहतर और दूसरे मामले प्रदर्शन में है 133% इसी कारण से बेहतर है, उस वस्तु क्षेत्र फोन करने के लिए JIT अनुकूलन है?

+1

मैं हाँ कहूंगा, दस्तावेज गलत/गलत/बहुत अलग मापों के आधार पर है। यदि आईएमओ सचमुच लिया जाता है तो यह वास्तव में बताता है कि जेआईटी 20% और 133% (3x बनाम 7x) तक फ़ील्ड एक्सेस को गति देता है, जो असंभव है – zapl

+0

बिल्कुल, यह मेरा मुद्दा है। मैं सोच रहा हूं कि कौन से मूल्य सही हैं। – pawelzieba

+1

दोनों कथन 20% और [MethodInvocationBenchmark.java] के लिए विभिन्न मानक [FieldAccessBenchmark.java] (http://code.google.com/p/dalvik/source/browse/trunk/benchmarks/FieldAccessBenchmark.java) पर आधारित हैं। (http://code.google.com/p/dalvik/source/browse/trunk/benchmarks/MethodInvocationBenchmark.java) 133% के लिए। एक कारण हो सकता है। लेकिन मुझे बहुत ज्यादा परवाह नहीं है, केवल सभी उपकरणों के <5% ([<एंड्रॉइड 2.2] (http://developer.android.com/about/dashboards/index.html)) में JIT और महत्वपूर्ण सबक नहीं है क्या आंतरिक गेटर्स धीमे हैं। – zapl

उत्तर

5

मुझे लगता है कि आप सेब और संतरे की तुलना कर रहे। प्रदर्शन मिथक संदर्भ फ़ील्ड एक्सेस के लिए एक जेआईटी के लाभ पर चर्चा करता है, जबकि दूसरा संदर्भ विधि पहुंच के लिए एक जेआईटी के लाभ पर चर्चा करता है।

: -

मैं यह समझ के रूप में, स्थानीय उपयोग बनाम प्रत्यक्ष क्षेत्र पहुँच के लिए एक सादृश्य (स्थानीय नहीं क्षेत्र पहुँच के रूप में आप अपनी पोस्ट में लिखा था कि वहाँ एक स्थानीय क्षेत्र के रूप में ऐसी कोई बात नहीं है) निम्नलिखित है

class foo { 
    int bar = 42; 

    int doStuff(){ 
     int x = 1; 
     x += bar; 
     x += bar; 
     x += bar; 
     return x; 
    } 
} 

प्रत्येक संदर्भ bar लिए एक संबद्ध प्रदर्शन लागत है। एक अच्छा संकलक जैसे अनुकूलन और 'फिर से लिखने के' कोड के लिए अवसर की पहचान करेगा:

int doStuff(){ 
    int x = 1f; 
    int local_bar = bar; 
    x += local_bar; 
    x += local_bar; 
    x += local_bar; 
    return x; 
} 

एक JIT बिना, इस एक आसान अनुकूलन है, जो आप प्रदर्शन में एक 20% टक्कर हो जाता है।

एक जेआईटी के साथ, अनुकूलन अपरिहार्य है, क्योंकि जेआईटी पहली जगह में bar तक पहुंच से प्रदर्शन हिट को हटा देता है।

दूसरा संदर्भ का वर्णन करता है इस परिदृश्य पर:

class foo { 
    int bar = 42; 

    int getBar() { return bar; } 

    int doStuff(){ 
     int x = 1; 
     x += getBar(); 
     x += getBar(); 
     x += getBar(); 
     return x; 
    } 
} 

प्रत्येक समारोह कॉल एक संबद्ध प्रदर्शन दंड है। एक कंपाइलर नहीं एकाधिक getBar() विधि कॉल को कैश कर सकता है (क्योंकि यह पिछले प्रत्यक्ष क्षेत्र में bar तक पहुंचता है), क्योंकि getBar() प्रत्येक बार इसे कॉल करने पर एक पूरी तरह से अलग संख्या लौटा सकता है (यानी यदि उसके पास इसके वापसी मूल्य के लिए यादृच्छिक या समय-आधारित घटक)। इसलिए, यह तीन विधि कॉल पर अमल करना होगा।

यह समझना महत्वपूर्ण है कि उपर्युक्त फ़ंक्शन लगभग एक ही गति के साथ या बिना किसी गति के निष्पादित करेगा।

यदि आप उपरोक्त फ़ंक्शन में के साथ मैन्युअल रूप से getBar() को प्रतिस्थापित करना चाहते हैं, तो आप प्रदर्शन को बढ़ावा देंगे।एक जेआईटी के बिना मशीन पर, यह प्रदर्शन बूस्ट लगभग 3x है, क्योंकि क्षेत्र का उपयोग अभी भी कुछ हद तक धीमा है, इसलिए धीमी गति से पहुंचने वाले बहुत धीमे तरीकों को बदलने से बहुत ही धीमी गति से केवल मध्यम वृद्धि होती है। एक जेआईटी के साथ, हालांकि, क्षेत्र का उपयोग तेजी से होता है, इसलिए तेज क्षेत्र की पहुंच के साथ बहुत धीमी विधियों को प्रतिस्थापित करने से बहुत अधिक (7x) बढ़ावा मिलता है।

मुझे आशा है कि यह समझ में आता है!

+1

@ पेडेंटिक: मुझे इसे मारो! :) आह ठीक है, मुझे लगता है कि मैं पूर्णता के लिए एक संपादन में अपना जवाब खत्म कर दूंगा। यह मनोरंजक है कि हम दोनों सेब और संतरे का संदर्भ बनाते हैं। – bfishman

+0

अच्छा संयोग :) @bfishman: मैंने "स्थानीय क्षेत्र" के साथ एक फिक्स किया। डॉक्टर का कहना है कि छोटे गेटटर के लिए प्रदर्शन लाभ फ़ील्ड एक्सेस ऑप्टिमाइज़ेशन से जुड़ा हुआ है (जहां प्रत्यक्ष क्षेत्र का उपयोग स्थानीय के रूप में सस्ता है) '। ऐसा लगता है कि कुछ और है। – pawelzieba

+0

दाएं, इसलिए तरीके (गेटर्स) फ़ील्ड की तुलना में धीमी हैं, जो स्थानीय लोगों की तुलना में धीमी हैं। एक जेआईटी के बिना, आप एक फ़ील्ड के साथ एक विधि को प्रतिस्थापित कर सकते हैं, और एक मध्यम (3x) बढ़ावा प्राप्त कर सकते हैं। एक जेआईटी के साथ, आप एक फ़ील्ड के साथ एक विधि को प्रतिस्थापित कर सकते हैं, जिसे तब स्थानीय द्वारा प्रतिस्थापित किया जाता है, इसलिए आप एक अधिक महत्वपूर्ण बढ़ावा (7x) देते हैं क्योंकि आप एक स्थानीय विधि का उपयोग करने के लिए विधि का उपयोग करने से जाते हैं। या, जैसा कि @ डेलन ने कहा था, गेटटर का उपयोग करने का _relative_ प्रदर्शन प्रभाव एक जेआईटी के साथ अधिक है, क्योंकि आप विधि-> स्थानीय, उपाध्यक्ष विधि-> जेआईटी के बिना फ़ील्ड से जाने से चूक जाते हैं। – bfishman

2

मुझे लगता है कि आप सेब बनाम संतरे की तुलना कर सकते हैं। पहली बोली में:

caching field accesses is about 20% faster than repeatedly accesssing the field 

का तात्पर्य एक कैशिंग रणनीति केवल प्रत्यक्ष क्षेत्र पहुँच दौरान JIT संकलन के बिना प्रदर्शन में सुधार होगा। दूसरे शब्दों में:

int a = this.field; 
if (a == 1) 
... 
if (a == 7) // etc. 

बेहतर प्रदर्शन

if (this.field == 1) 
.... 
if (this.field == 7) //etc. 

से उद्धरण से पता चलता है कि आप एक दंड बार-बार क्षेत्र को संदर्भित करने के बजाय स्थानीय स्तर पर यह भंडारण के द्वारा मारा होगा अर्जित करता है।

दूसरी बोली पता चलता है कि एक छोटी सी गेटर का उपयोग कर JIT बिना/सेटर प्रत्यक्ष क्षेत्र का उपयोग की तुलना में धीमी है, जैसे:

if (this.field) // etc. 

मुझे नहीं लगता कि:

if (this.getField()) // etc. 

की तुलना में धीमी दस्तावेज गलत है या एक कथन दूसरे को कमजोर करता है।

1

यह सिर्फ एक शिक्षित अनुमान है, मुझे Dalvik internals के बारे में कोई जानकारी नहीं है। लेकिन ध्यान दें कि पहले मामले में, स्थानीय पहुंच के प्रदर्शन की तुलना फ़ील्ड एक्सेस से की जाती है, जबकि दूसरे मामले में, फील्ड एक्सेस की तुलना एक छोटी विधि कॉल से की जाती है। यह भी ध्यान रखें कि एक्स% स्पीडअप वास्तव में एक जेआईटी जोड़कर एक ही कोड के लिए x% कम समय नहीं लिया जाता है, हम सापेक्ष प्रदर्शन के बारे में बात कर रहे हैं: (ए) व्याख्या की गई स्थानीय पहुंच की तुलना में स्थानीय पहुंच 20% तेज है, और (बी) JIT'd स्थानीय पहुंच जितनी जल्दी हो सके उतनी तेजी से JIT'd फ़ील्ड एक्सेस का अर्थ नहीं है (सी) स्थानीय उपयोग की व्याख्या स्थानीय स्तर पर जेआईटीएड स्थानीय/फील्ड पहुंच जितनी तेज है। वास्तव में, यह वास्तव में धीमी है।

एक दुभाषिया में एक स्थानीय पढ़ना, है सबसे वीएम आर्किटेक्चर, एक स्मृति का उपयोग, नहीं एक रजिस्टर का उपयोग (हम मशीन रजिस्टर, नहीं Dalvik रजिस्टरों के बारे में बात कर रहे हैं) के साथ। एक क्षेत्र पढ़ना भी धीमी है - मुझे यकीन है कि के लिए नहीं कह सकते क्यों (मेरा अनुमान है दूसरी देखने होगा, दोनों रजिस्टर और वस्तु क्षेत्र पढ़ने), लेकिन किसी भी मामले में यह और अधिक जटिल है। दूसरी ओर JIT दोनों क्षेत्रों और स्थानीय लोगों के रजिस्टरों में डाल सकते हैं (कि क्या मैं प्रदर्शन समानता की व्याख्या करने के ग्रहण करना है, और वास्तव में वहाँ JITs जो यह कर रहे हैं - मैं बस नहीं जानता कि अगर यह यहाँ लागू होता है) और अधिकतर ओवरहेड हटा देता है।

विधि कॉल के लिए, माना जाता है कि डाल्विक जेआईटी इनलाइन विधियों (जो अंतर्निहित है) नहीं है, आपके पास वास्तविक कॉल के ऊपर कुछ ओवरहेड है जो JIT'd के समय भी महंगे कॉल करता है: रजिस्टरों को ढेर में सहेजना चाहिए, पुनर्स्थापित करना होगा उन्हें बाद में, अनुकूलित नहीं किया जा सकता क्योंकि सभी कोड दिखाई नहीं दे रहे हैं। एक कॉल अपेक्षाकृत अधिक महंगा है तो कॉल-कम कोड क्योंकि कॉल-कम विकल्प इतनी तेजी से चमक रहा है, न कि क्योंकि दुभाषिया कॉल करने में बेहतर करता है (ऐसा नहीं है, यह भी सबकुछ धीमा कर रहा है)। उदाहरण के लिए, कॉल द्वारा कोई अनुकूलन नहीं रोका जा रहा है, क्योंकि कोई अनुकूलन नहीं है।

संबंधित मुद्दे