2013-03-13 8 views
27

Warum Googles V8-JavaScript-Engine in meinem C++ - Addon funktioniert wesentlich langsamer als in Node.JS?Warum ist V8 in Node.JS schneller als in meinem nativen C++ - Addon?

Ich habe versucht, einige dumm einfache Code zum Generieren von Primzahlen im JavaScript zu schreiben und lief es in V8 über meine C++ - Addon und direkt in Node.JS.

war ich ziemlich schockiert, weil beide den gleichen JavaScript-Engine sein sollten und beide haben den gleichen Code ausgeführt (Zeit in Millisekunden, weniger ist besser):

V8 in Node.JS: 495517 
V8 in Node.JS C++ Addon: 623598 

Hier ist die Quelle des JavaScript-Modul ist und Quelle für C++ Addon, das läuft gleichen JavaScript-Code (und ich denke Problem nicht in der Interop, weil die Zeitmessung direkt in JS funktioniert):

index.js:

var jsInNodeJsPrimeGeneratorBenchmark = require("./javascript.js"); 
var jsInNativePrimeGeneratorBenchmark = require("./native"); 

console.log("V8 in Node.JS: ", jsInNodeJsPrimeGeneratorBenchmark.primeGeneratorBenchmark()); 
console.log("V8 in Node.JS C++ Addon: ", jsInNativePrimeGeneratorBenchmark.primeGeneratorBenchmark()); 

javascript.js:

function primeGeneratorBenchmark() { 
    var result, primeNumberCounter, i, j, isPrime, start, end; 

    i = 3; 
    primeNumberCounter = 1; 

    start = Date.now(); 

    while (primeNumberCounter < 100000) { 
     isPrime = true; 
     for (j = 2; j < i; j++) { 
      if (i % j === 0) { 
       isPrime = false; 
       break; 
      } 
     } 

     if (isPrime) { 
      result = i; 
      primeNumberCounter++; 
     } 

     i++; 
    } 

    end = Date.now(); 

    return end - start; 
} 

exports.primeGeneratorBenchmark = primeGeneratorBenchmark; 

native.cpp:

#include <node.h> 

v8::Handle<v8::Value> primeGeneratorBenchmark(const v8::Arguments &arguments); 
void registerModule(v8::Handle<v8::Object> target); 

v8::Handle<v8::Value> primeGeneratorBenchmark(const v8::Arguments &arguments) { 
    v8::HandleScope handleScope; 

    v8::Local<v8::Context> context = arguments.Holder()->CreationContext(); 

    v8::Context::Scope scope(context); 

    const char *sourceStringC = 
     "var result, primeNumberCounter, i, j, isPrime, start, end, time;\n" 
     "i = 3;\n" 
     "primeNumberCounter = 1;\n" 
     "start = Date.now();\n" 
     "while (primeNumberCounter < 100000) {\n" 
     " isPrime = true;\n" 
     " for (j = 2; j < i; j++) {\n" 
     "  if (i % j === 0) {\n" 
     "   isPrime = false;\n" 
     "   break;\n" 
     "  }\n" 
     " }\n" 
     " if (isPrime) {\n" 
     "  result = i;\n" 
     "  primeNumberCounter++;\n" 
     " }\n" 
     " i++;\n" 
     "}\n" 
     "end = Date.now();\n" 
     "time = end - start;\n"; 

    v8::Local<v8::String> sourceStringV8 = v8::String::New(sourceStringC); 

    v8::Local<v8::Script> script = v8::Script::Compile(sourceStringV8); 
    script->Run(); 

    v8::Local<v8::Value> timeResult = v8::Context::GetCurrent()->Global()->Get(v8::String::New("time")); 

    return handleScope.Close(timeResult); 
} 

void registerModule(v8::Handle<v8::Object> target) { 
    target->Set(v8::String::NewSymbol("primeGeneratorBenchmark"), v8::FunctionTemplate::New(primeGeneratorBenchmark)->GetFunction()); 
} 

NODE_MODULE(native, registerModule); 
+1

Nur ein interessanter Gedanke: Was sind die Ergebnisse, wenn Sie den gleichen Algorithmus in C++ implementieren, anstatt V8 zu bitten, es in JS zu parsen und auszuführen? – Venemo

Antwort

38

in der C++ Version alle Variablen im Skript Quelle deklariert (result, primeNumberCounter, i, j, isPrime , start, Ende, time) sind global, da der oberste Bereich des Skripts der globale Bereich ist.

Zum Optimieren des Compilers ist es einfach, lokale Variablen in Maschinenregistern (oder Überlauf-Slots auf Stapel) zuzuordnen und deren Typ zu verfolgen. Das Arbeiten mit globalen Variablen erfordert dagegen konstante Speicherzugriffe und Typprüfungen, da V8 (derzeit) keine Register-Promotion-Optimierung durchführt.

Wenn Sie die Quelle in eine sofort aufgerufene Funktion umbrechen, sollte die Differenz verschwinden.

+3

Danke, Vyacheslav, du hast meine Zeit gerettet! Ich habe alles in anonyme Funktion eingepackt, die sich sofort selbst aufruft und C++ Addon läuft manchmal noch schneller. Ich habe die Variable 'time' im globalen Bereich verlassen, um meine Ergebnisse zu erhalten, ohne meinen C++ Code neu schreiben zu müssen. –

+0

das hat mir geholfen für dich +1 zu geben. –

Verwandte Themen