Algorithmic performance comparison of C++, JavaScript, and Java.

Algorithmic performance comparison of C++, JavaScript, and Java.

I was doing some practice tests recently and after implementing my solution in C++, decided to compare its performance in other languages - JavaScript, ES6, and Java.

This is problem #35 from Project Euler web site:

The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.

There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.

How many circular primes are there below one million?

I uploaded the solution in different languages on my Github account and will not post code here. The files contain running instructions for each language on top. I just want to note that due to algorithmic nature of the problem the implementation is almost identical with the exception of obvious language syntactic differences. Also I do not pretend that this solution is the fastest. Actually it is a pretty straight forward brute force algorithm with some prime test optimization.

The results vary from run to run, but not significantly. I added a screenshot with a sample run in each language to the top of the page.

C++

I compiled C++ version with the highest level of optimization -O3. The result is 0.183s. Without optimization it was more than twice as slow - 0.411s.

JavaScript

Interestingly JavaScript ran just a little slower - in 0.229s.

ES6

ES6 is basically the same JavaScript. I only replaced var with let and added "use strict"; on top. The result however surprised me - 1.187s, five times as slow compared to old JavaScript. There is probably some bug in the node implementation of new standard.

Java

Java result was most surprising - 0.284s. It appears that it is the slowest of all (not counting ES6 version which is obviously a bug).

Conclusion

V8 based, node.js engine is extremely efficient and outperforms Java. This simple performance test proves that JavaScript is more efficient than Java. Interestingly the performance difference is about 24%, almost the same as other author came up with on an entirely different test case. Not surprisingly C++ is better than JavaScript by the same margin.

You are welcome to run the same tests on your machine. Use the link on top to download the sources.

Hardware and Software

node -v
v5.9.0
g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.3.0
Thread model: posix
javac -version
javac 1.8.0_65
java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

MacBook Pro 15'' 2015
OS X El Capitan
Version 10.11.3
Processor 2.8 GHz Intel Core i7

Ivan V.

Quantitative developer

8y

Code not being optimized, JIT compilation, GC, preallocation, all these unaddressed issues aside... In the Java version you're using a Vector, which is fully synchronized. Slowest choice ever.

István Kovács

Lead Software Engineer at EPAM Switzerland

8y

I have been unable to reproduce those numbers. Mine is a very old machine, so even the g++ -O3 code ran in about 0.5 seconds: kofa@eagle ~/git/perfcomp/euler35 $ time echo 1000000| ./a.out 55 real 0m0.567s user 0m0.552s sys 0m0.000s I went on to wrap your Java code into a proper JMH benchmark (seehttp://openjdk.java.net/projects/code-tools/jmh/): # JMH version: 1.19 # VM version: JDK 1.8.0_131, VM 25.131-b11 # VM invoker: /usr/lib/jvm/java-8-oracle/jre/bin/java # VM options: <none> # Warmup: 5 iterations, 50 s each # Measurement: 5 iterations, 50 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: org.sample.MyBenchmark.testOriginal # Run progress: 50.00% complete, ETA 00:08:23 # Fork: 1 of 1 # Warmup Iteration 1: 0.517 s/op # Warmup Iteration 2: 0.510 s/op # Warmup Iteration 3: 0.507 s/op # Warmup Iteration 4: 0.510 s/op # Warmup Iteration 5: 0.514 s/op Iteration 1: 0.514 s/op Iteration 2: 0.512 s/op Iteration 3: 0.513 s/op Iteration 4: 0.508 s/op Iteration 5: 0.513 s/op Result "org.sample.MyBenchmark.testOriginal": 0.512 ±(99.9%) 0.009 s/op [Average] (min, avg, max) = (0.508, 0.512, 0.514), stdev = 0.002 CI (99.9%): [0.503, 0.521] (assumes normal distribution) The only modification was omitting printing the result, instead returning it to JMH to make sure the call was not optimised away by the JIT. Confirming that, a command-line run (using unmodified code straight from your git repo), including JVM initialisation overhead: kofa@eagle ~/git/perfcomp/euler35 $ time echo 1000000| java euler35 55 real 0m0.664s user 0m0.688s sys 0m0.024s Maybe on a more modern CPU g++ produces far better code than javac. I suggest that you repeat your test using JMH.

Like
Reply

Hello Aleksey, did you try the experiment again with Sergey's recommendation? If so, I'm curious as to your results.

Like
Reply
Sergei Grinev

Senior Engineering Manager

9y

Please note that most probably you are running java code basically by interpreter. You need to warm up JVM to have C1/C2 join in action and show real app level performance.

That's not a big surprise to me. I've checked just the C++ code and it seems extremely unoptimized (as you said). I'm pretty sure that if you run the code without optimization using a profiler, you'll see a disproportionate amount of time spent in the call of sqrt, call that could be easily optimized away (-O3 perform that optimization, V8 is able to do a similar thing with function caching, not sure ES6 has that optimization available yet). Now, the difference between the languages is the time spent in compiling the code and how fast is at optimizing it. If you work hard in optimizing manually the code (I've solved the same problem on project Euler using Python, my first version looked like your code, my last was more complex and like 100 times faster) you'll see the difference in performance of the different languages, also because the optimizations you could apply are different. Usually, C/C++ came out as the clear winner with 10X improvement (but the code is fairly difficult to write, read and debug). The runners up are usually GO and Rust, almost as efficient and fairly easier to read and debug. JS, Java, Python, Ruby, Scala etc are a lot slower. But readability matters, and as you noticed, compiler/interpreters are pretty good at optimizing code

Like
Reply

To view or add a comment, sign in

Explore content categories