2011-03-09 6 views
14

मैं इस कोड का परीक्षण किया जाता है कि Calendar.getInstance().getTimeInMillis()System.currentTimeMilli() बनाम है:कैसे बनाने के लिए सुनिश्चित करें कि कोई JVM और संकलक अनुकूलन होता

long before = getTimeInMilli(); 
for (int i = 0; i < TIMES_TO_ITERATE; i++) 
{ 
    long before1 = getTimeInMilli(); 
    doSomeReallyHardWork(); 
    long after1 = getTimeInMilli(); 
} 
long after = getTimeInMilli(); 
System.out.println(getClass().getSimpleName() + " total is " + (after - before)); 

मुझे यकीन है कि कोई JVM या संकलक अनुकूलन होता है बनाना चाहते हैं, तो परीक्षण मान्य हो सकता है और होगा वास्तव में अंतर दिखाएगा।

कैसे सुनिश्चित करें?

संपादित करें: मैंने कोड उदाहरण बदल दिया है, इसलिए यह और अधिक स्पष्ट होगा। मैं यहां क्या देख रहा हूं कि विभिन्न कार्यान्वयन में GetTimeInMilli() को कॉल करने में कितना समय लगता है - कैलेंडर बनाम सिस्टम।

उत्तर

24

मुझे लगता है कि आपको जेआईटी को अक्षम करने की आवश्यकता है। अपने रन कमांड में जोड़ें अगला विकल्प:

-Djava.compiler=NONE 
+6

धन्यवाद; क्लाउड प्रदर्शन के लिए ओ (1), ओ (एन) और ओ (एन^2) एल्गोरिदम के बीच दक्षता में अंतर दिखाने के लिए जावा को "सटीक" करने के लिए मुझे बस इतना ही आवश्यक था :-) ग्रहण में, आप इसे डाल सकते हैं रन कॉन्फ़िगरेशन/तर्क/वीएम सेटिंग में। –

4

क्षमा करें, लेकिन आप जो करने की कोशिश कर रहे हैं वह थोड़ा समझ में आता है।

यदि आप जेआईटी संकलन बंद करते हैं, तो आप केवल यह मापने जा रहे हैं कि जेआईटी संकलन बंद होने के साथ उस विधि को कॉल करने में कितना समय लगता है। यह उपयोगी जानकारी नहीं है ... क्योंकि यह जेआईटी संकलन चालू होने पर क्या होगा, इसके बारे में कुछ भी कम बताता है।

जेआईटी चालू और बंद के बीच के समय एक बड़े कारक से अलग हो सकते हैं। आप जेआईटी बंद होने के साथ उत्पादन में कुछ भी चलाने की संभावना नहीं है।

एक बेहतर दृष्टिकोण यह करने के लिए होगा:

long before1 = getTimeInMilli(); 
for (int i = 0; i < TIMES_TO_ITERATE; i++) { 
    doSomeReallyHardWork(); 
} 
long after1 = getTimeInMilli(); 

... और/या nanosecond घड़ी का उपयोग करें।


आप समय getTimeInMillis() के दो संस्करणों कॉल करने के लिए ले जाया को मापने के लिए कोशिश कर रहे हैं, तो मैं अपने कॉल की बात doSomeReallyHardWork() को समझ में नहीं आता। एक और अधिक senible बेंचमार्क इस होगा:

public long test() { 
    long before1 = getTimeInMilli(); 
    long sum = 0; 
    for (int i = 0; i < TIMES_TO_ITERATE; i++) { 
     sum += getTimeInMilli(); 
    } 
    long after1 = getTimeInMilli(); 
    System.out.println("Took " + (after - before) + " milliseconds"); 
    return sum; 
} 

... और कॉल कि कई बार, जब तक बार मुद्रित को स्थिर।

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

+0

शायद आपको याद आती है। जो मैं परीक्षण करने की कोशिश कर रहा हूं वह यह है कि TimeInMilli() लेने के लिए कॉल कितना है। एक बार कैलेंडर का उपयोग करके और सिस्टम का उपयोग कर एक बार। – oshai

11

आप अनुकूलन चाहते हैं, क्योंकि यह वास्तविक जीवन में होगा - परीक्षण तब मान्य नहीं होगा जब JVM ने उस वास्तविक स्थिति में ऑप्टिमाइज़ नहीं किया है, जिसकी आप रुचि रखते हैं।

हालांकि, यदि आप यह सुनिश्चित करना चाहते हैं कि JVM नहीं है कॉल को हटा दें कि यह संभावित रूप से नो-ऑप्स पर विचार कर सकता है, एक विकल्प परिणाम का उपयोग करना है - इसलिए यदि आप बार-बार System.currentTimeMillis() पर कॉल कर रहे हैं, तो आप सभी रिटर्न मानों को जोड़ सकते हैं और फिर अंत में योग प्रदर्शित कर सकते हैं।

ध्यान दें कि आपके पास अभी भी कुछ पूर्वाग्रह हो सकते हैं - उदाहरण के लिए, कुछ अनुकूलन हो सकते हैं यदि JVM सस्ता रूप से निर्धारित कर सकता है कि अंतिम कॉल के बाद System.currentTimeMillis() पर केवल थोड़ी सी अवधि बीत चुकी है, इसलिए यह एक कैश का उपयोग कर सकता है मूल्य।मैं यह नहीं कह रहा हूं कि वास्तव में मामला यहां है, लेकिन यह ऐसी चीज है जिसके बारे में आपको सोचने की आवश्यकता है। आखिरकार, बेंचमार्क केवल उन भारों का परीक्षण कर सकते हैं जो आप उन्हें देते हैं।

एक अन्य बात पर विचार करना: यह सोचते हैं कि आप एक वास्तविक दुनिया स्थिति है जहाँ कोड एक बहुत चलाया जाता है मॉडल बनाना चाहते हैं तो आप किसी भी समय लेने से पहले एक बहुत कोड चलाना चाहिए, -, क्योंकि हॉटस्पॉट JVM उत्तरोत्तर कठिन अनुकूलित करेंगे और संभवतः आप भारी अनुकूलित संस्करण और पर ध्यान नहीं देते कोडिंग के समय और कोड के "धीमे" संस्करणों को मापना चाहते हैं।

के रूप में स्टीफन उल्लेख किया है, आप लगभग निश्चित रूप से समय बाहर पाश लेना चाहिए ... और वास्तव में उपयोग परिणाम के लिए मत भूलना ...

2

क्या आप मानदंड जैसी लगती है कर रहे हैं, आप इसे सही बनाने के तरीके के बारे में कुछ अच्छी पृष्ठभूमि प्राप्त करने के लिए Robust Java benchmarking पढ़ सकते हैं। कुछ शब्दों में, आपको इसे बंद करने की आवश्यकता नहीं है, क्योंकि यह उत्पादन सर्वर पर क्या नहीं होगा .. इसके बजाय आपको 'वास्तविक' समय अनुमान/प्रदर्शन के करीब जितना संभव हो जाना चाहिए।

// warm up 
for (int j = 0; j < 1000; j++) { 
    for (int i = 0; i < TIMES_TO_ITERATE; i++) 
    { 
     long before1 = getTimeInMilli(); 
     doSomeReallyHardWork(); 
     long after1 = getTimeInMilli(); 
    } 
} 

// measure time 
long before = getTimeInMilli(); 
for (int j = 0; j < 1000; j++) { 
    for (int i = 0; i < TIMES_TO_ITERATE; i++) 
    { 
     long before1 = getTimeInMilli(); 
     doSomeReallyHardWork(); 
     long after1 = getTimeInMilli(); 
    } 
} 
long after = getTimeInMilli(); 

System.out.prinltn("What to expect? " + (after - before)/1000); // average time 

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

public void doIt() { 
    for (int i = 0; i < TIMES_TO_ITERATE; i++) 
    { 
     long before1 = getTimeInMilli(); 
     doSomeReallyHardWork(); 
     long after1 = getTimeInMilli(); 
    } 
} 

// warm up 
for (int j = 0; j < 1000; j++) { 
    doIt() 
} 

// measure time 
long before = getTimeInMilli(); 
for (int j = 0; j < 1000; j++) { 
    doIt(); 
} 
long after = getTimeInMilli(); 

System.out.prinltn("What to expect? " + (after - before)/1000); // average time 

दूसरा दृष्टिकोण अधिक सटीक है, लेकिन यह भी वीएम पर निर्भर करता है। जैसे हॉटस्पॉट "on-stack replacement" कर सकता है, इसका मतलब है कि यदि विधि का कुछ हिस्सा अक्सर निष्पादित किया जाता है तो इसे वीएम द्वारा अनुकूलित किया जाएगा और विधि के निष्पादित होने पर कोड के पुराने संस्करण को ऑप्टिमाइज्ड के साथ आदान-प्रदान किया जाएगा। बेशक यह वीएम पक्ष से अतिरिक्त कार्रवाई करता है। JRockit ऐसा नहीं करता है, कोड का अनुकूलित संस्करण केवल तभी उपयोग किया जाएगा जब इस विधि को फिर से निष्पादित किया जाता है (इसलिए कोई 'रनटाइम' अनुकूलन नहीं है ... मेरा मतलब है कि मेरे पहले कोड नमूने में हर बार पुराना कोड निष्पादित किया जाएगा ... को छोड़कर doSomeReallyHardWork आंतरिक - वे इस विधि से संबंधित नहीं हैं, इसलिए अनुकूलन अच्छी तरह से काम करेगा)।

अद्यतन: प्रश्न में कोड संपादित किया गया था जब मैं जवाब दे रहा था;)

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