জেডি কে কোড চালাওয়ার সময় জাভা জেআইটি কি প্রতারণা করে?


405

আমি কিছু কোড বেঞ্চমার্কিং করছিলাম, এবং java.math.BigIntegerঠিক একই অ্যালগরিদম ব্যবহার করার পরেও আমি এটির সাথে দ্রুত চালানো পেতে পারি না । সুতরাং আমি java.math.BigIntegerউত্সটি আমার নিজস্ব প্যাকেজে অনুলিপি করে দেখেছি :

//import java.math.BigInteger;

public class MultiplyTest {
    public static void main(String[] args) {
        Random r = new Random(1);
        long tm = 0, count = 0,result=0;
        for (int i = 0; i < 400000; i++) {
            int s1 = 400, s2 = 400;
            BigInteger a = new BigInteger(s1 * 8, r), b = new BigInteger(s2 * 8, r);
            long tm1 = System.nanoTime();
            BigInteger c = a.multiply(b);
            if (i > 100000) {
                tm += System.nanoTime() - tm1;
                count++;
            }
            result+=c.bitLength();
        }
        System.out.println((tm / count) + "nsec/mul");
        System.out.println(result); 
    }
}

আমি যখন এটি চালনা করি (ম্যাকোজে 1.8.0_144-b01 jdk) এটি আউটপুট দেয়:

12089nsec/mul
2559044166

আমি যখন এটিকে আমদানি লাইনটি নিরবিচ্ছিন্নভাবে চালিত করি তখন:

4098nsec/mul
2559044166

আমার সংস্করণ বনাম বিগইন্টেজারের জেডিকে সংস্করণ ব্যবহার করার সময় এটি প্রায় তিনগুণ দ্রুত, যদিও এটি সঠিক কোডটি ব্যবহার করে।

আমি জাভাপের সাথে বাইটকোড পরীক্ষা করেছি এবং অপশনগুলির সাথে চলাকালীন কম্পাইলার আউটপুট তুলনা করেছি:

-Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions 
-XX:+PrintInlining -XX:CICompilerCount=1

এবং উভয় সংস্করণ একই কোড উত্পন্ন বলে মনে হচ্ছে। তাহলে হটস্পট কি এমন কিছু প্রাক্পম্পিউটিড অপটিমাইজেশন ব্যবহার করছে যা আমি আমার কোডটিতে ব্যবহার করতে পারি না? আমি সবসময় বুঝতে পারি যে তারা তা করে না। এই পার্থক্য কী ব্যাখ্যা করে?


29
মজাদার. 1. ফলাফল কি সামঞ্জস্যপূর্ণ (বা কেবল ভাগ্যবান এলোমেলো)? ২. আপনি কী জেভিএম গরম করার পরে চেষ্টা করতে পারেন? ৩. আপনি কি এলোমেলো ফ্যাক্টরটি নির্মূল করতে পারেন এবং উভয় পরীক্ষার জন্য ইনপুট হিসাবে একই ডেটাসেট সরবরাহ করতে পারেন?
জিগার জোশী

7
আপনি কী জেএমএইচ openjdk.java.net/projects/code-tools/jmh দিয়ে আপনার বেঞ্চমার্কটি চালানোর চেষ্টা করেছিলেন ? ম্যানুয়ালি সঠিকভাবে পরিমাপ করা এত সহজ নয় (উষ্ণতা এবং সমস্ত জিনিস)।
রোমান পুচকোভস্কি

2
হ্যাঁ এটি খুব সামঞ্জস্যপূর্ণ। যদি আমি এটি 10 ​​মিনিটের জন্য চালাতে দেয় তবে আমি এখনও একই পার্থক্য পাই। স্থির র্যান্ডম বীজ নিশ্চিত করে যে উভয় রান একই ডেটাসেট পেয়েছে।
কোএন হেন্ডরিক্স

5
আপনি সম্ভবত এখনও জেএমএইচ চান, সেক্ষেত্রে। এবং আপনার নিজের সংশোধিত বিগআইন্টেগারটি অন্য কোথাও স্থাপন করা উচিত যাতে লোকেরা আপনার পরীক্ষাটি পুনরুত্পাদন করতে পারে এবং যা যা মনে হয় আপনি যা চালাচ্ছেন তা যাচাই করতে পারে।
পিভিজি

উত্তর:


528

হ্যাঁ, হটস্পট জেভিএম হ'ল ধরণের "প্রতারণা", কারণ এটির কয়েকটি BigIntegerপদ্ধতির একটি বিশেষ সংস্করণ রয়েছে যা আপনি জাভা কোডে পাবেন না। এই পদ্ধতিগুলিকে জেভিএম অন্তর্নিহিত বলা হয় ।

বিশেষত BigInteger.multiplyToLenহটস্পটে একটি ইনস্ট্রিনসিক পদ্ধতি। জেভিএম উত্স বেসে একটি বিশেষ হ্যান্ড-কোডেড অ্যাসেমব্লিকেশন বাস্তবায়ন রয়েছে তবে কেবল x86-64 আর্কিটেকচারের জন্য।

আপনি জেভিএমকে -XX:-UseMultiplyToLenIntrinsicখাঁটি জাভা প্রয়োগে ব্যবহার করতে বাধ্য করার বিকল্প সহ এই ইনস্ট্রিনসিকটি অক্ষম করতে পারেন। এই ক্ষেত্রে পারফরম্যান্সটি আপনার অনুলিপি কোডের পারফরম্যান্সের সাথে সমান হবে।

পিএস এখানে অন্যান্য হটস্পট অভ্যন্তরীণ পদ্ধতির তালিকা রয়েছে।


141

ইন জাভা 8 এই সত্যিই একটি স্বকীয় পদ্ধতি; পদ্ধতির একটি সামান্য পরিবর্তিত সংস্করণ:

 private static BigInteger test() {

    Random r = new Random(1);
    BigInteger c = null;
    for (int i = 0; i < 400000; i++) {
        int s1 = 400, s2 = 400;
        BigInteger a = new BigInteger(s1 * 8, r), b = new BigInteger(s2 * 8, r);
        c = a.multiply(b);
    }
    return c;
}

এটি দিয়ে চালানো:

 java -XX:+UnlockDiagnosticVMOptions  
      -XX:+PrintInlining 
      -XX:+PrintIntrinsics 
      -XX:CICompilerCount=2 
      -XX:+PrintCompilation   
       <YourClassName>

এটি প্রচুর লাইন প্রিন্ট করবে এবং এর মধ্যে একটি হ'ল:

 java.math.BigInteger::multiplyToLen (216 bytes)   (intrinsic)

ইন জাভা 9 অন্যদিকে পদ্ধতি আর একটি স্বকীয় হতে হবে বলে মনে হয়, কিন্তু ঘুরে এটি একটি পদ্ধতি যা একটি স্বকীয় হয় কল:

 @HotSpotIntrinsicCandidate
 private static int[] implMultiplyToLen

সুতরাং জাভা 9 এর অধীনে একই কোড চালানো (একই পরামিতি সহ) প্রকাশ করবে:

java.math.BigInteger::implMultiplyToLen (216 bytes)   (intrinsic)

পদ্ধতির জন্য এটি একই কোডের নীচে - কিছুটা আলাদা নামকরণ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.