Les performances de la compilation vs interprété javascript dans java7 / Rhino
J'ai un problème avec la performance de Rhino moteur javascript Java7, peu de temps - mon script (qui analyse et compile des textes) s'exécute dans le navigateur Chrome autour de 50 à 100 fois plus rapide que la même en Java7 Rhino moteur de script.
J'ai essayé de trouver le moyen d'améliorer la situation et ont constaté que la Rhino prend en charge la compilation des scripts. J'ai essayé de le faire avec mes scripts et en fait ne vois aucune amélioration. Enfin - j'ai fini avec un mannequin d'essai de suite où je ne vois aucune différence de performance entre compilé et interprété versions. S'il vous plaît laissez-moi savoir ce que j'avais fait de mal.
Remarque: certaines sources mentionnent que le Rhino moteur tourne script compilé environ 1,6 plus lent que le "même" code écrit directement en Java. Vous ne savez pas si la "compilation de script" utilisé dans cet exemple est le même que celui qui est censé là.
De Test de la classe java est ci-dessous et exemple de résultat que j'obtiens sur ma machine ...
Résultats
À l'aide d'com.sun.script.javascript.RhinoScriptEngine@c50443 ... temps: 886ms, chars: 38890, somme: 2046720 temps: 760ms, chars: 38890, somme: 2046720 temps: 725ms, chars: 38890, somme: 2046720 temps: 765ms, chars: 38890, somme: 2046720 temps: 742ms, chars: 38890, somme: 2046720 ... 3918ms À l'aide d'com.sun.script.javascript.RhinoCompiledScript@b5c292 @ com.sun.script.javascript.RhinoScriptEngine@f92ab0 ... temps: 813ms, chars: 38890, somme: 2046720 temps: 805ms, chars: 38890, somme: 2046720 temps: 812ms, chars: 38890, somme: 2046720 temps: 834ms, chars: 38890, somme: 2046720 temps: 807ms, chars: 38890, somme: 2046720 ... 4101ms
mise à Jour après le commentaire de Anon-Micro:
Après avoir décroché l'appel du JavaScript eval() et de compiler() dans la classe de test en ...
import sun.org.mozilla.javascript.internal.Context;
try {
Context cx = Context.enter();
cx.setOptimizationLevel(9);
cx.setLanguageVersion(170);
...
}
finally {
Context.exit();
}
résultat changé signigicantly - à partir de la moyenne de 1,8 (dans la nouvelle version de la classe de test) s à ~150msec. Cependant instance de la doTest() la fonction extraite de ScriptEngine chargé par (CompiledScript = Compilable.compile()).eval(Bindings) -> Bindings.get("doTest")
toujours dit que c'est sun.org.mozilla.javascript.internal.InterpretedFunction
et ses performances sont légèrement inférieures (environ 10%) que la version de JS chargé de la pré-compilé en bytecode (par Rhino 1.7r4) - donc, je ne suis toujours pas sûr de ce qui se passe réellement derrière la scène.
1800ms - ScriptEngine.eval(), Optimization Level = default(-1?)
1758ms - CompiledScript, Optimization Level = default(-1?)
165ms - ScriptEngine.eval(), Optimization Level = 9
132ms - CompiledScript, Optimization Level = 9
116ms - compiled by Rhino 1.7r4 into bytecode class
PS: le soleil.org.mozilla.le javascript.interne.Contexte au sein de soleil interne du package air d'être un drôle de conception de moi - l '"intérieur" désigne cette classe est présumé ne pas être utilisé par les développeurs et à cet effet, il n'est pas "certifié" façon de manipuler le niveau d'optimisation de la JS évaluateur dans Java 7.
de la classe de Test (mise à jour, doTestCompiled est chargé à partir externes *.classe)
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;
import sun.org.mozilla.javascript.internal.Context;
import sun.org.mozilla.javascript.internal.Scriptable;
import sun.org.mozilla.javascript.internal.Function;
public class RhinoPerfTest4 {
final static ScriptEngineManager scm = new ScriptEngineManager();
final static String TEST_SCRIPT1 =
"function doTest() {\n"
+ " var scale = 5000, i, a = [], str, l, sum = 0,\n"
+ " start = (new Date()).getTime(), end;\n"
+ " for( i = 0; i < scale; i++ )\n"
+ " a.push(\"\" + i);\n"
+ " str = a.join(\"\");\n"
+ " l = str.length;\n"
+ " for( i = 0; i < l; i++ ) {\n"
+ " var c = str.charCodeAt(i);\n"
+ " if( c > 0)\n"
+ " sum += c;\n"
+ " }\n"
+ " end = (new Date()).getTime();\n"
+ "\n"
+ " //print(\" time: \" + (end - start) "
+ " + \"ms, chars: \" + l "
+ " + \", sum: \" + sum + \"\\n\");\n"
+ "}\n";
final static String TEST_SCRIPT2 =
"function doTest() {\n"
+ " var a = [], i;\n"
+ " for( i = 0; i < 500; i++ ) a.push(1);\n"
+ "}\n";
static class TestSet {
public int nCycles;
public String script;
public TestSet(int nCycles, String script) {
this.nCycles = nCycles;
this.script = script;
}
}
static TestSet set1 = new TestSet(5, TEST_SCRIPT1);
static TestSet set2 = new TestSet(500, TEST_SCRIPT2);
public static void main(String[] args) throws Exception {
ScriptEngine se;
int i;
long ts, te;
TestSet set = set1;
Object noArgs[] = new Object[]{};
try {
org.mozilla.javascript.Context mctx = org.mozilla.javascript.Context.enter();
se = scm.getEngineByExtension("js");
doTestCompiled doTestPreCompiled = new doTestCompiled();
org.mozilla.javascript.Scriptable scope = mctx.initStandardObjects();
doTestPreCompiled.call(mctx, scope, scope, null);
org.mozilla.javascript.Function doTest =
(org.mozilla.javascript.Function)scope.get("doTest", null);
for( int nHotSpot = 0; nHotSpot < 5; nHotSpot++ ) {
if( nHotSpot > 0 )
Thread.sleep(500);
ts = System.currentTimeMillis();
for( i = 0; i < set.nCycles; i++ ) {
doTest.call(mctx, scope, null, null);
}
te = System.currentTimeMillis();
System.out.println(" " + nHotSpot + ": " + (te - ts) + "ms");
}
}
finally {
org.mozilla.javascript.Context.exit();
}
for( int nOpt = 0; nOpt < 2; nOpt++ ) {
if( nOpt > 0 )
Thread.sleep(500);
Context cx = null;
try {
System.out.println("Cycle: " + nOpt);
cx = Context.enter();
if( nOpt > 0 ) {
System.out.println("OptLevel: " + 9);
cx.setOptimizationLevel(9);
cx.setLanguageVersion(170);
}
se = scm.getEngineByExtension("js");
se.eval(set.script);
System.out.println("\nRunning via " + se + " ... ");
Invocable invocable = (Invocable) se;
for( int nHotSpot = 0; nHotSpot < 5; nHotSpot++ ) {
if( nHotSpot > 0 )
Thread.sleep(500);
ts = System.currentTimeMillis();
for( i = 0; i < set.nCycles; i++ ) {
invocable.invokeFunction("doTest", noArgs);
}
te = System.currentTimeMillis();
System.out.println(" " + nHotSpot + ": " + (te - ts) + "ms");
}
se = scm.getEngineByExtension("js");
Compilable cse = (Compilable) se;
CompiledScript cs = cse.compile(set.script/* + "(doTest())"*/);
Scriptable scope = cx.initStandardObjects();
ScriptContext scriptContext = new SimpleScriptContext();
Bindings vars = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
cs.eval(vars);
Object odoTest = scriptContext.getAttribute("doTest");
Function doTest = (Function) vars.get("doTest");
System.out.println("\nRunning via " + cs + " @ " + se + " ... ");
for( int nHotSpot = 0; nHotSpot < 5; nHotSpot++ ) {
if( nHotSpot > 0 )
Thread.sleep(500);
ts = System.currentTimeMillis();
for( i = 0; i < set.nCycles; i++ ) {
doTest.call(cx, scope, null, noArgs);
}
te = System.currentTimeMillis();
System.out.println(" " + nHotSpot + ": " + (te - ts) + "ms");
}
}
finally {
if( cx != null )
Context.exit();
}
}
}
}
OriginalL'auteur Xtra Coder | 2013-01-26
Vous devez vous connecter pour publier un commentaire.
Le Rhino moteur est en fait capable de compiler des scripts en bytecode "in-process", de sorte que vous n'avez pas besoin d'exécuter l'outil pour générer .les fichiers de classe de première. Vous avez seulement besoin de mettre de "l'optimisation" de niveau et le moteur sera automatiquement pré-compiler le script avant de l'exécuter. Une façon de remplacer l'optimisation du niveau de la machine virtuelle de l'argument-Drhino.opt.niveau. Définir ce à quoi que ce soit entre 0 et 9 et exécuter l'original de votre programme de test et vous devriez voir de meilleures performances.
C'est la même configuration optimisation utilisé par l'outil de compilation que vous avez mentionné, par la manière. https://developer.mozilla.org/en-US/docs/Rhino/Optimization
Pour un contrôle total de l'optimisation du niveau et de la version javascript dans votre programme, vous pouvez effectuer les opérations suivantes. Cependant, vous perdez une partie des règlages que RhinoScriptEngine classe (qui est juste un environnement wrapper et pas le moteur javascript). L'un de ces parage est la "imprimer" de la fonction qui est en fait injecté par le wrapper. À des fins de test, vous pouvez simplement remplacer "imprimer" avec " java.lang.Système..print".
Vous avez mentionné les éléments suivants:
Je serais intéressé par la source qui a signalé cette, Ma fonction de fibonacci en java prend environ 1/30 le temps que la compilation des js de mise en œuvre. Mais peut-être que je suis absent quelque chose.
OriginalL'auteur Anon-Micro
J'ai trouvé que pour des programmes simples, au moins, le temps supplémentaire passé à la compilation de votre code peut faire de l'ombre au moment de l'exécution. Alors n'oubliez pas, il faut un peu de temps avant de HotSpot compile le bytecode Java en code natif.
Je pense que si vous avez utilisé plus de course de référence avec un code plus complexe (par opposition à un nombre relativement simple programme qui fait beaucoup d'appels de bibliothèque) la version compilée finira par gagner, mais la performance tout de même de ne pas être comparable à des V8.
Oracle travaille sur un nouveau moteur EcmaScript pour Java 8 qui devrait être plus rapide, mais ça va être un certain temps avant qu'il soit disponible.
OriginalL'auteur Matthew Crumley
On dirait que j'ai trouvé quel est le problème de compilation utilisé dans " mon "code (en fait prises à partir d'internet échantillons) n'a rien à voir avec "compilé'.
Enfin j'ai sur ce lien - https://developer.mozilla.org/en-US/docs/Rhino_JavaScript_Compiler - le Rhino outil pour compiler .js .classe. J'ai le résultat suivant avec le même code JS exécution en mode compilé .classe du bytecode:
(c'est à peu près 10 fois plus rapide)
et c'est le résultat de Chrome:
(la moyenne est de 3 à 4 ms, ~15 plus rapide que Java compilé/Rhino, et ~200 fois plus rapide que celui interprété Java/Rhino).
OriginalL'auteur Xtra Coder