Why is this NodeJS 2x faster than native C?
Adding the register key word helps as expected
#include <stdio.h>
#include <time.h>
int main () {
register long i, d;
clock_t start = clock();
i = d = 0L;
for (i = 0; i < 100000000L; i++) {
d += i >> 1;
}
clock_t end = clock();
clock_t elapsed = (end - start) / (CLOCKS_PER_SEC / 1000);
printf("%ld\n", d);
printf("%lu\n", elapsed);
}
and compile with the C compiler
cc for.c -o for
./for ; node for.js
returns
2499999950000000
97
2499999950000000
222
This begs the question, how is it that the native C settings are not optimized as much as a Javascript compiler?
Since C is statically-compiled and linked, requiring a potentially lengthy build step of your entire codebase (I once worked in one that took almost an hour for a full optimized build, but only 10 minutes otherwise), and a very dangerous, hardware-level language that risks a lot of undefined behaviors if you don't treat it with care, the default settings of compilers usually don't optimize to smithereens since that's a developer/debug build intended to help with debugging and productivity with faster turnaround.
So in C you get a distinct separation between an unoptimized but faster-to-build, easier-to-debug developer/debug build and a very optimized, slower-to-build, harder-to-debug production/release build that runs really fast, and the default settings of compilers often favor the former.
With something like v8/NodeJS, you're dealing with a just-in-time compiler (dynamic compilation) that builds and optimizes only the necessary code on the fly at run-time. On top of that, JS is a much safer language and also often designed for security that doesn't allow you to work at the raw bits and bytes of the hardware.
As a result, it doesn't need that kind of strong release/debug build distinction of a native, statically-compiled language like C/C++. But it also doesn't let you put the pedal to the metal as you can in C if you really want.
A lot of people trying to benchmark C/C++ coming from other languages often fail to understand this build distinction and the importance of compiler/linker optimization settings and get confused. As you can see, with the proper settings, it's hard to beat the performance of these native compilers and languages that allow you to write really low-level code.