Pourquoi le code Java généré pour effectuer une course de fonctionnement plus lentement qu'une « boucle interprète »?

StackOverflow https://stackoverflow.com/questions/875695

Question

J'ai un code Java qui effectue des opérations de manipulation de bits sur un BitSet. J'ai une liste d'opérations et peut « interpréter » les par-dessus les boucles, mais il est important pour moi que je puisse effectuer ces opérations le plus rapidement possible, donc j'ai essayé de générer dynamiquement du code pour les appliquer. Je produis source de Java pour effectuer les opérations et compiler une classe implémentant ces opérations en utilisant Javassist.

Malheureusement, mon code généré dynamiquement est plus lent que le code interprété. Il semble que ce soit parce que HotSpot optimise le code interprété, mais n'optimise le code compilé: Après l'exécuter quelques milliers de fois, mon code interprété fonctionne deux fois plus vite qu'il a fait au début, mais mon code compilé ne montre aucun gain de vitesse. Conformément à cette hypothèse, mon code interprété est d'abord plus lent que le code compilé, mais est finalement plus rapide.

Je ne sais pas pourquoi cela se passe. Je pense que peut-être Javassist utilise un chargeur de classes dont les classes HotSpot ne touche pas. Mais je ne suis pas expert sur le chargement des classes en Java, donc je ne suis pas sûr que ce soit une estimation raisonnable ou comment s'y prendre pour le tester. Voici comment je créer et charger la classe avec Javassist:

ClassPool pool = ClassPool.getDefault();
CtClass tClass = pool.makeClass("foo");

// foo implements MyInterface, with one method
tClass.addInterface(pool.get(MyInterface.class.getName()));

// Get the source for the method and add it
CtMethod tMethod = CtNewMethod.make(getSource(), tClass);
tClass.addMethod(tMethod);

// finally, compile and load the class
return (MyInterface)tClass.toClass().newInstance();

Quelqu'un at-il une idée de ce qui se passe ici? J'apprécierais vraiment tout ce que vous pouvez donner de l'aide.

J'utilise la machine virtuelle Java du serveur Sun 1.6 sur Windows XP 32 bits.

Était-ce utile?

La solution

HotSpot ne se soucie pas où le code vient. Par exemple, il va heureusement le code en ligne appelé par un appel de méthode virtuelle avec une mise en œuvre chargée par un chargeur de classes différentes.

Je vous suggère d'écrire dans le code source des opérations que vous essayez d'effectuer cette référence, et ensuite de référence qui. Il est généralement plus facile d'écrire un exemple de code généré plutôt que d'écrire le générateur de toute façon.

un certain nombre de raisons pour lesquelles HotSpot pourrait ne pas optimiser le code aussi difficile que cela pourrait. Par exemple très longues méthodes auront tendance à ne pas être inline ou ont méthode inline en eux.

Autres conseils

Je pense que je comprends ce qui se passait ici. Ma première erreur générait des méthodes qui étaient trop longues. Après avoir fixé, je remarque que même si mon code généré était encore plus lent, il a finalement approché la vitesse du code interprété.

Je pense que le plus gros gain de vitesse vient ici de HotSpot optimiser mon code. Dans la version interprétée, il y a très peu de code pour optimiser, si HotSpot prend rapidement en charge. Dans la version produite, il y a beaucoup de code pour optimiser, si HotSpot prend plus de temps travailler sa magie sur tout le code.

Si je lance mes repères assez longtemps, je vois mon code généré effectuer juste un peu mieux que le code interprété.

Il y a un paramètres JVM qui contrôle rapide du code doit être compilé -XX: CompileThreshold = 10000

  

Nombre d'invocations de méthode / branches avant de compiler [-client: 1500]

Je ne sais pas si cela vous aidera, parce que dans votre exemple, la taille semblent jouer un rôle vital.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top