I've been experimenting with Node.JS and C++ addons and found that populating an Int32Array is considerably slower when using the C++ addon rather than directly doing so in Node.JS / JavaScript.
Node.JS: 133 ~ ms
C++: 1103 ~ ms
Does anyone know why this is? My test code consists of a fairly large array and for loops containing if statements.
I suspect I'm populating the array incorrectly in my C++ addon. (?)
JavaScript:
var testArray = new Int32Array(36594368);
var i = 0;
for (var xi = 0; xi < 332; xi++) {
for (var yi = 0; yi < 332; yi++) {
for (var zi = 0; zi < 332; zi++) {
if ((xi + yi + zi) % 62 == 0) testArray[i] = 2;
else if (yi < 16) testArray[i] = 2;
else if (yi == 16) testArray[i] = 1;
else testArray[i] = 0;
i++;
}
}
}
C++ Addon:
Local<Int32Array> testArray = Int32Array::New(ArrayBuffer::New(isolate, 4 * 36594368), 0, 36594368);
int i = 0;
for (int xi = 0; xi < 332; xi++) {
for (int yi = 0; yi < 332; yi++) {
for (int zi = 0; zi < 332; zi++) {
if ((xi + yi + zi) % 62 == 0) testArray->Set(i, Integer::New(isolate, 2));
else if (yi < 16) testArray->Set(i, Integer::New(isolate, 2));
else if (yi == 16) testArray->Set(i, Integer::New(isolate, 1));
else testArray->Set(i, Integer::New(isolate, 0));
i++;
}
}
}
EDIT: Just to add, the functions I'm using in my C++ code are V8 functions and weren't defined by myself. Is there another way to set values in an Int32Array without using these?
I'm not surprised this is slow as written, but there is a lot you can do to speed it up. The critical insight is that when dealing with JavaScript typed arrays in node, you can gain access to the memory buffer and operate on that directly.
Though when dealing with normal JavaScript arrays/objects, the following are necessary
Integer::New(isolate,value)
and
testArray->Set(value)
So for example the following line
testArray->Set(i, Integer::New(isolate, 0));
creates a new Number object, converts the integer 0 to a double since all JavaScript numbers are double, calls Set with the Number object, then converts the double back to an integer because it's storing the value in a Int32 typed array, and then destructs the Number object. This happens 3 million times.
But typed arrays are different, and the call GetIndexedPropertiesExternalArrayData gives one access to the underlying buffer, which for a Int32Array is a buffer of int. This allows the C++ function to be re-written to avoid all of those allocations and casts:
void doMkArray(const FunctionCallbackInfo<Value> &args)
{
v8::Isolate *I = v8::Isolate::GetCurrent();
Local<Int32Array> testArray = Int32Array::New(ArrayBuffer::New(I, 4 * 36594368),0,36594368);
int *dptr = (int*)testArray->GetIndexedPropertiesExternalArrayData();
int i = 0;
for (int xi = 0; xi < 332; xi++)
{
for (int yi = 0; yi < 332; yi++)
{
for (int zi = 0; zi < 332; zi++)
{
if ((xi + yi + zi) % 62 == 0) dptr[i] = 2;
else if (yi < 16) dptr[i] = 2;
else if (yi == 16) dptr[i] = 1;
else dptr[i] = 0;
i++;
}
}
}
args.GetReturnValue().Set(testArray);
}
Replacing with the above makes things faster, but how much faster needs a test. The following package can be cloned and when run (using node 0.12.5) results in the following
Performance Tests
✓ via javascript (169ms)
✓ via c++ (141ms)
So that alone makes using C++ faster, but maybe not all that amazing, but if both the Javascript and the C++ loops (see the src) are commented out, and when only the array allocation is included:
void doMkArray(const FunctionCallbackInfo<Value> &args)
{
v8::Isolate *I = v8::Isolate::GetCurrent();
Local<Int32Array> testArray = Int32Array::New(ArrayBuffer::New(I, 4
/*
...
Then the time changes to
Performance Tests
✓ via javascript (62ms)
✓ via c++ (80ms)
In other words, simply allocating the array takes approximately 60ms in JavaScript, and 80ms in the C++ module. But that means that the rest of the time is the time spent in the loop, which is approximately 60ms in C++ and 110ms in Javascript. And so for actions that are predominately loops and calculations using direct buffer access, C++ is preferred.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With