Java Performance vs. Readability

Discussions

News: Java Performance vs. Readability

  1. Java Performance vs. Readability (18 messages)

    In "Declare Variables Inside or Outside a Loop," Dru Devore attacks a topic some carry over from other languages: the tendency to sacrifice readability for performance. While Mr. Devore uses a very (very!) simple performance test, it's a good start to a useful line of thought: Java doesn't usually need to be unreadable to perform well. He wrote two tests: one allocated a primitive inside and outside of a simple loop, and the other allocated an object inside and outside of a similar loop. His conclusion was that for the primitive, it didn't matter, and for the object, it mattered some (in terms of allocating the instance). His object example compares StringBuffer.setLength(0) to new StringBuffer(), which may or may not be very representative of normal code, but his point is that for primitives it doesn't matter, and for objects, it's probably better to reuse a previously allocated instance. This isn't exactly rocket science, but few people bother to actually find out what's going on under the covers. Another aspect to consider is that the code he shows is pre-HotSpot. HotSpot will convert the code and optimize it as it's run; this code would have to execute a large number of times (1000 times, if memory serves) before the initial optimization runs, and as the code is used over and over again, might be re-optimized over time. Simple code like this might not be optimizable past a simple compilation, but more complex code would be. Is there a way to test the HotSpot-generated code to see what's more efficient over long-running processes? What do you think about the whole issue?

    Threaded Messages (18)

  2. I think this is a useful topic, as it comes up every day. Personally my view is that, in general, readability is more important than extracting the maximum performance out of code, because human confusion costs companies much more than slow applications in my opinion. Obviously there are exceptions - there are no absolute rules in any business that I know of. Devore also talks about 'small systems' - the habit of doing similar things in similar ways every time. In this case it is how he declares variables, object or primitive. Again I think this is a valuable habit. A lot of the time, it's the small stuff that defines excellence. His points are worth considering IMO.
  3. Normally it doesn't matter[ Go to top ]

    Normally you don't end up allocating new instances of objects inside a loop, you just iterate through them. Hence the performance penalty for declaring an Object reference is (about) the same as for declaring a native type.
  4. Considering how inexpensive memory and hardware and how good the compiler and VM is now does this really matter for business applications dealing with simple domain models? Therefore isin't it generally better to go fo readability and not worry about premature optimization? Let's face it the amount of XML processing, database access that goes on in the average business application small optimizations are low down the list. Of course there are exceptions. Large complex data structures, systems running research math problems or applications running on limited devices etc, etc, etc.
  5. Variables is variables[ Go to top ]

    1. Object type variables and primitive type variables are not fundamentally different in Java. They both contain a value. I don't think it serves anyone any good to continue to talk as if they are. It just creates a lot of confusion. 2. Reusing a Object is not 'probably' better. In fact, it's probably not. For one, it screws with garbage collection. Your temporary Object could end up moving out of the young generation. In the specific case of StringBuffer, things get worse. Most likely, if the StringBuffer truly only needs a block scope, it's going to have a call to toString in the block somewhere (otherwise, why are you creating it?) When you call toString on a StringBuffer, the new String shares the underlying array with that StringBuffer. It also sets a flag saying that it's array is shared with a String. So when you reset the buffer length to 0 and start modifying it again, it is forced to allocate another array. In short, doing this doesn't buy you much of anything and can cause performance issues. I know it's a cliche but this is just another example of premature optimization. 3. Why is someone creating a blog entry about a topic that has been discussed ad nauseum years ago? Does Dru Devore believe this to be an unresolved question in the Java universe?
  6. Refering to James Watson's post[ Go to top ]

    Well! with all respect,the topic has already been deprecated long back but I don't think it should stop somebody to raise it again(say for backward compatibility). The best outcome always comes from good design and efficient use of objects! Code readability matters when the code is evolving over time but performance is of most importance when you are fighting for milliseconds. Primitives are always preferred over Wrappers and these has always been practised though we don't get much out of it but it surely doesn't mean we shouldn't. The point always is: Encourage,Don't criticise.
  7. He wrote two tests: one allocated a primitive inside and outside of a simple loop, and the other allocated an object inside and outside of a similar loop. His conclusion was that for the primitive, it didn't matter ..
    (I apologize for being pedantic)
    int i;
    Local variable declarations create no byte code (regardless of in or out of a loop), so one would expect that it would not influence performance.
    i = 0;
    Primitive assignment (as with many primitive operations) has such an unbelievably negligible impact on performance as to be almost entirely unmeasurable.
    for the object, it mattered some
    Object allocation differs widely from VM to VM, and is impacted by circumstances that are unlikely to be foreseen, such as object tenuring. While general performance trends can be established (and thus predicted), one cannot draw definitive conclusions without witnessing performance in a given environment (server, OS, VM, tuning parameters, load mix, etc.) Peace, Cameron Purdy Tangosol Coherence: Clustered Shared Memory for Java
  8. as if readable is objective[ Go to top ]

    This is a pretty crummy example of pitting readability vs performance, as it relies on one person's idea that it's more readable if variables used exclusively in the loop are declared outside the loop. I think just the opposite. And loops should be methods anyway, right?
  9. Patterns and idioms...[ Go to top ]

    I'm all form routine code patterns and idioms. Things like using "c++" vs "c = c + 1". In the past, that was an actual performance blip back when you hade cheap compilers translating C in to 8080 assembly. Nowadays, not so much. But the idiom stays, it habitual. It's also good to get "good habits". If technique X is equivalent to technique Y, yet X is [faster, better, cheaper, smaller, etc.] than Y, then promote Y. But nowadays, specifically with back office business progammers, it's pretty meaningless. With the modern JVMs, client vs server mode, JITs, machines with dozens of cores and CPU's, L1, L2, L3 caches, optimizing our code in the small is SO far detached from the "reality" of whatever that code actually ends up getting turned in to in terms of bits fed to a CPU, it's simply not worth the cognitive load to even think about it. There was a time where folks would talk about the "sufficiently smart compiler". Where programmers could write straightforward code, and the compiler would magically be able to turn that readable, simple code into arcane, resequenced "optimal code". For very, very specific tasks, there will never be a smart enough compiler. But for folks summing up order detail lines to prepare them for shipping? It's no contest. The compilers are GENIUS level for those mundane tasks. Nowadays, whatever I stuff in to my x.java files are mere suggestions to the compilers, JVMs, CPUs, and operating systems. No matter what I put in there, those tools are going to mold that code in to their own image, and as long as the result that comes out matches the contract I specified in my code, the actual details of how that's done by the computer is pretty much irrelevant. So, I'm going to continue writing code as I think it should be written to better clarify interpretaion of the problem domain as given in the specifications I'm implementing. I will cede very little simply to appease the computer, and will rather wait until the computer proves to me that whatever I gave it was the worst possible implementation possible, simply through demonstrated, miserable performance. Much like my task as a programmer is to convert the intentions of the person creating the specification into performant, reasonable code, it is the compiler and runtimes jobs to take my scribbling and make it working well on the architectures I'm running upon. Solid algorithms, solid design, these are what make programs efficient and performant. Moving variables around in source code is a waste of time. If I were writing 3D game engines for cell phones, then micro-managing the compiler can well pay off. But for shoving bits back and forth between databases, it's simply not worth the time or effort.
  10. There appear to be a whole school of java developers who are totally unaware of the changes made to the jvm over the past few years. I would say that the majority of the devs that I've met and work with still use "optimization" techniques that have been totally obsolete in java for some time now. My theory is that it makes them feel clever, so be damned with whether it actually helps or not. Besides, I think 99% of good performance comes from good design. Architecture is really what you should be spending your grey matter on optimizing.
    But nowadays, specifically with back office business progammers, it's pretty meaningless.
    holy crap. That's me. I'd never thought of myself in quite those terms before. depressing.. Look forward to seeing your presentation on Thursday Mr P.
  11. But ffs[ Go to top ]

    The problem here is that there are two fairly different types of optimizations being talked about. One is where you select algorithms based on data read/write patterns, such as picking the right sorting algorithm, doing things in the right order so that expensive operations don't get performed on data that obviously isn't going to need it for whatever reason. Another, also connect to this, is picking the right data structures based on data read/write-patterns and the size of N (how many items are we talking about) to make sure that the data actually fits in memory. This is real and ever so important and will never ever go away. The other type of optimization, the type you numbnuts are talking about here is such a waste of time. As a newbie to optimization and programming you do not waste time trying to re-use this or that StringBuffer, worry about declaring ints in the wrong place and whatnot. I'd have fired almost every one of you numbnuts in this thread if you'd done any of tasks you mentioned. HotSpot needs/wants Regular and Proper Damn Java Code and so do you when a need arises to add more features/fix bugs. You should never type in things you think are smart and cool optimizataions because they're GOING to be wrong and make things go slower. Dealing with code bases with millions of missused Strings and StringBuffers is making me go bald. And I can clearly see where the authors picked up whichever Cool Optimization some codpiece happens to represent. It's all from crap published on sites like this and/or JavaWorld and it's ALWAYS just a waste of his, mine and the CPU's time.
  12. Re: But ffs[ Go to top ]

    The other type of optimization, the type you numbnuts are talking about here is such a waste of time. As a newbie to optimization and programming you do not waste time trying to re-use this or that StringBuffer, worry about declaring ints in the wrong place and whatnot. I'd have fired almost every one of you numbnuts in this thread if you'd done any of tasks you mentioned.
    Since most of the posts in this thread are saying basically what you have said here, why are you being such a hard-on?
  13. Actual results[ Go to top ]

    Looks like the guy who wrote the article did a very thorough non-JIT analysis of code. But as near as I can tell, he didn't simply run the code and look at the results, and my take is that the "proof is in the pudding." This applies double when a JIT (e.g. HotSpot) compiler comes into play. Here are my results of the code from the article as run on Java 1.5.0_07 with 2,000,000,000 iterations on the primitives, and 100,000,000 iterations on the objects: primitives test 1: 3344 milliseconds primitives test 2: 3390 milliseconds primitives test 3: 3125 milliseconds objects test 1: 28828 milliseconds objects test 2: 24594 milliseconds objects test 3: 24421 milliseconds The tests ran pretty consistently with times usually within a few hundred (or thousand for the objects) milliseonds of those shown, always with test 3 being the fastest. Of course, there's a third variable to the overall equation not taken into considartion in the article (one beyond performance and readability, I mean): good coding practices. If we live by what we're told in Effective Java (by Josh Bloch), declaring the variable inside the loop is the best coding practice. This ties in to my own personal readability preferance for declaring it there. However, my personal preferences aside, with the results of test 3 combined with the recommendations from Effective Java, there should be enough influence, hopefully, to persuade any smart Java programmer to declare loop-local variables inside the loop.
  14. Re: Actual results[ Go to top ]

    The tests ran pretty consistently with times usually within a few hundred (or thousand for the objects) milliseonds of those shown, always with test 3 being the fastest.
    Yes, as Hotspot warms up, the code gets faster ;-) You have to run in a loop, with each loop iteration running each of the tests in a random order, otherwise GC harmonics etc. will distort the results. With the primitive test written taking these things into account, here are my results:
    C:\java\[...]\jdk\142_04\bin\java -server -Xms128m -Xmx128m [...] test 1: 0ms test 2: 121ms test 3: 0ms test 2: 20ms test 1: 0ms test 3: 0ms test 2: 0ms test 3: 0ms test 1: 0ms test 3: 0ms test 1: 0ms test 2: 0ms test 1: 0ms test 3: 0ms test 2: 0ms test 2: 0ms test 1: 0ms test 3: 0ms ...
    ... and so on. None of the tests took over 0ms once Hotspot kicked in. ;-) For reference:
    public static void main(String[] asArg) { for (int i = 0; i < 100; ++i) { testPrimitives(1000000000); } } public static void testPrimitives(int count) { int nBase = getRandom().nextInt(3); boolean fFwd = getRandom().nextBoolean(); for (int i = 0; i < 3; ++i) { int nTest = (nBase + (fFwd ? i : -i) + 3) % 3; long lStart = System.currentTimeMillis(); switch (nTest) { case 0: testPrimitives1(count); break; case 1: testPrimitives2(count); break; case 2: testPrimitives3(count); break; default: azzert(); } long lStop = System.currentTimeMillis(); out("test " + (nTest + 1) + ": " + (lStop - lStart) + "ms"); } } public static void testPrimitives1(int count) { int a = 0; for (int i = 0; i < count; i++) { a = i; } } public static void testPrimitives2(int count) { int a; for (int i = 0; i < count; i++) { a = i; } } public static void testPrimitives3(int count) { for (int i = 0; i < count; i++) { int a = i; } }
    Peace, Cameron Purdy Tangosol Coherence: The Java Data Grid
  15. Different applications (Java or not) require different approaches. Readability is sometimes more important than performance, but not always. The guys that have, and are deploying Cameron's product certainly care about performance (where milliseconds count). They're also not just relying solely on products, VMs, compilers, etc. to achieve that performance.
  16. Java coding good practices ?[ Go to top ]

    Hi all I've read your topic with much interest. Indeed, to produce "good code" is something most of the developpers are, I think, eager to do. However, having read all yours comments, I've the feeling that there's no "coding trick" but only "sound architecture/design solutions". Is this correct ? Is there nothing to avoid in order to have good performances ? Furthermore, if you were to write some "Java coding good pratices", what would you say ? IMHO, I just see : - use the right sort - limit the times you read/write files What would you add ? Thanks in advance ZedroS
  17. Hi all

    I've read your topic with much interest. Indeed, to produce "good code" is something most of the developpers are, I think, eager to do.

    However, having read all yours comments, I've the feeling that there's no "coding trick" but only "sound architecture/design solutions". Is this correct ? Is there nothing to avoid in order to have good performances ?
    There are but the general trend in programming languages is to elimate the need to use 'tricks' in code to improve preformance. The theory being that the code that best solves the real problem should be the code used and that the compiler or VM sohuld handle the details of making it fast.


    Furthermore, if you were to write some "Java coding good pratices", what would you say ?

    IMHO, I just see :
    - use the right sort
    - limit the times you read/write files

    What would you add ?

    Thanks in advance
    ZedroS
    Using the correct data structure is important, probably more so than sorting because sorting of non-trivial length lists and arrays is a rarity in Java (from my experience) but use of structures like Lists and Maps is extremely common. Since IO is on the order of 1000 times slower than in memory access, it's something to minimize. The main point to take away from this is that if you do need to hand optimize something 1. make sure it's necessary 2. and make sure you know why you are doing it. Often the first is not true. Maybe some piece of code is not optimal but it only happens once a day and executes in subsecond times. No need to mess with something like that. You are more likely to create issues than anything else. The second is also a common failure. Many developers figure less lines of code is faster or bringing a variable declaration up out of a loop body will make things faster. But they haven't verified these assertions in any way. Make sure you know that your change will have a noticeable effect on performance.
  18. Thanks for the answer.
    Many developers figure less lines of code is faster or bringing a variable declaration up out of a loop body will make things faster. But they haven't verified these assertions in any way. Make sure you know that your change will have a noticeable effect on performance.
    Do you think that bringing a variable out of a loop isn't improving performance ? Or rather that the improvement is small ? BTW, except running the code, do you have any other way to know what improves the code's performance ?
  19. Do you think that bringing a variable out of a loop isn't improving performance ? Or rather that the improvement is small ?
    There is no improvement what so ever. The byte code is identical.