Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
238 views
in Technique[技术] by (71.8m points)

javascript - Why V8 in Node.JS is faster than in my native C++ addon?

Why Google's V8 JavaScript engine in my C++ addon works significantly slower than in Node.JS?

I've tried to write some stupidly simple code for generating prime numbers in the JavaScript and ran it in V8 via my C++ addon and directly in Node.JS.

I was quite shocked, because both should be using the same JavaScript engine and both have executed the same code (time in milliseconds, less is better):

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

Here is the source of JavaScript module and source of C++ addon that runs same JavaScript code (and I think problem not in the interop, because measuring of time works directly in JS):

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;
"
        "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();
"
        "time = end - start;
";

    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);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In the C++ version all variables declared in the script source (result, primeNumberCounter, i, j, isPrime, start, end, time) are global because script's top level scope is global scope.

For optimizing compiler it is easy to allocate local variables into machine registers (or spill slots on stack) and keep track of their type. Working with global variables on the other hand requires constant memory accesses and type checks because V8 does not (currently) perform a register promotion optimization.

If you wrap the source into an immediately called function difference should go away.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...