Eu estava comparando algum código e não consegui executá-lo tão rápido quanto antes java.math.BigInteger
, mesmo usando o mesmo algoritmo. Então, copiei o java.math.BigInteger
código-fonte no meu próprio pacote e tentei o seguinte:
//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);
}
}
Quando eu executo isso (jdk 1.8.0_144-b01 no MacOS), ele gera:
12089nsec/mul
2559044166
Quando o executo com a linha de importação não comentada:
4098nsec/mul
2559044166
É quase três vezes mais rápido ao usar a versão JDK do BigInteger em relação à minha versão, mesmo que esteja usando exatamente o mesmo código.
Examinei o bytecode com javap e comparei a saída do compilador ao executar com as opções:
-Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining -XX:CICompilerCount=1
e ambas as versões parecem gerar o mesmo código. Então, o hotspot está usando algumas otimizações pré-computadas que não posso usar no meu código? Eu sempre entendi que eles não. O que explica essa diferença?
fonte
Respostas:
Sim, o HotSpot JVM é uma espécie de "trapaça", porque possui uma versão especial de alguns
BigInteger
métodos que você não encontra no código Java. Esses métodos são chamados de intrínsecos da JVM .Em particular,
BigInteger.multiplyToLen
é um método instrínseco no HotSpot. Há uma implementação de montagem codificada manualmente na base de origem da JVM, mas apenas para a arquitetura x86-64.Você pode desativar este instrinsic com a
-XX:-UseMultiplyToLenIntrinsic
opção de forçar a JVM a usar a implementação Java pura. Nesse caso, o desempenho será semelhante ao desempenho do seu código copiado.PS Aqui está uma lista de outros métodos intrínsecos do HotSpot.
fonte
No Java 8, esse é realmente um método intrínseco; uma versão ligeiramente modificada do método:
Executando isso com:
Isso imprimirá muitas linhas e uma delas será:
No Java 9, por outro lado, esse método parece não ser mais intrínseco, mas, por sua vez, chama um método que é intrínseco:
Portanto, a execução do mesmo código no Java 9 (com os mesmos parâmetros) revelará:
Abaixo, está o mesmo código do método - apenas uma nomeação ligeiramente diferente.
fonte