IT이야기

Java JIT는 JDK 코드를 실행할 때 부정행위를 합니까?

cyworld 2022. 6. 2. 21:33
반응형

Java JIT는 JDK 코드를 실행할 때 부정행위를 합니까?

몇 가지 코드를 벤치마킹하고 있었는데, 같은 알고리즘을 사용해도 와 같은 속도로 실행할 수 없었습니다.그래서 소스를 내 패키지에 복사하고 다음을 시도했습니다.

//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); 
    }
}

이것을 실행하면(MacOS에서는 jdk 1.8.0_144-b01) 다음과 같이 출력됩니다.

12089nsec/mul
2559044166

Import 행에 코멘트 없이 실행하는 경우:

4098nsec/mul
2559044166

BigInteger의 JDK 버전을 사용하면 동일한 코드를 사용하더라도 거의 3배 더 빠릅니다.

javap을 사용하여 바이트 코드를 조사하고 옵션과 함께 실행할 때의 컴파일러 출력을 비교했습니다.

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

두 버전 모두 동일한 코드를 생성하는 것 같습니다.핫스팟은 코드에 사용할 수 없는 미리 계산된 최적화를 사용하고 있습니까?나는 그들이 그렇지 않다는 것을 항상 이해했다.무엇이 이 차이를 설명합니까?

네, HotSpot JVM은 특별한 버전의 HotSpot JVM이 있기 때문에 일종의 "사기"입니다.BigIntegerJava 코드에서는 찾을 수 없는 메서드입니다.이러한 방법을 JVM 내장이라고 합니다.

특히,BigInteger.multiplyToLen는 HotSpot의 instrinsic 메서드입니다.JVM 소스 기반에는 x86-64 아키텍처 전용으로 특별한 수동 코드 어셈블리가 구현되어 있습니다.

이 instrinsic을 디세블로 할 수 있습니다.-XX:-UseMultiplyToLenIntrinsicJVM이 순수 Java 구현을 사용하도록 강제하는 옵션입니다.이 경우 성능은 복사한 코드의 성능과 비슷합니다.

추신: 다음은 다른 HotSpot 고유 메서드 목록입니다.

Java 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)

반면 Java 9에서는 이 메서드가 더 이상 본질적인 메서드가 아닌 것처럼 보이지만, 결국 본질적인 메서드를 호출합니다.

 @HotSpotIntrinsicCandidate
 private static int[] implMultiplyToLen

따라서 Java 9에서 동일한 코드(같은 파라미터)를 실행하면 다음과 같은 결과가 나타납니다.

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

그 아래에는 메서드 코드와 이름이 약간 다를 뿐입니다.

언급URL : https://stackoverflow.com/questions/45912510/does-java-jit-cheat-when-running-jdk-code

반응형