Win a copy of Murach's Python Programming this week in the Jython/Python forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

looping performance boost?  RSS feed

 
Matt O'Keefe
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I once heard that the following code will execute faster than the more conventional approach:
try {
for (int i=0; ; i++) {
System.out.println(stuff[i]);
}
} catch (IndexOutOfBoundsException ioobe) {
//do nothing
}
Is this true? At one time I know that Symantec Cafe would halt when an unchecked exception was thrown... given this kind of problem would any potential performance gain be worthwhile?
Thanks,
Matt
 
Peter den Haan
author
Ranch Hand
Posts: 3252
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Matt O'Keefe:
[B]I once heard that the following code will execute faster than the more conventional approach:

Is this true?
[/B]

You're saving yourself a comparison, but since throwing an exception is an expensive operation, I'd think it would only be true if stuff[] is very large. And pretty insignificant unless the loop body is very trivial indeed.
Looks like bad practice to me.
- Peter
 
Peter Haggar
author
Ranch Hand
Posts: 106
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is definitely bad practice. I have only found this idiom to be faster than a normal for loop when you run without a JIT and the loop has to run for many interations. I think on my JVM I had to run it for at least 1 million times before it would be any faster than a normal for loop.
Since most all JVM's have JITs today, the normal for loop is often optimized to always be faster than the exception case, even for lots of iterations.
Also, creating an exception is more expensive than creating a "normal" object. See my post here for more details on this.
Bottom line: avoid this unless you are running without a JIT and you prove that you need a loop speedup and this code gives it to you.
Peter Haggar
------------------
author of: Practical Java
 
Peter Tran
Bartender
Posts: 783
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
When I first doing research on Performance tips, a lot of old articles recommended this idiom with the for() loop to increase performance. Notice the world "old" as meaning pre-JIT days or poorly implemented JITs. As Peter Haggar pointed out, with current JITs technology this idiom is unwarranted and makes the code much more difficult to read.
They also recommended the following from this article.

For example, a data-intensive operation would benefit from first copying instance variables into stack variables, operating on the stack variables, and, finally, copying the stack variables back to the permanent instance variables.
This technique is particularly useful when a method variable is accessed repeatedly within a loop. For example, the common loop construct:
for (int i=0; ++i<=limit; ) <br /> can be improved by 25% (5% with the JIT compiler) by rewriting it as <br /> for (int i=limit; --i>=0; )
to reduce the number of accesses to the limit variable.

I got hammered during a coding standard review for recommending to using the second version with all for() loops (throughout the entire company).
-Peter
[This message has been edited by Peter Tran (edited January 17, 2001).]
 
Marius Holm
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Peter Tran,
Just for curiosity, what was the problem with that for-loop, why did you get hammered? In my eyes it looks perfect.
Regards,
Marius
 
Peter Tran
Bartender
Posts: 783
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Marius,
Pick any book that teaches you to use the for() using that idiom. I bet you a cup of Starbucks coffee that you won't be able to find an example for any programming language. The standard for() loop idiom counts forward - not backward. Depending on what you're doing, sometimes you can't count backward. Anyway, I think the people in that meeting didn't see the need to make the code any more difficult to comprehend by forcing other coders to think "backward".
-Peter
[This message has been edited by Peter Tran (edited January 17, 2001).]
 
Peter Haggar
author
Ranch Hand
Posts: 106
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Marius Holm:
Just for curiosity, what was the problem with that for-loop, why did you get hammered? In my eyes it looks perfect.

The count backwards for loop is another old idiom that I have not found to be true. The thing was that if you count back to zero you are comparing against zero instead of against limit. The thinking is that comparing against zero is faster.
On some hardware it might be, but I have not noticed a difference in my tests of forward or backward counting loops in Java.
Peter Haggar

------------------
author of: Practical Java
 
Matt O'Keefe
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I must say that I agree with all of the comments thus far advising against weird idioms. I too prefer readability over slight performance gains which apparently no longer apply. The intention of my original post was to discuss the validity of some advice that I'd seen, not to promote it. :->
Regarding "forward" loops, would most compilers be smart enough to optimize this code in order to avoid redundant method invocations?

Matt
 
Peter Haggar
author
Ranch Hand
Posts: 106
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Matt O'Keefe:
Regarding "forward" loops, would most compilers be smart enough to optimize this code in order to avoid redundant method invocations?

No. I haven't tried all compilers, but I've tried a lot. None of them do anything but the most trivial optimizations. One thing to assume when you are writing Java code: The bytecode generated isn't any better than what you write.
I compiled your loop above with both the Sun JDK 1.2.1 compiler and the IBM JDK 1.3 compiler. As expected, both generated the same crappy bytecode:
0 iconst_0
1 istore_2
2 goto 11
5 invokestatic #5 <Method void doStuff()>
8 iinc 2 1
11 iload_2
12 aload_1
13 invokevirtual #6 <Method int size()>
16 if_icmplt 5
19 return
The for loop is between location 2 and 16. Notice that it is invoking the size() method for each loop iteration. Bottom line: the compiler didn't optimize anything. For this loop to be more efficient, you would have to change the source code to make the compiler generate better bytecode.
This and more is covered in my book. Also, if you want to learn more about bytecode and how it works, I authored an article on it that can be found here.
Peter Haggar
IBM Corporation
------------------
author of: Practical Java
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'd say that the compiler shouldn't optimize this anyway, unless it can be shown that doStuff() cannot possibly change the size of the Vector. Which at a minimum would require that doStuff() be static, final, or private (for no overriding), and then the compiler would have to carefully check the method to understand what it does. Which could be done, but as Peter notes most existing Java compilers aren't that smart.
 
Peter Tran
Bartender
Posts: 783
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If the Vector.size() doesn't change, wouldn't the code be more efficient using this technique?

To use this technique, you do have to guarantee that doStuff() method doesn't change the vector size as Jim mentioned.
-Peter
 
Peter Haggar
author
Ranch Hand
Posts: 106
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, assuming the size of the vector didn't change, this is the rewrite of the code I was proposing.
Peter Haggar
------------------
Senior Software Engineer, IBM
author of: Practical Java
 
Marius Holm
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Peter Tran,
I once got hammered for changing this:
<PRE>
int maxvalue=1000;
int checkvalue=-1;
for(int i=0;i< maxvalue;i++){
if((checkvalue< 0)&&(myArray[i]))checkvalue=i;
}
System.out.println("Desired value found in "+checkvalue);
</PRE>
into this:
<PRE>
int maxvalue=1000;
int checkvalue=-1;
for(int i=0;i< maxvalue;i++){
if(myArray[i]){
checkvalue=i;
i=maxvalue;
}
}
System.out.println("Desired value found in "+checkvalue);
</PRE>
My version, as you see, saves one comparison on every loop, and on average, half of the loops. I was told this to be bad style (I was about 16 at the time) and I thought the teacher would be correct. Now, in the first message of this thread, I think the practice of throwing an unnecessary Exception is better described as HORRIBLE, than just 'bad'. And there are no big performance issues around it to justify it, so I didn't like that one.
As when it comes to the counting backwards operation, it is technically the same as counting forwards (as long as you store the comparison value in an int) except that the value zero does not have to be looked up in a processor register(!), that's what makes it faster. So, as long as this is true (I see Peter Haggars critical remark there) I think it justifies the backwards counting, even though it looks somewhat less readable to humans. And when it comes to my example above, I find the potential performance increase (especially with large loop bodies, but saving one comparison is also significant when the loop body is small) to be more than worth the somewhat 'untidy' style. Any other having views on this?
Regards,
Marius
[This message has been edited by Marius Holm (edited January 18, 2001).]
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!