Slashdot Log In
Java Faster Than C++?
Posted by
michael
on Tue Jun 15, 2004 04:25 PM
from the sacred-cow dept.
from the sacred-cow dept.
jg21 writes "The Java platform has a stigma of being a poor performer, but these new performance benchmark tests suggest otherwise. CS major Keith Lea took time out from his studies at student at Rensselaer Polytechnic Institute in upstate New York's Tech Valley to take the benchmark code for C++ and Java from Doug Bagley's now outdated (Fall 2001) "Great Computer Language Shootout" and run the tests himself. His conclusions include 'no one should ever run the client JVM when given the choice,' and 'Java is significantly faster than optimized C++ in many cases.' Very enterprising performance benchmarking work. Lea is planning next on updating the benchmarks with VC++ compiler on Windows, with JDK 1.5 beta, and might also test with Intel C++ Compiler. This is all great - the more people who know about present-day Java performance, the better.""
This discussion has been archived.
No new comments can be posted.
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
Um, it's online (Score:5, Informative)
The Java is Faster than C++ and C++ Sucks Unbiased Benchmark [kano.net]
Re:Um, it's online (Score:5, Insightful)
Parent
Re:Um, it's online (Score:5, Informative)
int c = 0;
for (int i=n; i>0; i--) {
sprintf(buf, "%d", i);
if (X[strdup(buf)]) c++;
}
When this would have worked just fine:
int c = 0;
for (int i=n; i>0; i--) {
if (X[atoi(i)]) c++;
}
The code is dumb, yes, but you are wrong, nonetheless. That code won't even compile. I think you meant itoa(), which would be about the same as sprintf in terms of functionality.
That for() loop is not equivalent to the Java code's for loop, either. In the java code, he used
if (ht.containsKey(Integer.toString(i, 10))) c++;
which means that he should have used
if (X.count(somestringrepofi)) c++;
X[somestringrepofi] will create an entry for the key if it is not found, making it very different from containsKey().
Parent
The Great Computer Language Shootout (Score:5, Informative)
Anyone got a match? (Score:5, Funny)
vi is better than emacs
bsd is better than linux
gnome is better than kde
.
.
.
anything else?
oh yeah...
my dad can beat up your dad.
And you smell funny.
One more... (Score:5, Funny)
anything else?
Yeah, Kuro5hin is better than Slashdot.
Parent
What are -client and -server? (Score:5, Informative)
different requirements (Score:5, Informative)
You might think that the two are the same, but the two settings actually make a visible impact if you're running on a multi-processor system. Most notably, the garbage collector and locking primitives are implemented differently.
Parent
Re:What are -client and -server? (Score:5, Informative)
Am I the only one who noticed the "inlining policy" thing? Considering "method call" was one of the most compelling arguments for his case (by orders of magnitude!), the fact that the methods being "called" are being called *INLINE* should mean something.
If you're allowed to turn on the java inliner, surely you can spare the time to turn on the C++ one as well (he used -O2, not -O3, for compiling the C++ apps).
Parent
He used g++ to compare C++ with Java... (Score:5, Insightful)
Re:He used g++ to compare C++ with Java... (Score:5, Informative)
Parent
Re:He used g++ to compare C++ with Java... (Score:5, Informative)
Parent
Languages vs Compilers (Score:5, Insightful)
Java and C++ are language. Languages aren't "faster" or "slower", but compilers for them might be. I find it somewhat underhanded to put the languages in the header when it's really comparing compilers.
Not to mention, inter-language compiler benchmark[et]ing is notoriously difficult to get 'right'. The programs tested are often stupid (doesn't do anything meaningful), or constructed by a person with more skill/bias for one language than the other.
The language does matter (Score:5, Insightful)
1) Java has bounds checking for arrays, C++ doesn't. This is specified in the language. This affects performance.
2) Java has garbage collection, C++ doesn't. This is specified in the language. This affects performance.
Also, the specification of Java says that it should be compiled to byte code and executed in a JVM.
So the "language" certainly affects performance.
Parent
A few points... (Score:5, Insightful)
- How equivalent were the benchmarks? Where they programmed in an optimum way for their respective compilers and libraries? I'm sure the java ones were.. what about the C++ ones? The author states he doesn't understand G++ very well.
G++ is also known to not produce the best results.
"I rant it with -O2"
My guess is many of the tests were not implemented properly in c++.
The main clue would be this... I can understand java having better than expected performance.. but there is no way I can accept that java is that much FASTER than properly done C++... it doesn't make any sense.
Re:A few points... (Score:5, Insightful)
Maybe it does make sense. But what it proves is that C++ (at least as implemented by GCC, but it's probably a design flaw) is slower than expected, not that Java is blazingly fast.
Parent
Re:A few points... (Score:5, Interesting)
A couple points:
- The "Great Shootout" benchmark times are sometimes way off because the run-time was too short to get an accurate reading. In those cases the tests should have been run with higher values to really stress the machine. That doesn't appear to be an issue in this test though (assuming his graph values are in seconds).
- Many of the C++ tests are not optimized. That is, they use C++ features like the iostream stuff (cout, and friends) which is extremely slow. The C versions are available and very fast. C++ is pretty much just an extension of C. You don't need to use C++ features if they slow you down. Another one is the hash stuff. In the C++ hash benchmark there are some goofy mistakes made by using the brackets [] operator where it forces several unnecessary lookups. You can also substitute a better STL hashing function that is faster (like MLton's insanely fast hasher).
- The test could be done by comparing C to Java. Anything in C++ can be made as fast as an equivalent C version but there are not many programmers that know how. Just assume anything in C++ will run as fast as a C version, and if it doesn't then you did something wrong. The hash tests would be easier in C++ though. If they were written properly they would kill the Java version.
With that said, I'm going to try these tests myself because I do not believe the results to be accurate. but who knows...
Parent
More info, after some testing (Score:5, Insightful)
Here is the "correct" code for hash2.cpp:
#include <stdio.h>
#include <iostream>
#include <ext/hash_map>
using namespace std;
using namespace __gnu_cxx;
struct eqstr {
bool operator()(const char* s1, const char* s2) const {
return strcmp(s1, s2) == 0;
}
};
struct hashme
{
size_t operator()(const char* s) const
{
size_t i;
for (i = 0; *s; s++)
i = 31 * i + *s;
return i;
}
};
int
main(int argc, char *argv[]) {
int n = ((argc == 2) ? atoi(argv[1]) : 1);
char buf[16];
typedef hash_map<const char*, int, hashme, eqstr> HM;
HM hash1, hash2;
for (int i=0; i<10000; i++) {
sprintf(buf, "foo_%d", i);
hash1[strdup(buf)] = i;
}
for (int i=0; i<n; i++) {
for (HM::iterator k = hash1.begin(); k != hash1.end(); ++k) {
hash2[(*k).first] += k->second;
}
}
cout << hash1["foo_1"] << " " << hash1["foo_9999"] << " "
<< hash2["foo_1"] << " " << hash2["foo_9999"] << endl;
}
Parent
Could use a good analysis (Score:5, Interesting)
I looked at his results page quite extensively, but failed to find a good analysis/justification of the results. Just saying that the Server JVM is better than the Client JVM is *not* enough.
I want to know where the C++ overhead comes from, which Java manages to avoid - does the JVM do better optimization because it is given a better intermediate code (bytecode)? Is it better at doing back/front end optimizations (unlikely given gcc's maturity).
I tried to look for possible discrepancies in the results, but the analysis will definitely take more time - and I think it's the job of the experimenter to do a proper analysis of the results. Liked his choice of benchmarks though.
Re:Could use a good analysis (Score:5, Interesting)
Most of his tests are big loops (primes, string concatenation, etc.) These are cases where (as a sibling poster mentioned) hot path analysis can do you a world of good. A heavily tuned C++ program can do it just as well, or better, but the point of using a high-level language is that you don't have to do those optimizations yourself; you write the code in whatever way seems natural and you let the compiler optimize.
In a long-running Java program, you don't have that extra layer between the program and the CPU. The JIT does a real native compilation and passes control off to it. Once that's started, it runs just as fast as any other assembly code. Potentially faster, given that the JIT can look at the current run and optimize based on the way the code is going: the precise CPU it's running on, where things are in memory, how far it can afford to unroll a loop, what loop invariants it can lift, etc. It can even replace code as it runs.
The question then is, does the one-time (albeit run-time) optimization do more good than it costs?
That's especially easy on a hyperthreaded system. In a C++ program, these loops will run in a single thread on a single CPU, so if the JIT compiler runs on the other (virtual) CPU, you get its effort for free. Even the garbage collector can run on the other CPU, so you get the convenience of memory management with no total performance cost. (You do burn more CPU cycles, but you use up no extra wall-clock time.)
GCC is very mature, but it doesn't have the option of changing the code at run time. Especially on modern CPUs with their incredibly deep pipelines, arranging your code to avoid pipeline stalls will depend a lot on runtime considerations.
Also, Java has a few advantages over C++ in optimization. It's very easy to analyze Java programs to be certain that certain memory locations absolutely will not be modified. That's much harder in languages with native pointers. Those invariants allow you to compile out certain calculations that would have to be done at runtime in a C/C++ program. You can even start spreading loop cycles over multiple CPUs, but I'm pretty certain that the present JVMs aren't that smart.
These results are toy benchmarks, and not really indicative of real performance, even on purely non-GUI code. But I wanted to outline the reasons why the results aren't just silly, and they do have a theoretical basis.
Parent
Now you're talking Profiling (Score:5, Interesting)
So, if the JIT computes Hot/Cold Paths, and optimizes the Hot paths, then it should work better and better on successive runs (as more and more profiling information is gathered). On the other hand, there will be cases where it performs worse, as profiles are gathered for specific inputs.
That means that if an average of say 5 runs (on the same input) is taken, it will have an unfair advantage (since gcc did NOT have the advantage of profiling information (see man gprof or similar)). Using Profiling as an optimization tool is *always* unfair unless both tools are provided with the advantage of the same profiling information. This is a valid question for the author then: if the JIT/javac/JVM uses profiling information, gcc should too, for fair comparison.
PS: I have seen this argument being made by my Professor and audiences at compiler conferences.
Parent
On the flip side (Score:5, Insightful)
With any JIT system you have the opertunity to use the profiling information from a given "window" of the execution so there is the possibility of having more than one compilation for a function.
Now, I do not know how sophisticated JAVA JIT compilers have become but this is one area where JIT will have an upper hand over a static compiler.
OTOH, these tests do not look like there is enough significant variation in the execution path for profiling to make a large difference.
Parent
Expert results (Score:5, Insightful)
That's Great! I can't figure out GCC's error messages, but I offer definitive proof that Java is faster than C++. Nice.
Re:Expert results (Score:5, Interesting)
"I was sick of hearing people say Java was slow, when I know it's pretty fast"
Nice, unbiased viewpoint there...
Parent
I don't actually care hugely about performance (Score:5, Interesting)
I care that Java is an inconvenient pain to develop in and use. I care that I have to start a mini-OS just to run a Java program. I care that the language is under the control of one vendor. I care that the 'intialization == resource allocation' model doesn't work in Java. I care that the type system is too anemic to support some of the more powerful generic programming constructs. I care that I don't get a choice about garbage collection. I care that I don't get to fiddle bits in particular memory locations, even if I want to.
I think Java is highly overrated. I would prefer that a better C++ (a C-like memory model, powerful generic programming, inheritance, and polymorphism) that lacked C++'s current nightmare of strangely interacting features and syntax.
I use Python when I don't need C++s speed or low-level memory model, and I'm happier for it. It's more flexible than Java, much quicker to develop in, and faster for running small programs. Java doesn't play well with others, and it was seemingly designed not to.
Besides, I suspect that someone who knew and like C++ really well could tweak his benchmarks to make C++ come out faster again anyway. That's something I've noticed about several benchmarks that compare languages in various ways.
Java is not under one vendor!!!! (Score:5, Insightful)
It's a standards body just like any other, just more open.
P.S. - Aside from that gripe being wrong, I agree with the other poster that you should look into Objective-C to address other issues. Look for "GnuSTEP" for cross-platform objective C GUI work. It's just nicer to use on a Mac as they have very good tools (though in fairness I have never looked at what GnuSTEP tools might be around, I just can't imagine them being quite as good as the tools Apple has sunk so much effort into!).
Parent
One example of why the tests are BS (Score:5, Insightful)
int
main(int argc, char *argv[]) {
int n = ((argc == 2) ? atoi(argv[1]) : 1);
bool val = true;
>> Toggle *toggle = new Toggle(val);
for (int i=0; i<n; i++) {
val = toggle->activate().value();
}
cout << ((val) ? "true" : "false") << endl;
delete toggle;
val = true;
NthToggle *ntoggle = new NthToggle(val, 3);
for (int i=0; i<n; i++) {
val = ntoggle->activate().value();
}
cout << ((val) ? "true" : "false") << endl;
>> delete ntoggle;
return 0;
}
Why allocate and deallocate an object within the scope of a function? Well, in C++, there's no reason, so this is bad code. You can just declare it as a non-pointer and it lives in stack space. But guess what? You can't do that in Java: all objects are allocated on the heap.
That, and using cout instead of printf, are probably why this is slower than the "equivalent" Java.
-_-_-
Some performance myths (Score:5, Interesting)
Now, regarding java performance ... Java isn't slow per se, JVMs and some apis (most notably swing) are. Furthermore, JVMs usually have a slow startup, which gave java a bad name (for desktop apps startup matters a lot, for servers it's hardly a big deal). Java can be interpreted, but it doesn't have to be so (all "modern" JVMs compile to binary code on the fly)
Bytecode-based environments will, IMNSHO, eventually lead to faster execution than with pre-compilation. The reason is profiling and specialized code generation. With today's processors, profiling can lead sometimes to spectacular improvements - as much as 30% performance improvements on Itanium for instance. Although Itanium is arguably dead, other future architectures will likely rely on profiling as well. If you don't believe me, check the research in processor architecture and compiling.
The big issue with profiling is that the developper has to do it, and on a dataset that's not necessarily similar to the user's input data. Bytecode environments can do this on-the-fly, and with very accurate data.
What about gcj? (Score:5, Interesting)
-josh
java *can* be fast... (Score:5, Interesting)
I am starting on a new standalone server now doing something different, but I am going to stick with Java, and will be happy to see what 1.5 does for me.
But I have seen Java run slow before, and I will tell you this: in every instance it is due to someone writing some needlessly complicated J2EE application with layer upon bloaty layer of indirection. All the wishing in the world won't make one of those behemoths run fast, but it's not fair to blame Java. Maybe blame Sun for EJB's and their best practices, or blame BEA for selling such a pig.
Stuff I like in the Java world:
Can I have an infinite budget to write the code? (Score:5, Interesting)
We knew java in theory should be worse than C++ at manipulating large blocks of raw data, so we spent some time architecting, prototyping, and profiling java. We quickly learned the limitations and strengths.
The result? After 4 engineers worked for 6 months, we had a program that was rock solid, had more features, had a modern UI, and was WAY faster. Night and day; the old program felt like a hog, and the new program was zippy as anything. And the new code is fewer lines, and (in our opinion) way more maintainable. Since the original release, we've added severeal new features after day or two of work; the same features never would have happened on the old version, because they would have been too risky.
So the question is this? Could we have re-written or refactored the C++ program and gotten the same speed benefits? No doubt, such a thing is possible. But we are all convinced there is NO WAY we could have done it with as little effort. The C++ version would have taken longer to write and debug.
O3? Equivalent programs? (Score:5, Insightful)
-O3 adds function inlining and register renaming [gnu.org].
Also, some of the code doesn't look too much of a test of the language, but more of a test of the libraries. Both versions of hash rely on the library implementations, and it looks like hash.cpp [kano.net] does an extra strdup that the java version doesn't. I don't know either of the hash libraries well enough, but I don't see why this significant slowdown would be necessary in the gcc version.
Troll (Score:5, Insightful)
Gcc is designed for compatibility with a wide range of architectures, and is not optimized for a single one. He also (apparantly) used stock glibc from Red Hat. And only one "test", the method call test, showed java to be a real winner. And even then, it's server-side Java, which is meaning less when you talk about it as a day-to-day dev language (ie; creating standalone client-side apps).
Intel's (heavily optimized) C++ compiler should be a damn sight faster, and so should VC++.
This "comparison" is so limited in scope and meaning, that this writeup should be considered a troll.
Hell, read his lead-in:
Ie; I set out to prove Java is teh awesome and c++ is teh suck!
If anything it proves something I've known intuitively for a long time. gcc does not produce x86 code that's as fast as it could be. That's a trade-off for it being able to compile for every friggin cpu under the sun.
I can't wait till RMS takes personal offense and goes on the attack.
Explanation (Score:5, Interesting)
Reviewing the console log, we find that when java programs were tested with a large number of iterations, Java only performed better on one test.
I know that Java has many strengths, but speed isn't one of them. Looking at the results, we see the g++ runtimes are much more consistent than those of Java - on some tests, the Java Server is faster than the client by a factor of 20!? How could a programmer code without having any realistic expectation of the speed of his code. How embarrassed would you be to find that your "blazingly fast" app ran slower than molasses on the client machine, for reasons yet unknown?
When it comes to speed, compiled languages will always run faster than interpreted ones, especially in real-world applications.
But discussions of language speed are a moot point. What this really tested was the implementation, not the language. Speed is never a criteria upon which languages are judged - a "slow" language can always be brought up to speed with compiler optimizations (with a few exceptions). I suspect that if C++ was interpreted, and Java compiled, we'd see exactly the opposite results.
In short, the value of a language consists not in how fast it runs, but in what it enables the programmer to do.
Optimization at runtime vs. compile time (Score:5, Insightful)
I think some of you are overlooking the fact that a VM running byte code is capable of doing optimizations that a compiled language just can't possibly do. A compiled language can only be optimized at compile time. Those optimizations may be very sophisticated, but they can never be any better than an educated guess about what's going to happen at runtime.
But a VM is capable of determining exactly what is happening at runtime; it doesn't have to guess. And thus it is able to optimize those sections of code that really are, in true fact, impacting performance most severely. In can do this by compiling those sections to machine code, thus exploiting precisely the advantage that a compiled language is alleged to have by its very nature. And other kinds of optimizations, the kind that a compiler traditionally does, can be performed on those sections as well.
Of course there are scenarios where runtime optimization doesn't win much, for example in a program that is run once on a small amount of data and then stopped, so that the profiler doesn't get much useful info to work with. This is why Java is more likely to have benefits like this in long-running server processes.
And of course a conscientious C++ programmer will run a profiler on his program on a lot of sample data, and go about optimizing the slowest parts. A conscientious Java programmer should do that too. But an interpreted language has the advantage that the VM can do a lot of that work for you, and always does it at runtime, which is when it really counts.
Function calls (Score:5, Interesting)
For example:
[bdr@arthurdent tests]$ time
165580141
real 0m3.709s
user 0m3.608s
sys 0m0.005s
time
165580141
real 0m0.006s
user 0m0.002s
sys 0m0.002s
I think a lot of these benchmarks are showing that the Hotspot optimiser is very good at avoiding function call overheads.
Re:If you don't run the JVM... (Score:5, Informative)
Parent
Re:Sorry, no. (Score:5, Funny)
Parent
Re:Sorry, no. (Score:5, Interesting)
If you have a program that runs for awhile (so the startup time is small compared to the time the program takes to run), and does not do intensive output to the console, then Java is a reasonable choice in my opinion. Combined with SWT, Java applications can be quite snappy (see Eclipse, Azureus), and the end user will probably never know the difference.
- shadowmatter
Parent
Re:Sorry, no. (Score:5, Funny)
Parent
Re:Caught up with the speed, but still the ugliest (Score:5, Informative)
Oh... and as of Java1.5, Swing apps can now be skinned to look however you'd like them to.
Parent
Re:Caught up with the speed, but still the ugliest (Score:5, Insightful)
Parent
Very true, if don't nkow what you are doing (Score:5, Informative)
Now, when you need to change that quickly and without much overload, there are ways. A little known global HashTable called UIDefaults lets you change just about everything on the visual interface without having to write your own LookAndFeel (which you obviously can do too, for very large projects). You can have your scrollbars, menus, etc in any colour, size and shape, using any font. You can easily change all default colours without having to set every control. After a while the ugliness ceases to be a problem.
Parent
Re:Caught up with the speed, but still the ugliest (Score:5, Insightful)
Actually you can do most anything in those languages. Although for performance, and desgin reasons you may wish to use something else depending on the application.
You have no respect for code. Learn assembly and then we'll talk.
I know assembly, and fun as it is, it isn't well suited for high level projects where code reuse and mantainability are important. By the way, I have no respect for someone who knows assembly and thinks it is difficult. It isn't. And it certainly isn't graceful or elegant, but I love it all the same.
Parent
My Hero! (Score:5, Insightful)
I'm tired of some programmers expecting to be worshipped because they know assembly.
Assembly isn't all that.
For some uses, it is the right tool. For 99.9%+ it most definitely isn't.
Parent
Re:This doesn't make any sense... (Score:5, Informative)
Something I've often wondered is whether this caching could be persistent, i.e. be kept between runs of the JVM. Eventually, the entire program would be translated to pure assembler with the cost of translation largely amortised across many sessions. You still keep the safety, cross platform compatibility and ease-of-programming of a bytecode language (i.e. Java, C#) but you get the bonus of the cached object code being just as fast, even during startup and shutdown.
Parent
Re:my arse (Score:5, Informative)
This whole "x is written in y, so x can't be faster than y" rubbish is just that - rubbish.
Parent
Re:Nort really surprising (Score:5, Insightful)
This would be much more meaninful if you had used fputs() instead of write() in the C version.
As for "several orders of magnitude," I call bullshit. There's no way in hell the standard C++ IO functions are hundreds of times slower unless they're extremely badly written. Which leads me to another reason why this example sucks: there can be different implementations of the standard libraries.
In conclusion, this "comparison" is a stinky pile of shit, and should be ignored. And it's not even on topic, since it doesn't have a Java version.
Parent
been there, done that (Score:5, Informative)
2) While it's not an id game, IL2 Sturmovik [il2sturmovik.com] is a critically-acclaimed fight simulator that was written almost entirely in Java.
Parent
Re:every year this happens... (Score:5, Insightful)
_Jikes_, OTOH, is written in C++. But that's not really the official Java compiler by a long shot.
Your second requirement is absolutely bizarre. Does this mean you're not taking languages like Lisp, Prolog, Python, and Perl seriously, too? Those are all very nice languages for doing stuff in, but I'm pretty sure id never wrote a 3D engine in them. In fact, I was under the impression that id has never written a 3D engine in C++, either. Should we not take C++ seriously?
IMHO: The measure of a language is not how easy it is to write an arbitrary application in it. It's how easy it is to write something for which the language was designed to do.
-Erwos
Parent