Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Testing to which extent method calls affect processig speed

Reply
Thread Tools

Testing to which extent method calls affect processig speed

 
 
Albretch
Guest
Posts: n/a
 
      09-08-2004


I wanted to measurably test how much the stack un/rewinding done by function calls taxes processing speed.

... and the winner is ..., well, as we all knew already, using a C-like structure with all members public is consistently fater. It was actually approx. three times as fast as the Java Bean like class with setters and getters methods

My conclusion is, as long as you -internally- use C Structs-like value objects and they don't get exposed by the API itself, you should go for them.

Would you differ? What is it I am missing here?

// - - - - - START OF CODE
// __ Object's state set at creationg time
class JK00{
private int iI;
private int[] iIAr;
private String aS;
private String[] aSAr;
// __
JK00(int iI, int[] iIAr, String aS, String[] aSAr){
this.iI = iI;
this.iIAr = iIAr;
this.aS = aS;
this.aSAr = aSAr;
}
// __
public int getI(){ return(iI); }
public int[] getIAr(){ return(iIAr); }
public String getS(){ return(aS); }
public String[] getSAr(){ return(aSAr); }
}

// - - - - -
// __ Object state resettable for each single member (Java Bean way)
class JK02{
private int iI;
private int[] iIAr;
private String aS;
private String[] aSAr;
// __
JK02(){}
// __
public void setI(int iI){ this.iI = iI; }
public int getI(){ return(iI); }
// __
public void setIAr(int[] iIAr){ this.iIAr = iIAr; }
public int[] getIAr(){ return(iIAr); }
// __
public void setS(String aS){ this.aS = aS; }
public String getS(){ return(aS); }
// __
public void setSAr(String[] aSAr){ this.aSAr = aSAr; }
public String[] getSAr(){ return(aSAr); }
// __
}

// - - - - -
// __ Object state with a bulk set method and single getters
class JK04{
private int iI;
private int[] iIAr;
private String aS;
private String[] aSAr;
// __
JK04(){}
// __
public void setCtxt(int iI, int[] iIAr, String aS, String[] aSAr){
this.iI = iI;
this.iIAr = iIAr;
this.aS = aS;
this.aSAr = aSAr;
}
// __
public int getI(){ return(iI); }
public int[] getIAr(){ return(iIAr); }
public String getS(){ return(aS); }
public String[] getSAr(){ return(aSAr); }
// __
}

// - - - - -

// __ ANSI C struct-like object
class JK06{
public int iI;
public int[] iIAr;
public String aS;
public String[] aSAr;
// __
JK06(){}
}

// - - - - -
import java.io.*;
import java.util.*;
import java.lang.Math.*;

// __
public class TestStructBean06{
static final boolean IsOutFl = false;
// static final boolean IsOutFl = true;
// __
static void setOutputFile(String azOutFlName){
try{
File Fl = new File(azOutFlName);
FileOutputStream OutFlStrm = new FileOutputStream(Fl);
PrintStream PrntStrm = new PrintStream(OutFlStrm);
System.setOut(PrntStrm);
} catch(IOException IOXcptn){ IOXcptn.printStackTrace(); }
}// setOutputFile(String)

// __
public static void main(String[] azArgs){
String azOFlNm ="PrntOut.txt";
if(IsOutFl)setOutputFile(azOFlNm);
long lTm00, lTtlTm;
int iNewObjs, iTms = 4*4096, iTmsTest=16;
JK00 K00;
JK02 K02;
JK04 K04;
JK06 K06;
// __
int iI;
int[] iIAr;
String aS;
String[] aSAr;
// __
String[][] aA2DAr = new String[][]{
{"The","quick","brown","fox","jumped","over","the" ,"lazy","dog"},
{"quick","brown","fox","jumped","over","the","lazy ","dog"},
{"brown","fox","jumped","over","the","lazy","dog"} ,
{"fox","jumped","over","the","lazy","dog"},
{"jumped","over","the","lazy","dog"},
{"over","the","lazy","dog"},
{"the","lazy","dog"},
{"lazy","dog"},
{"dog"}
};
// __
int[][] i2DAr = new int[aA2DAr.length][];
for(int j = 0; (j < aA2DAr.length); ++j){
i2DAr[j] = new int[(j + 1)];
//System.out.println("|" + j + "|" + i2DAr[j].length + "|");
for(int k = 0; (k < i2DAr[j].length); ++k){
//System.out.println("|" + j + "|" + k + "|" + i2DAr[j].length + "|");
i2DAr[j][k] = k;
}// k
}// j
// __
iNewObjs = iTms*(aA2DAr.length*(aA2DAr.length - 1)/2);
// __
long[][] lTests = new long[4][iTmsTest];
for(int iTest = 0; (iTest < iTmsTest); ++iTest){
System.out.println(" iTest: [" + iTest + "," + iTmsTest + ")");
// __ JK00 Objects
lTm00 = System.currentTimeMillis();
for(int i = 0; (i < iTms); ++i){
for(int j = 0; (j < aA2DAr.length); ++j){
for(int k = 0; (k < aA2DAr[j].length); ++k){
K00 = new JK00(k, i2DAr[k], aA2DAr[j][0], aA2DAr[j]);
// __
iI = K00.getI();
iIAr = K00.getIAr();
aS = K00.getS();
aSAr = K00.getSAr();
// __
}// k
}// j
}// i
lTtlTm = (System.currentTimeMillis() - lTm00);
System.out.println(lTtlTm + " milliseconds needed to create " + iNewObjs + " JK00 Objects.");
lTests[0][iTest] = lTtlTm;

// __ JK02 Objects
lTm00 = System.currentTimeMillis();
K02 = new JK02();
for(int i = 0; (i < iTms); ++i){
for(int j = 0; (j < aA2DAr.length); ++j){
for(int k = 0; (k < aA2DAr[j].length); ++k){
// __
K02.setI(k);
K02.setIAr(i2DAr[k]);
K02.setS(aA2DAr[j][0]);
K02.setSAr(aA2DAr[j]);
// __
iI = K02.getI();
iIAr = K02.getIAr();
aS = K02.getS();
aSAr = K02.getSAr();
// __
}// k
}// j
}// i
lTtlTm = (System.currentTimeMillis() - lTm00);
System.out.println(lTtlTm + " milliseconds needed to create " + iNewObjs + " JK02 Objects.");
lTests[1][iTest] = lTtlTm;

// __ JK04 Objects
lTm00 = System.currentTimeMillis();
K04 = new JK04();
for(int i = 0; (i < iTms); ++i){
for(int j = 0; (j < aA2DAr.length); ++j){
for(int k = 0; (k < aA2DAr[j].length); ++k){
K04.setCtxt(k, i2DAr[k], aA2DAr[j][0], aA2DAr[j]);
// __
iI = K04.getI();
iIAr = K04.getIAr();
aS = K04.getS();
aSAr = K04.getSAr();
// __
}// k
}// j
}// i
lTtlTm = (System.currentTimeMillis() - lTm00);
System.out.println(lTtlTm + " milliseconds needed to create " + iNewObjs + " JK04 Objects.");
lTests[2][iTest] = lTtlTm;

// __ JK04 Objects
lTm00 = System.currentTimeMillis();
K06 = new JK06();
for(int i = 0; (i < iTms); ++i){
for(int j = 0; (j < aA2DAr.length); ++j){
for(int k = 0; (k < aA2DAr[j].length); ++k){
// __
K06.iI = k;
K06.iIAr = i2DAr[k];
K06.aS = aA2DAr[j][0];
K06.aSAr = aA2DAr[j];
// __
iI = K06.iI;
iIAr = K06.iIAr;
aS = K06.aS;
aSAr = K06.aSAr;
// __
}// k
}// j
}// i
lTtlTm = (System.currentTimeMillis() - lTm00);
System.out.println(lTtlTm + " milliseconds needed to create " + iNewObjs + " JK06 Objects.");
lTests[3][iTest] = lTtlTm;

}// [0, iTmsTest)
// __
double[][] d2DAr = getStatsAveDev(lTests);
double dMax = Double.MIN_VALUE;
for(int i = 0; (i < d2DAr.length); ++i){
if(dMax < d2DAr[i][0]){ dMax = d2DAr[i][0]; }
}

// __
System.out.println();
System.out.println(" Test run " + iTmsTest + " times.");
String[] aSArKNms = new String[]{"JK00", "JK02", "JK04", "JK08"};
System.out.println("- - - - - - - - - - - - - - - - - - - - - - - - - -");
System.out.println("|__class__|__ave. (ms)|__dev. (ms)__|_times faster_|");
for(int i = 0; (i < d2DAr.length); ++i){
//System.out.println("|\t" + aSArKNms[i] + "\t|\t" + d2DAr[i][0] + "\t|\t" + d2DAr[i][1] + "\t|\t" + dMax/d2DAr[i][0] + "\t|");

System.out.printf("| %s |% 9.4f |%9.4f |%9.4f |\n", aSArKNms[i], d2DAr[i][0], d2DAr[i][1], dMax/d2DAr[i][0]);
System.out.println("- - - - - - - - - - - - - - - - - - - - - - - - - -");

}
}// main

// __
private static double[][] getStatsAveDev(long[][] lVals){
double[][] d2DAr = new double[lVals.length][2];
double dAve;
double dDev;
double dVal;
// __
int iN = lVals.length;
for(int i = 0; (i < iN); ++i){
dAve = .0;
for(int j = 0; (j < lVals[i].length); ++j){ dAve += lVals[i][j]; }
d2DAr[i][0] = dAve/lVals[i].length;
// __
dDev = .0;
for(int j = 0; (j < lVals[i].length); ++j){
dVal = (1.*lVals[i][j] - d2DAr[i][0]); dDev += dVal*dVal;
}
// __
dDev /= (iN - 1);
d2DAr[i][1] = Math.sqrt(dDev);
}// i
// __
return(d2DAr);
}
}// TestStructBean06


// - - - - - END OF CODE

Test run 2 times.
- - - - - - - - - - - - - - - - - - - - - - - - - -
|__class__|__ave. (ms)|__dev. (ms)__|_times faster_|
| JK00 | 85.5000 | 12.6557 | 1.1696 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK02 | 100.0000 | 0.0000 | 1.0000 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK04 | 85.0000 | 4.0825 | 1.1765 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK08 | 35.0000 | 4.0825 | 2.8571 |
- - - - - - - - - - - - - - - - - - - - - - - - - -

Test run 2 times.
- - - - - - - - - - - - - - - - - - - - - - - - - -
|__class__|__ave. (ms)|__dev. (ms)__|_times faster_|
| JK00 | 85.0000 | 12.2474 | 1.1765 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK02 | 100.0000 | 0.0000 | 1.0000 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK04 | 85.5000 | 3.6742 | 1.1696 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK08 | 30.0000 | 0.0000 | 3.3333 |
- - - - - - - - - - - - - - - - - - - - - - - - - -


Test run 16 times.
- - - - - - - - - - - - - - - - - - - - - - - - - -
|__class__|__ave. (ms)|__dev. (ms)__|_times faster_|
| JK00 | 71.3750 | 24.3019 | 1.4212 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK02 | 101.4375 | 7.5263 | 1.0000 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK04 | 80.0625 | 8.1841 | 1.2670 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK08 | 35.0625 | 11.7038 | 2.8930 |
- - - - - - - - - - - - - - - - - - - - - - - - - -

Test run 16 times.
- - - - - - - - - - - - - - - - - - - - - - - - - -
|__class__|__ave. (ms)|__dev. (ms)__|_times faster_|
| JK00 | 71.3750 | 24.3019 | 1.4203 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK02 | 101.3750 | 7.5664 | 1.0000 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK04 | 81.3750 | 7.5664 | 1.2458 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK08 | 34.4375 | 11.6324 | 2.9437 |
- - - - - - - - - - - - - - - - - - - - - - - - - -



 
Reply With Quote
 
 
 
 
P.Hill
Guest
Posts: n/a
 
      09-09-2004
Albretch wrote:
>using a C-like structure with all members public is consistently fater. It was actually approx. three times as fast as the Java Bean like class with setters and getters methods
> Would you differ? What is it I am missing here?


Yes, I would differ.
This smells like premature optimization to me.

What precentage of the code in an actual app is getter/setter calls?
If it is 1% you have shaved 0.666% off the running of your app.
If it is 10% you have shaved 6% off the running of your app.

I'm still not impressed. You'd better show it it more like 20% percent before
the 13% improvement starts sounding interesting to me.

Having setters and getters is very useful for other reasons.

-Paul

 
Reply With Quote
 
 
 
 
Albretch
Guest
Posts: n/a
 
      09-09-2004
"P.Hill" <(E-Mail Removed)> wrote in message news:<chop5g$roj$(E-Mail Removed)>...
> Albretch wrote:
> >using a C-like structure with all members public is consistently fater. It was actually approx. three times as fast as the Java Bean like class with setters and getters methods
> > Would you differ? What is it I am missing here?

>
> Yes, I would differ.
> This smells like premature optimization to me.
>
> What precentage of the code in an actual app is getter/setter calls?
> If it is 1% you have shaved 0.666% off the running of your app.
> If it is 10% you have shaved 6% off the running of your app.
>
> I'm still not impressed. You'd better show it it more like 20% percent before
> the 13% improvement starts sounding interesting to me.
>
> Having setters and getters is very useful for other reasons.
>
> -Paul


Doesn't 300% faster sound good enough for you?

Maybe I wasn't clear enough, but I used maximal score proratings.
Meaning, I took the slowest\highest value and divided the rest ones by
all other ones. Look at the code.

So when I say 'times_faster' I mean I divided the slowest value by
the one for this entry
 
Reply With Quote
 
Matt Humphrey
Guest
Posts: n/a
 
      09-09-2004

"Albretch" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> "P.Hill" <(E-Mail Removed)> wrote in message

news:<chop5g$roj$(E-Mail Removed)>...
> > Albretch wrote:
> > >using a C-like structure with all members public is consistently fater.

It was actually approx. three times as fast as the Java Bean like class with
setters and getters methods
> > > Would you differ? What is it I am missing here?

> >
> > Yes, I would differ.
> > This smells like premature optimization to me.
> >
> > What precentage of the code in an actual app is getter/setter calls?
> > If it is 1% you have shaved 0.666% off the running of your app.
> > If it is 10% you have shaved 6% off the running of your app.
> >
> > I'm still not impressed. You'd better show it it more like 20% percent

before
> > the 13% improvement starts sounding interesting to me.
> >
> > Having setters and getters is very useful for other reasons.
> >
> > -Paul

>
> Doesn't 300% faster sound good enough for you?
>
> Maybe I wasn't clear enough, but I used maximal score proratings.
> Meaning, I took the slowest\highest value and divided the rest ones by
> all other ones. Look at the code.
>
> So when I say 'times_faster' I mean I divided the slowest value by
> the one for this entry


No one is questioning that you have shown that avoiding an extra layer of
getter / setter methods improves performance. However, any improvement in a
piece of code that comprises only 1% of an application's work is not
necessarily that significant of an improvement, especially when doing so
risks making the design more difficult to build or change. In a sense, your
300% improvement is something like ranking CPU speed based on how fast it
performs no-ops. It presumes that applications do nothing more than get or
set object attributes. Most applications do complex calculations, database
/ storage access, network access, gui control, etc which require only a
small element of attribute / getter setter access. A real sense of the
speed improvement is only meaningful by knowing the frequency getters and
setters are used in an application as a whole.

Cheers,
Matt Humphrey http://www.velocityreviews.com/forums/(E-Mail Removed) http://www.iviz.com/


 
Reply With Quote
 
Michael Borgwardt
Guest
Posts: n/a
 
      09-09-2004
Albretch wrote:

> ... and the winner is ..., well, as we all knew already, using a C-like structure with all members public is consistently fater. It was actually approx. three times as fast as the Java Bean like class with setters and getters methods


Nope, it's not.

> My conclusion is, as long as you -internally- use C Structs-like value objects and they don't get exposed by the API itself, you should go for them.


Even if the speed difference really existed, it would still hurt the maintainability
of your code.

> Would you differ? What is it I am missing here?


Apart from the other poster's point (that you didn't get):

That code is damn near obfuscated, so I can't even begin to look for
details of the methodology, but your absolute measured times are
too small on a modern machine, so the granularity of the system
clock has a considerable impact.

But the main thing you missed is the existence of the server VM, which
is expecially aggressive about (and successful at) inlining methods,
thereby completely destroying the speed advantages of field access.

This is the result when I run your program on my 2.0 GHz P4 with java -server
using Sun's SDK 1.4.2_04 and making the following podifications:

- fewer repeats, but bigger internal loops:
int iNewObjs, iTms = 256 * 4096, iTmsTest = 4;

- replace unavailable printf() call by string concatenation


Test run 4 times.
- - - - - - - - - - - - - - - - - - - - - - - - - -
|__class__|__ave. (ms)|__dev. (ms)__|_times faster_|
| JK00 | 2763.75 | 276.7554576396522 | 1.0 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK02 | 836.5 | 611.654314135035 | 3.3039450089659295 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK04 | 558.25 | 88.63925014724948 | 4.9507389162561575 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
| JK08 | 533.25 | 32.25290684574028 | 5.182841068917019 |
- - - - - - - - - - - - - - - - - - - - - - - - - -
 
Reply With Quote
 
P.Hill
Guest
Posts: n/a
 
      09-09-2004
Albretch wrote:
> Would you differ? What is it I am missing here?


Let's continue on this original question.
What you are missing is:
The ability to write code such that it tells me what it is doing.
There is little comments of intent and your report of the results
explains nothing. Only your post said 3x better times for set/get vs direct
access. Otherwise what statistics you gathered and what you
want to do with them is defined no where.

Sharing a cryptic chart with 1000s of people without more verbage about the
chart is silly. All it tells me is that there is an "avg.(ms)" of something,
but we can guess it is the runs mentioned above, something called a dev (but is
usually called STD, AKA standard
deviation), and something called "times faster". Apparently
we're supposed to take the time to figure out why the second
line of the table is the 100% value we are comparing to the others.

And what's with all the output to a file, but you don't show us that?

Do you really think code such as
> }// [0, iTmsTest)

is useful for somebody looking at it?

Your hungarian notation is sick, just plain sick.
i2DAr vs. aA2DAr etc. is supposed to communicate something?
Even if I decode your hungarian notation all I get is that
we are working with the second array of each. Now why
would that be the most useful information to know?

And these: JK00, JK02, JK04, JK04
have got to be the poorest named classes I've seen in
a long time. If you want to write like that try some assembler
from the early 70's.

> return(d2DAr);


FWIW, the parenthesis around a return value are not needed in
either C or Java, despite its idiomatic appearance in
K&R I and K&R II and hence many other books.

Suggestion 1: Learn to communicate to other humans, now that you know
how to communicate to the computer.

Suggestion 2: Figure out where optimization is needed before you
attempt to optimize.

-Paul

 
Reply With Quote
 
P.Hill
Guest
Posts: n/a
 
      09-09-2004
Michael Borgwardt was kind enough to bother with the cryptic code and tried
it on an optimizing VM. I have tiddied up the results and
noted what JK00, JK02, JK04 and JK08 seem to be.

> Test run 4 times.
> - - - - - - - - - - - - - - - - - - - - - - - - - -
> |__class__|__ave. (ms)|__dev. (ms)__ |_times faster_ |
> | JK00 | 2763.75 | 276.7554576396522 | 1.0 | c-tor set, 4 getters
> - - - - - - - - - - - - - - - - - - - - - - - - - -
> | JK02 | 836.5 | 611.654314135035 | 3.3039450089659295 | 4 setters, 4 getters
> - - - - - - - - - - - - - - - - - - - - - - - - - -
> | JK04 | 558.25 | 88.63925014724948 | 4.9507389162561575 | 1 4-arg set, 4 getters
> - - - - - - - - - - - - - - - - - - - - - - - - - -
> | JK08 | 533.25 | 32.25290684574028 | 5.182841068917019 | 4 public members
> - - - - - - - - - - - - - - - - - - - - - - - - - -


If Michael ran the same objects as Albretch, which is what he claimed, Michaels
results have the 4 public member variation at 57% overhead as compared with 4
setters and 4 getters. So if time spent calling setters and getters was 10% of
the total of time spent in a program, I'd actually increase by another 5-6% the
runtime of the program!

That's curious results, I wonder if the VM as dropped a few sets/gets just
because the didn't result in anything.

Whatever,
-Paul

 
Reply With Quote
 
Joona I Palaste
Guest
Posts: n/a
 
      09-09-2004
Albretch <(E-Mail Removed)> scribbled the following:
> Maybe I wasn't clear enough, but I used maximal score proratings.
> Meaning, I took the slowest\highest value and divided the rest ones by
> all other ones. Look at the code.


That's "slowest/highest". "Slowest - frigging / - highest". Just
because Microsoft insists on non-standard typography doesn't mean the
whole world has to.
Nothing against you personally, Albretch. This has been bugging me for
years and I have to let it out occasionally.

--
/-- Joona Palaste ((E-Mail Removed)) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"When a man talks dirty to a woman, that's sexual harassment. When a woman talks
dirty to a man, that's 14.99 per minute + local telephone charges!"
- Ruben Stiller
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      09-09-2004
P.Hill wrote:

> That's curious results, I wonder if the VM as dropped a few sets/gets just
> because the didn't result in anything.


I haven't looked at this specific case, but Sun's "server" JVM is /definitely/
capable of destroying simple benchmarks by optimising away code that has no
detectable effect.

-- chris



 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      09-09-2004
I wrote:

> I haven't looked at this specific case, but Sun's "server" JVM is
> /definitely/ capable of destroying simple benchmarks by optimising away
> code that has no detectable effect.


Since posting that, I've realised that it might give the impression that the
"client" JVM is not capable of eliminating dead code. This is not the case,
I've had to re-write (trivial) benchmarks for both VMs to prevent them from
optimising the test code away altogether -- the difference is that the "server"
VM is noticeably better at it.

-- chris



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
To what extent will WPA reduce throughput? and the cause of thisreduction? MingChingMin@yahoo.com.hk Wireless Networking 5 03-28-2008 09:29 AM
Menu Does Not Extent to Bottom of Page Matt White HTML 8 08-13-2007 09:31 PM
jdk1.6: "javac -nowarn" does not work, "to some extent" chunji08@gmail.com Java 0 02-09-2007 10:11 PM
GA/optimizer frameworks with automatic adjustment of mut/cross extent? robert Python 0 12-10-2006 09:15 PM
Extent of the "as-if" rule Sidney Cadot C Programming 145 02-01-2004 01:00 AM



Advertisments