Skip to main content

generics: for (class obj:list) 3x slower how come ?.

12 replies [Last post]
gustav3d
Offline
Joined: 2005-10-05
Points: 0

ArrayList list = new ArrayList(500);
...

int a=0;
for (String s:list)
a+=s.length();

why is the code below a factor 3 faster ?

int a=0;
int size=list.size();
for (int i=0;i

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
linuxhippy
Offline
Joined: 2004-01-07
Points: 0

> you did not notice the main loop that iterates 10
> times over the entire test sequence ?
Hotpot triggers a full compilation after 10.000 -> 15.000 method invocations, otherwise just an OSR compilation is done if a method is long enough on the top of the stack. That means at least some stuff is still interpreted or just OSR compiled.

> but thats an bug that is in progress status.
Yes I know this bug, it was filed by me.
But note that it talkes about unusual loop constructs which confuse the server compiler, not about a general slowdown which happens at "second" *rofl* compilation.
So in general this has nothing or just very little to do with your stuff.

> and how can you state that "some ar interpreted".
> that statement shows that you have not even run these
> tests for your self trying to figure it out.
Right, since this type of performance "problems" get in my eyes just very little attention.
If you operate over collections which contain objects you'll most likely do something with these objects which will most likely consume much more time that the loop itself consumes.
Ok, its not pretty but its not that big thing you want to make it.

> linuxhippi ,youre not bringing any scientific based
> conlusions, only leting your mouth talk without any
> brain involved at all, so please shutup !
Sorry but it seems you just can't cope with some criticism which is some form of uneducation or lack of intelligence. Just the way you express yourself says everything :-/

In fact I did not even criticise you I just mentioned:
- That this a classical micro-benchmark. Thats simply true, sorry.
- That the impact on tuning such statements is negligible under most conditions.
- That the runtime circumstance are maybe not optimal.

Please inform yourself a bit better before you start flaming against others or read posts more carefully (or learn readin??).

lg Clemens

gustav3d
Offline
Joined: 2005-10-05
Points: 0

linuxhappy,

linuxhippy,
you talk about 15000 calls before hotspot compiles from OSR ?.

so why do you ignore the fact that i gave figures based on 10x 500000 calls for the method ?. and inside that call is 500 calls for the iteration / get.

so why are you mumbeling about your 15000 ?.
youre clearly just talking rubish without even bathered to test out for your self in a decent way.

its still *VERY* obvious that you have not done this testing by yourself.

the fact still remains as i originally stated.
factor 2 or slower.
and if you had checked what actually happens you would noticed that when hotspot bug kicks in the slowdown is 50% for the get version and the generic one is speed up some.
still with with this 50% slowdown for the get()versions its a factor of 2.
you can see this here in the output from a longer test:

ns/iter: 2.46 12.42 1.93 ret:284500
ns/iter: 2.46 12.96 1.93 ret:284500
ns/iter: 367.79 58.46 1.89 ret:284500
ns/iter: 3.32 7.98 1.87 ret:284500
ns/iter: 3.32 7.93 1.87 ret:284500

get() version goes from 2.45 -> 3.32 ns/iter. nice eh !
generic iter goes from 12.5 -> 8 still the now crippled get() is more then 2 times faster.
and now we have done more then 5 million calls a 500 get/iters.

or you mean doing 5 million a 500 iterate/get is not enough ?. please stop joking.

and actually you have no right to state that this slowdown is of no concern.
i that kind of thinking was used everywhere , it would be generall slowdown of factor 2 or more.

youre a person who only like your own theoretical talk without checking any facts at all. nice work man !

linuxhippy
Offline
Joined: 2004-01-07
Points: 0

Sorry for beeing such an idiot, I know what you say is right, what you think is right and what you consider as important or significant is important or significant.

Because of your whisdome and your glory you'll show me the way to the one and only light.

lg Clemens

PS: Would be great if you could stop flaming and shouting like a 6 years old. You just generate traffic and disqualify yourself.

PS2:
> i that kind of thinking was used everywhere , it would be generall slowdown of factor 2 or more.
seems you just don't get it?
Developing this way is ... well ... normal. In almost any case a few cycles could be saved but the big question is wether its worth in terms of investment or not.

gustav3d
Offline
Joined: 2005-10-05
Points: 0

the qeustion is not about a few cycles,

its about a relative slowdown of several 100% percent.

thats wrong direction in development imo =).

if you extrapolate that kind of thinking, it is perfectly ok to make everything that much slower.
or where should the limit be drawn ?
doing 1% of the functionallity in java alot slower or 100% of it ?. or how about none ?.
or its you are uncapable of understanding this ?.
and youre correct i have exactly 0 respect for people like you.

linuxhippy
Offline
Joined: 2004-01-07
Points: 0

> the qeustion is not about a few cycles,
> its about a relative slowdown of several 100%
> percent.
Which are still just a few cycles.

> and youre correct i have exactly 0 respect for people
> like you.
Although I never assumed or implied that, do you really think I care about it? *laughing*

tackline
Offline
Joined: 2003-06-19
Points: 0

With -server on b86, I get around 20% difference. Room for improvement, but not that bad for a loop that essentially does nothing. Where it does matter, you can always drop back to arrays.

So that we can compare the same thing:

import java.util.List;

class EnhancedForSpeed {
public static void main(String[] args) {
final int num = 500;
List list = new java.util.ArrayList(num);
for (int ct=0; ct list.add(Integer.toString(ct));
}
for (int run=0; run<3; ++run) {
long start = System.currentTimeMillis();
int sum = loop(list);
long end = System.currentTimeMillis();
System.out.println((end-start)+" ms. Sum: "+sum);
}
}
private static int loop(List list) {
int total = 0;
for (int i=0; i<1000*1000; ++i) {
total += fn(list);
}
return total;
}
private static int fn(List list) {
int a = 0;
/**/
for (String s : list) {
a += s.length();
}
/*/
int num = list.size();
for (int i=0; i a += list.get(i).length();
}
/**/
return a;
}
}

gustav3d
Offline
Joined: 2005-10-05
Points: 0

declaring list in Main and passing as argument to private static method ? =)

heres my result of my tests confirmed by others:

arraysize 100 and rep 100 gives a factor 4 in difference.
arraysize 500 and rep 500000 gives a factor 2 in difference.

heres a simple test:

import java.util.ArrayList;

public class Main {
private ArrayList list = new ArrayList();
private String[] array = new String[500];

public static void main(String[] args) {
new Main();
}

public Main() {
for (int i=0;i list.add(String.valueOf(i));
array[i]=String.valueOf(i);
}
int rep=500000;
for (int a=0;a<10;a++){ // you can try to move the order of ntest and gentest around if wanted. the result is the same.
int ret=0;
long t1= System.nanoTime();
for (int i=0;i ret+=ntest();
long ta= (System.nanoTime()-t1)*100/(rep*list.size());

t1= System.nanoTime();
for (int i=0;i ret+=gentest();
long tb= (System.nanoTime()-t1)*100/(rep*list.size());

t1= System.nanoTime();
for (int i=0;i ret+=arraytest();
long tc= (System.nanoTime()-t1)*100/(rep*list.size());

System.out.println("ns/iter: "+ta/100.0+" "+tb/100.0+" "+tc/100.0+" ret:"+ret ); // ret is just here so we use it externally at all.
}
}

private int gentest(){
int a=0;
for (String s:list)
a+=s.length();
return a;
}

private int ntest(){
int a=0;
int size=list.size();
for (int i=0;i a+= list.get(i).length();
return a;
}

private int arraytest(){
int a=0;
for (int i=array.length-1;i>0;i--)
a+=array[i].length();
return a;
}
}

linuxhippy
Offline
Joined: 2004-01-07
Points: 0

First of all your benchmark is a classical micro-benchmark.
You'll just trigger OSR compilation for some methods, others will stay interpreted.

So the foreach-loops are 2-4x slower than direct access, which is, well not that bad. Sure there's room for improvements but keep in mind this are very small loops, where most time is spent in the loop itself.
These should be considered as a typical micro-optimization which should only lead to minimalistic overall improvements.

Furthermore did you use the java server compiler.

lg Clemens

gustav3d
Offline
Joined: 2005-10-05
Points: 0

linuxhippy ,on all yout statements, that is not the case:

you can see that for your self by leting the jvm output
both inlining , compile events for methods during runtime.

you can also see the compiled code produced in runtime if you want to.

you will se that there is no unfair treatment of either test case from the jvm/hotspot.

you did not notice the main loop that iterates 10 times over the entire test sequence ?
you get a performance comparison output from each iteration.

and my coment regardin that you can move the calling sequences around, the performance factors will stay terrible.

and the case is that if you incease the repeatment too much, the current hotspot compiler bugg regarding second compilation time will kick in and make ALL methods we are benchmarking several times slower.
again thats no unfair treatment.
but thats an bug that is in progress status.
i see no reason to enforce that bug here, since that is a different matter and its being fixed.

and how can you state that "some ar interpreted".
that statement shows that you have not even run these tests for your self trying to figure it out.

you would noticed that there are no performance increase for any of the methods we benchmark by increasing any loop counter of the several that exists.
only thing that happens is the slowdown that the bug i explained earlier kicks in.

what youre saying in your post linuxhippy shows that you have not even read my posts.so how can youjudge it ?
ive allready stated that i use jdk1.6b86 -server
so why ask about it ?.

linuxhippi ,youre not bringing any scientific based conlusions, only leting your mouth talk without any brain involved at all, so please shutup !

gustav3d
Offline
Joined: 2005-10-05
Points: 0

this is the compiler bug im talking about.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6396953

gustav3d
Offline
Joined: 2005-10-05
Points: 0

well the point is that its the officially recomended way of doing it that is so slow.
so thats how all new people learn to do from the tutorials etc.

thats exactly what we dont need, new fluffy stuff that boggs down the performance.

specially if the case is that it wont get fixed ?.

if it was a 5% or so it could *maybe* be overseen.
but a factor of 3-4 is not tollerable.

regards
gustav

forax
Offline
Joined: 2004-10-07
Points: 0

> ArrayList list = new
> ArrayList(500);
> ...
>
> int a=0;
> for (String s:list)
> a+=s.length();

this one use an Iterator so basically two
methods call by loop increment (hasNext, next())
+ failfast incrementation.

>
> why is the code below a factor 3 faster ?
>
> int a=0;
> int size=list.size();
> for (int i=0;i > a+= list.get(i).length();

only one call but with a range check

and this one is more faster :

String[] array=new String[500];
for (String s:array)
a+=s.length();

>
> (putting list.size() in the for() does no or minimal
> difference).
>
> nomatter where in a program scope , microbench or not
> i
> get about factor 3 with nanotime().
>
> jdk1.6b86 -server , same problem on at least both
> 64,32bit JDK and windows. (using a single AMD cpu)

see bug 6348767

>
> regards
> gustav

best

Rémi Forax