J'étalonnais du code et je ne pouvais pas le faire fonctionner aussi vite qu'avec java.math.BigInteger
, même en utilisant exactement le même algorithme. J'ai donc copié la java.math.BigInteger
source dans mon propre package et essayé ceci:
//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);
}
}
Lorsque je lance ceci (jdk 1.8.0_144-b01 sur MacOS), il génère:
12089nsec/mul
2559044166
Lorsque je l'exécute avec la ligne d'importation sans commentaire:
4098nsec/mul
2559044166
C'est presque trois fois plus rapide lorsque vous utilisez la version JDK de BigInteger par rapport à ma version, même si elle utilise exactement le même code.
J'ai examiné le bytecode avec javap et comparé la sortie du compilateur lors de l'exécution avec des options:
-Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining -XX:CICompilerCount=1
et les deux versions semblent générer le même code. Le hotspot utilise-t-il des optimisations précalculées que je ne peux pas utiliser dans mon code? J'ai toujours compris que non. Qu'est-ce qui explique cette différence?
la source
Réponses:
Oui, HotSpot JVM est une sorte de "tricherie", car il a une version spéciale de certains
BigInteger
méthodes que vous ne trouverez pas dans le code Java. Ces méthodes sont appelées intrinsèques JVM .En particulier,
BigInteger.multiplyToLen
est une méthode intrinsèque dans HotSpot. Il y a un spécial implémentation d'assemblage codée à la main dans la base de la source JVM, mais uniquement pour l'architecture x86-64.Vous pouvez désactiver cette instruction avec
-XX:-UseMultiplyToLenIntrinsic
option pour forcer JVM à utiliser une implémentation Java pure. Dans ce cas, les performances seront similaires à celles de votre code copié.PS Voici une liste d'autres méthodes intrinsèques HotSpot.
la source
En Java 8, il s'agit en effet d'une méthode intrinsèque; une version légèrement modifiée de la méthode:
Exécuter ceci avec:
Cela imprimera beaucoup de lignes et l'une d'elles sera:
En Java 9, en revanche, cette méthode ne semble plus être intrinsèque, mais à son tour, elle appelle une méthode intrinsèque:
Donc, exécuter le même code sous Java 9 (avec les mêmes paramètres) révélera:
En dessous, c'est le même code pour la méthode - juste un nom légèrement différent.
la source