मैं जावा में एक सही माइक्रो-बेंचमार्क कैसे लिखूं?
आप जावा में एक सही माइक्रो-बेंचमार्क कैसे लिखते हैं (और चलाते हैं)?
मैं कुछ कोड नमूने और टिप्पणियों के बारे में सोचने के लिए विभिन्न चीजों को दिखाता हूं।
उदाहरण: बेंचमार्क समय / पुनरावृत्ति या पुनरावृत्तियों / समय को मापना चाहिए, और क्यों?
संबंधित: स्टॉपवॉच बेंचमार्किंग स्वीकार्य है?
जवाब
जावा हॉटस्पॉट के रचनाकारों से माइक्रो बेंचमार्क लिखने के बारे में सुझाव :
नियम 0: जेवीएम और माइक्रो-बेंचमार्किंग पर एक प्रतिष्ठित पेपर पढ़ें। एक अच्छा ब्रायन Goetz, 2005 है । माइक्रो-बेंचमार्क से बहुत अधिक उम्मीद न करें; वे जेवीएम प्रदर्शन विशेषताओं की केवल सीमित सीमा को मापते हैं।
नियम 1: हमेशा एक वार्मअप चरण शामिल करें जो आपके परीक्षण कर्नेल को सभी तरह से चलाता है, समय चरण (ओं) से पहले सभी इनिशियलाइज़ेशन और संकलन को ट्रिगर करने के लिए पर्याप्त है। (वार्मअप चरण पर कुछ पुनरावृत्तियाँ ठीक हैं। अंगूठे का नियम कई दसियों हज़ार इनर लूप पुनरावृत्तियों का है।)
नियम 2: हमेशा साथ रखें -XX:+PrintCompilation
, -verbose:gc
आदि, तो आप यह सत्यापित कर सकते हैं कि आपके समय के चरण में कंपाइलर और जेवीएम के अन्य हिस्से अप्रत्याशित काम नहीं कर रहे हैं।
नियम 2.1: समय और वार्मअप चरणों की शुरुआत और अंत में संदेश प्रिंट करें, ताकि आप यह सत्यापित कर सकें कि समय चरण के दौरान नियम 2 से कोई आउटपुट नहीं है।
नियम 3: के बीच अंतर के प्रति सचेत रहें -client
और -server
, और OSR और नियमित रूप से संकलन। -XX:+PrintCompilation
झंडा एक पर हस्ताक्षर के साथ OSR संकलन रिपोर्ट उदाहरण के लिए, गैर प्रारंभिक प्रवेश बिंदु को निरूपित करने के: Trouble$1::run @ 2 (41 bytes)
। क्लाइंट के लिए सर्वर को प्राथमिकता दें, और यदि आप सर्वश्रेष्ठ प्रदर्शन के बाद भी OSR के लिए नियमित हैं।
नियम 4: आरंभिक प्रभावों से अवगत रहें। अपने लोडिंग चरण के दौरान पहली बार प्रिंट न करें, क्योंकि लोड लोड करना और कक्षाएं शुरू करना। वार्मअप चरण (या अंतिम रिपोर्टिंग चरण) के बाहर नई कक्षाएं लोड न करें, जब तक कि आप विशेष रूप से वर्ग लोडिंग का परीक्षण नहीं कर रहे हैं (और उस स्थिति में केवल परीक्षण कक्षाएं लोड करें)। नियम 2 इस तरह के प्रभावों के खिलाफ रक्षा की आपकी पहली पंक्ति है।
नियम 5: डीओपिटिमाइज़ेशन और पुनर्मूल्यांकन प्रभावों से अवगत रहें। टाइमिंग के चरण में पहली बार कोई कोड पथ न लें, क्योंकि कंपाइलर कोड को रद्दी कर सकता है और पहले की आशावादी धारणा के आधार पर कोड को फिर से जोड़ सकता है, जो कि पथ का उपयोग करने वाला नहीं था। नियम 2 इस तरह के प्रभावों के खिलाफ रक्षा की आपकी पहली पंक्ति है।
नियम 6: संकलक के दिमाग को पढ़ने के लिए उपयुक्त उपकरणों का उपयोग करें, और इसके द्वारा उत्पादित कोड से आश्चर्यचकित होने की उम्मीद करें। कुछ तेज या धीमा करने के बारे में सिद्धांतों को बनाने से पहले कोड का स्वयं निरीक्षण करें।
नियम 7: अपने माप में शोर को कम करें। एक शांत मशीन पर अपने बेंचमार्क को चलाएं, और इसे कई बार चलाएं, आउटलेर्स को त्याग दें। -Xbatch
अनुप्रयोग के साथ संकलक को क्रमबद्ध करने के लिए उपयोग करें , और -XX:CICompilerCount=1
संकलक को अपने साथ समानांतर में चलने से रोकने के लिए सेटिंग पर विचार करें । जीसी ओवरहेड को कम करने के लिए अपनी पूरी कोशिश करें, अगर यह उपलब्ध है तो Xmx
काफी (बराबर) सेट Xms
और उपयोग करें UseEpsilonGC।
नियम 8: अपने बेंचमार्क के लिए एक पुस्तकालय का उपयोग करें क्योंकि यह संभवतः अधिक कुशल है और पहले से ही इस एकमात्र उद्देश्य के लिए डिबग किया गया था। जैसे जावा के लिए जेएमएच , कैलिपर या बिल और पॉल का उत्कृष्ट यूसीएसडी बेंचमार्क ।
मुझे पता है कि इस प्रश्न को उत्तर के रूप में चिह्नित किया गया है, लेकिन मैं दो पुस्तकालयों का उल्लेख करना चाहता था जो हमें माइक्रो बेंचमार्क लिखने में मदद करते हैं
Google से कैलिपर
ट्यूटोरियल शुरू करना
- http://codingjunkie.net/micro-benchmarking-with-caliper/
- http://vertexlabs.co.uk/blog/caliper
OpenJDK से जेएमएच
ट्यूटोरियल शुरू करना
- जेवीएम पर बेंचमार्किंग के नुकसान से बचना
- जावा माइक्रोबेनमार्किंग के लिए जेएमएच का उपयोग करना
- JMH का परिचय
जावा बेंचमार्क के लिए महत्वपूर्ण चीजें हैं:
- कोड कई बार चलाकर पहले JIT वार्म अप समय से पहले यह
- सुनिश्चित करें कि आप इसे लंबे समय तक चलाते हैं ताकि सेकंड या (बेहतर) दसियों सेकंड में परिणामों को मापा जा सके
- जब आप
System.gc()
पुनरावृत्तियों के बीच कॉल नहीं कर सकते , तो परीक्षणों के बीच इसे चलाना एक अच्छा विचार है, ताकि प्रत्येक परीक्षा में आशा के साथ काम करने के लिए "स्वच्छ" मेमोरी स्पेस मिल सके। (हां,gc()
गारंटी से अधिक संकेत है, लेकिन यह बहुत संभावना है कि यह वास्तव में मेरे अनुभव को इकट्ठा करेगा) - मैं पुनरावृत्तियों और समय को प्रदर्शित करना पसंद करता हूं, और समय / पुनरावृत्ति का एक स्कोर जिसे इस तरह से स्केल किया जा सकता है कि "सर्वश्रेष्ठ" एल्गोरिथ्म को 1.0 का स्कोर मिलता है और अन्य को एक रिश्तेदार फैशन में स्कोर किया जाता है। इसका मतलब है कि आप सभी एल्गोरिदम को लंबे समय तक चला सकते हैं , पुनरावृत्तियों और समय दोनों को अलग-अलग कर सकते हैं, लेकिन फिर भी तुलनीय परिणाम प्राप्त कर सकते हैं।
मैं सिर्फ .NET में बेंचमार्किंग फ्रेमवर्क के डिज़ाइन के बारे में ब्लॉगिंग की प्रक्रिया में हूँ। मैं एक मिल गया है जोड़ी के पहले पदों जो आप कुछ विचार देने में सक्षम हो सकते हैं - सब कुछ, उचित होगा ज़ाहिर है, लेकिन इसके बारे में कुछ हो सकता है।
jmh OpenJDK का एक हालिया जोड़ है और इसे Oracle के कुछ प्रदर्शन इंजीनियरों द्वारा लिखा गया है। निश्चित रूप से देखने लायक।
जेएमएच जावा और अन्य भाषाओं में JVM को लक्षित करने वाली नैनो / माइक्रो / मैक्रो बेंचमार्क के निर्माण, चलाने और विश्लेषण के लिए जावा हार्नेस है।
नमूना परीक्षण टिप्पणियों में दफन जानकारी के बहुत दिलचस्प टुकड़े ।
यह सभी देखें:
- जेवीएम पर बेंचमार्किंग के नुकसान से बचना
- जेएमएच की मुख्य ताकत पर चर्चा ।
बेंचमार्क समय / पुनरावृत्ति या पुनरावृत्तियों / समय को मापना चाहिए, और क्यों?
यह इस बात पर निर्भर करता है कि आप क्या परीक्षण करना चाहते हैं।
यदि आप विलंबता में रुचि रखते हैं , तो समय / पुनरावृत्ति का उपयोग करें और यदि आप थ्रूपुट में रुचि रखते हैं , तो पुनरावृत्तियों / समय का उपयोग करें।
यदि आप दो एल्गोरिदम की तुलना करने की कोशिश कर रहे हैं, तो ऑर्डर को बारी-बारी से प्रत्येक के लिए कम से कम दो बेंचमार्क करें। अर्थात:
for(i=1..n)
alg1();
for(i=1..n)
alg2();
for(i=1..n)
alg2();
for(i=1..n)
alg1();
मैंने अलग-अलग पासों में एक ही एल्गोरिदम के रनटाइम में कुछ ध्यान देने योग्य अंतर (5-10% कभी-कभी) पाया है।
यह भी सुनिश्चित करें कि n बहुत बड़ा है, ताकि प्रत्येक लूप का रनटाइम बहुत कम 10 सेकंड या इतने पर हो। अधिक पुनरावृत्तियों, आपके बेंचमार्क समय में अधिक महत्वपूर्ण आंकड़े और डेटा जितना अधिक विश्वसनीय है।
सुनिश्चित करें कि आप किसी ऐसे परिणाम का उपयोग करते हैं, जिसकी गणना बेंचमार्क कोड में की जाती है। अन्यथा आपका कोड दूर अनुकूलित किया जा सकता है।
जावा में माइक्रो-बेंचमार्क लिखने के लिए कई संभावित नुकसान हैं।
पहला: आपको सभी प्रकार की घटनाओं की गणना करनी होगी जो समय को कम या अधिक यादृच्छिक रूप से लेती हैं: कचरा संग्रह, कैशिंग प्रभाव (फाइलों के लिए ओएस और मेमोरी के लिए सीपीयू), आईओ आदि।
दूसरा: आप बहुत कम अंतराल के लिए मापा समय की सटीकता पर भरोसा नहीं कर सकते।
तीसरा: JVM निष्पादित करते समय आपके कोड का अनुकूलन करता है। एक ही जेवीएम-उदाहरण में अलग-अलग रन तेज और तेज हो जाएंगे।
मेरी सिफारिशें: अपने बेंचमार्क को कुछ सेकंड चलाएं, जो कि मिलीसेकंड से अधिक रनटाइम से अधिक विश्वसनीय है। जेवीएम को गर्म करें (बिना माप के कम से कम एक बार बेंचमार्क चलाने का मतलब है कि जेवीएम अनुकूलन कर सकता है)। और अपने बेंचमार्क को कई बार (शायद 5 बार) चलाएं और माध्य-मान लें। हर माइक्रो-बेंचमार्क को एक नए JVM- उदाहरण (हर बेंचमार्क नए जावा के लिए कॉल) में चलाएं अन्यथा JVM का अनुकूलन प्रभाव बाद में चलने वाले परीक्षणों को प्रभावित कर सकता है। चीजों को निष्पादित न करें, जो वार्मअप-चरण में निष्पादित नहीं होते हैं (क्योंकि यह वर्ग-भार और पुनर्संयोजन को ट्रिगर कर सकता है)।
यह भी ध्यान दिया जाना चाहिए कि विभिन्न कार्यान्वयनों की तुलना करते समय माइक्रो बेंचमार्क के परिणामों का विश्लेषण करना भी महत्वपूर्ण हो सकता है। इसलिए एक महत्व परीक्षण बनाया जाना चाहिए।
ऐसा इसलिए है क्योंकि कार्यान्वयन की A
तुलना में बेंचमार्क के अधिकांश रन के दौरान कार्यान्वयन तेज हो सकता है B
। लेकिन A
इसका अधिक प्रसार भी हो सकता है, इसलिए A
जब तुलना की जाती है तो मापा प्रदर्शन लाभ किसी भी महत्व का नहीं होगा B
।
इसलिए माइक्रो बेंचमार्क को सही तरीके से लिखना और चलाना भी महत्वपूर्ण है, लेकिन इसका सही विश्लेषण भी करना है।
अन्य उत्कृष्ट सलाह को जोड़ने के लिए, मैं निम्नलिखित बातों पर भी ध्यान रखूंगा:
कुछ सीपीयू (जैसे इंटेल कोर आई 5 रेंज टर्बोबॉस्ट के साथ) के लिए, तापमान (और वर्तमान में उपयोग किए जा रहे कोर की संख्या, साथ ही साथ इसका उपयोग प्रतिशत) घड़ी की गति को प्रभावित करता है। चूंकि सीपीयू गतिशील रूप से देखे जाते हैं, यह आपके परिणामों को प्रभावित कर सकता है। उदाहरण के लिए, यदि आपके पास एक एकल-थ्रेडेड अनुप्रयोग है, तो अधिकतम घड़ी की गति (टर्बोबोस्ट के साथ) सभी कोर का उपयोग करने वाले एप्लिकेशन की तुलना में अधिक है। इसलिए यह कुछ प्रणालियों पर एकल और बहु-थ्रेडेड प्रदर्शन की तुलना के साथ हस्तक्षेप कर सकता है। यह ध्यान रखें कि तापमान और वोल्टेज भी प्रभावित करते हैं कि टर्बो आवृत्ति कितनी देर तक बनी रहती है।
शायद एक अधिक मौलिक रूप से महत्वपूर्ण पहलू जिस पर आपका सीधा नियंत्रण है: सुनिश्चित करें कि आप सही चीज़ को माप रहे हैं! उदाहरण के लिए, यदि आप System.nanoTime()
किसी विशेष बिट कोड को बेंचमार्क करने के लिए उपयोग कर रहे हैं, तो कॉल को उन स्थानों पर असाइनमेंट में रखें, जो उन चीजों को मापने से बचते हैं, जिनमें आपकी रुचि नहीं है। उदाहरण के लिए, ऐसा न करें:
long startTime = System.nanoTime();
//code here...
System.out.println("Code took "+(System.nanoTime()-startTime)+"nano seconds");
समस्या यह है कि कोड समाप्त होने पर आपको तुरंत अंतिम समय नहीं मिल रहा है। इसके बजाय, निम्नलिखित प्रयास करें:
final long endTime, startTime = System.nanoTime();
//code here...
endTime = System.nanoTime();
System.out.println("Code took "+(endTime-startTime)+"nano seconds");
http://opt.sourceforge.net/जावा माइक्रो बेंचमार्क - विभिन्न प्लेटफार्मों पर कंप्यूटर प्रणाली की तुलनात्मक प्रदर्शन विशेषताओं को निर्धारित करने के लिए आवश्यक कार्यों को नियंत्रित करता है। अनुकूलन निर्णयों का मार्गदर्शन करने और विभिन्न जावा कार्यान्वयनों की तुलना करने के लिए उपयोग किया जा सकता है।