Performance of Java versus C++J.P.Lewis www.idiom.com/~zilla
This article shows that
What is slow?Before getting to the data, let's calibrate what "slow" means. If you write a number of small benchmarks in several different types of programming language, the broad view of the performance relative to assembler might be something like this:
The benchmarks below show that java has e.g. 0.8-1.4 times the speed of C across a number of benchmarks, and is generally a bit faster than some C compilers (gcc). Is "slow" the right word? When stuck on an airplane I'll sometimes look through PC World or similar magazines. They usually have a systems shootout with language like "System X trounces the competition". The table showing the WinBizBench2000 scores reveals that System X is 4% faster than the other model. If you consider a 4% speed increase to be significant then indeed Java is slow... and you write everything in assembler no doubt! On the other hand if you think C and C++ have acceptable performance, read on. BenchmarksHere are five composite benchmarks indicating that modern Java certainly has acceptable performance, being nearly equal to (and in many cases faster than) C across a number of benchmarks.
And In Theory: Maybe Java should be fasterJava proponents have been saying that Java will soon be faster than C. Why? Several reasons (also see reference [1]):1) Pointers make optimization hardThis is a reason why C is generally a bit slower than Fortran.In C, consider the code x = y + 2 * (...)
*p = ...
z = x + ...
Because p could be pointing at x,
a C compiler cannot keep x in a register and
instead has to write it to cache and read it back --
unless it can figure out where p is pointing at compile time.
And of course because arrays are pointers
in C/C++, the same is true for assignment to array elements.
This pointer problem in C resembles the array bounds checking issue in Java: in both cases, if the compiler can determine the array (or pointer) index at compile time it can avoid the issue. In the loop below, for example, a Java compiler can trivially avoid testing the lower array bound because the loop counter is only incremented, never decremented. A single test before starting the loop handles the upper bound test if 'len' is not modified inside the loop (and java has no pointers, so simply looking for an assignment is enough to determine this): for( int i = 0; i < len; i++ ) { a[i] = ... }
In cases where the compiler cannot determine the necessary information at compile time, the C pointer problem may actually be the bigger performance hit. In the java case, the loop bound(s) can be kept in registers, and the index is certainly in a register, so a register-register test is needed. In the C/C++ case a load from cache is needed. 2) Garbage collection- is it worse...or better?Most everyone says GC is or should be slower, with no given reason- it's assumed but never discussed. Some computer language researchers say otherwise.Consider what happens when you do a new/malloc: a) the allocator wanders through some lists looking for a slot of the right size, then returns you a pointer. b) This pointer is pointing to some pretty random place. With GC, a) the allocator doesn't need to look for memory, it knows where it is, b) the memory it returns is adjacent to the last bit of memory you requested. The wandering around part happens not all the time but only at garbage collection. And then of course (and depending on the GC algorithm) things get moved of course as well. The cost of missing the cacheThe big benefit of GC is memory locality. Because newly allocated memory is adjacent to the memory recently used, it is more likely to already be in the cache. How much of an effect is this? One rather dated (1993) example shows that missing the cache can be a big cost: changing an array size in small C program from 1023 to 1024 results in a slowdown of 17 times (not 17%). This is like switching from C to VB! This particular program stumbled across what was probably the worst possible cache interaction for that particular processor (MIPS); the effect isn't that bad in general...but with processor speeds increasing faster than memory, missing the cache is probably an even bigger cost now than it was then. (It's easy to find other research studies demonstrating this; here's one from Princeton: they found that (garbage-collected) ML programs translated from the SPEC92 benchmarks have lower cache miss rates than the equivalent C and Fortran programs.) This is theory, what about practice? In a well known paper [2] several widely used programs (including perl and ghostscript) were adapted to use several different allocators including a garbage collector masquerading as malloc (with a dummy free()). The garbage collector was as fast as a typical malloc/free; perl was one of several programs that ran faster when converted to use a garbage collector. Another interesting fact is that the cost of malloc/free is significant: both perl and ghostscript spent roughly 25-30% of their time in these calls. 3) Run time compilationModern Java virtual machines do some amazing things: they profile the program while it is running, determine which parts to optimize, compile them, then uncompile and recompile them if new classes are loaded that override methods that were inlined!The people working on hotspot in particular have hinted that Java should sometime be faster than C because of this. Why?
Of the three reasons why Java may soon produce faster code than C/C++, I find this one the least convincing. I think it applies mainly to tasks (like web application servers) that are literally running for months under reasonably heavy load and slowly changing conditions; recompiling repeatedly is worth it in these cases. For more typical desktop programs, the compiler would need to be sure that a particular loop is going to run long enough for a re-optimize to be worthwhile. Don't characterize the speed of a language based on a single benchmark of a single program.In popular web forums we'll often see people drawing conclusions from a single benchmark. For example, an article posted on slashdot.org recently [3] claims to address the question "Which programming language provides the fastest tool for number crunching under Linux?", yet it discussed only one program.Why isn't one program good enough? For one, it's common sense; the compiler may happen to do particularly well or particularly poorly on the inner loop of the program; this doesn't generalize. The first study in benchmark #2 above shows Java is being faster C by a factor 2 on an FFT of an array of a particular size. Should you now proclaim that Java is always twice as fast as C? No, it's just one program. There is a more important issue than the code quality on the particular benchmark, however: Cache/Memory effects.
Look at e.g. the FFT microbenchmark that we referenced above.
The figure is reproduced here:
On this single program, depending on the input size, the relative performance of 'IBM' (IBM's Java) varies from about twice as slow to twice as fast as 'max-C' (gcc) (-O3 -lm -s -static -fomit-frame-pointer -mpentiumpro -march=pentiumpro -malign-functions=4 -fu nroll-all-loops -fexpensive-optimizations -malign-double -fschedule-insns2 -mwide-multiply -finline-function s -fstrict-aliasing). So what do you conclude from this benchmark? Java is twice as fast as C, or twice as slow, or anything in-between! For a more dramatic example of cache effects see this link, discussed more above.
The person who posted [3] demonstrated the fragility of his
own benchmark in a followup
post,
writing that
Conclusions: Why is "Java is Slow" so Popular?Java is now nearly equal to C++ on low-level and numeric benchmarks. This should not be surprising: Java is a compiled language (albeit JIT compiled).Nevertheless, it seems like "java is slow" is widely believed. Why this is so is perhaps the most interesting aspect of this article (at least in my mind). Let's look at several possible reasons.
The answer probably lies somewhere in sociology or psychology. Programmers, despite their professed appreciation of logical thought, are not immune to a kind of mythology, though these particular "myths" are arbitrary and relatively harmless. References
[1] K. Reinholtz, Java will be faster than C++, ACM Sigplan Notices, 35(2) 25-28 Feb 2000. [2] Benjamin Zorn, The Measured Cost of Conservative Garbage Collection Software - Practice and Experience 1992. [3] Linux Number Crunching: Languages and Tools, referenced on slashdot.org [4] Christopher W. Cowell-Shah, Nine Language Performance Round-up: Benchmarking Math & File I/O, appeared at OSnews.com, Jan. 2004.
|