Do any Java compilers or JVMs optimize getter method calls?

D

david.karr

I prefer to reference instance variables through getters, as opposed
to direct access to them. However, there's "obviously" going to be a
small time penalty for that. I did some timings in Eclipse, and I
found direct reads were a tiny fraction faster than through the getter
call (no surprise), and the difference between the setter and a direct
write was even smaller (I tested 100000000 iterations, adding up the
nanosecond intervals of each type of access).

I'm wondering whether there are any compiler/JVM combinations that
optimize getter calls to be the same as a direct access? I can see
from the bytecode in Eclipse that there is no optimization at that
level, but I don't know if the JVM will do any optimization in some
cases. It didn't appear to do it in Eclipse, but I don't know if other
JVMs would act differently.
 
L

Lew

david.karr said:
I prefer to reference instance variables through getters, as opposed
to direct access to them. However, there's "obviously" going to be a
small time penalty for that. I did some timings in Eclipse, and I
found direct reads were a tiny fraction faster than through the getter
call (no surprise), and the difference between the setter and a direct
write was even smaller (I tested 100000000 iterations, adding up the
nanosecond intervals of each type of access).

I'm wondering whether there are any compiler/JVM combinations that
optimize getter calls to be the same as a direct access? I can see
from the bytecode in Eclipse that there is no optimization at that
level, but I don't know if the JVM will do any optimization in some
cases. It didn't appear to do it in Eclipse, but I don't know if other
JVMs would act differently.

You cannot tell optimization from the bytecode, because optimization happens
in the JVM.

Doesn't Eclipse use the JVM installed on your system? What JVM is installed
on your system?

What options are you passing to the JVM now?

The most significant optimizations occur with the "-server" option to the
"java" command (or equivalent). Others are possible. They are documented on
java.sun.com and elsewhere.

Methods declared as 'final' tend to be inlined and run faster than methods not
so qualified.

When running your benchmarks, let the loop run a bunch of times before you
start timing. That lets the Hotspot compiler analyze the run and figure out
what to optimize.

The tricky thing with Hotspot is that it might inline or enregister or loop
unroll or compile certain things at some times, then de-optimize them at other
times depending on the moment-by-moment profile of the execution.

The compiler (i.e., "javac") tends to have negligible impact on optimization,
since optimization happens at run time.
 
J

Joshua Cranmer

david.karr said:
I'm wondering whether there are any compiler/JVM combinations that
optimize getter calls to be the same as a direct access?

From a cursory glance at the OpenJDK source code, hotspot does try to
inline accessors.
 
D

David Karr

You cannot tell optimization from the bytecode, because optimization happens
in the JVM.

Yes, I know, I was just pointing out the bytecode wasn't already pre-
optimized.
Doesn't Eclipse use the JVM installed on your system?  What JVM is installed
on your system?

Yes. I've tested with Sun's 1.5.0_19, 1.6.0_14, and 1.6.0_16.
What options are you passing to the JVM now?

The most significant optimizations occur with the "-server" option to the
"java" command (or equivalent).  Others are possible.  They are documented on
java.sun.com and elsewhere.

I wasn't using "-server" before, but I am now. That's a useful
change.
Methods declared as 'final' tend to be inlined and run faster than methods not
so qualified.

When running your benchmarks, let the loop run a bunch of times before you
start timing.  That lets the Hotspot compiler analyze the run and figure out
what to optimize.

I'm also using both of these strategies. I'm running 100000000 timed
iterations, so I doubt the warm-up loop is necessary, but I'm doing
that anyway.

My measurements show very tiny differences (perhaps .02% total
difference over all 100000000 iterations). In fact, emphasizing the
fact that this isn't statistically significant, I saw several runs
where the "direct" test was slightly slower than the "getter" test.

If it matters, following this is my test class.

------Timings.java----------
package timings;

public class Timings {

private String foo;

final public String getFoo() {return foo;}
final public void setFoo(String foo) {this.foo = foo;}

public static void main(String[] args) {
Timings timings = new Timings(args);
timings.go();
}

public Timings(String[] args) {}

private void go() {

// warmup loop.
for (int ctr = 0; ctr < 1000; ++ ctr) {
setFoo(ctr + "");
getFoo();
this.foo = this.foo + "";
}

int iters = 10000000;

long totalns;

totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
setFoo(ctr + "");
long startTime = System.nanoTime();
String val = getFoo();
totalns += (System.nanoTime() - startTime);
}
System.out.println("getter[" + totalns + "]");

totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
setFoo(ctr + "");
long startTime = System.nanoTime();
String val = this.foo;
totalns += (System.nanoTime() - startTime);
}
System.out.println("direct[" + totalns + "]");

totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
long startTime = System.nanoTime();
setFoo(ctr + "");
totalns += (System.nanoTime() - startTime);
}
System.out.println("setter[" + totalns + "]");

totalns = 0;
for (int ctr = 0; ctr < iters; ++ ctr) {
long startTime = System.nanoTime();
this.foo = ctr + "";
totalns += (System.nanoTime() - startTime);
}
System.out.println("direct[" + totalns + "]");
}
}
--------------------
 
R

Roedy Green

I'm wondering whether there are any compiler/JVM combinations that
optimize getter calls to be the same as a direct access?

this is one of the hotspot optimisations. I takes a while for the JVM
to optimise a routine. It can inline many small routines, not just
getters.

If you want it done immediately, you need static optimisation at
compile time with Jet.
see http://mindprod.com/jgloss/jet.html

--
Roedy Green Canadian Mind Products
http://mindprod.com

"People think of security as a noun, something you go buy. In reality, it’s an abstract concept like happiness. Openness is unbelievably helpful to security."
~ James Gosling (born: 1955-05-18 age: 54), inventor of Java.
 
K

Karl Uppiano

David Karr said:
david.karr wrote:
[...]

My measurements show very tiny differences (perhaps .02% total
difference over all 100000000 iterations). In fact, emphasizing the
fact that this isn't statistically significant, I saw several runs
where the "direct" test was slightly slower than the "getter" test.

Given the infinitesimal advantage of direct calls, it seems you could focus
your optimization efforts elsewhere to much more advantage. I have always
found that a solid design is much more effective at achieving high
performance than speculative optimization. The exception to this rule would
be if profiling revealed that you were spending an inordinate amount of time
calling getters.
 
L

Lothar Kimmeringer

david.karr said:
I'm wondering whether there are any compiler/JVM combinations that
optimize getter calls to be the same as a direct access?

As already mentioned this is done by the Hotspot. Maybe the
Hotspot inlines faster, if you declare the getter-method
final. On the other hand, why do you bother with this kind
of optimization? Do you have real performance-problems?

If not, just let it be the way it is (with getters and setters)
and concentrate on something else. I had to solve a couple
of problems and never it was a simple getter that caused the
problem but some inefficient algorithm.


Regards, Lothar
--
Lothar Kimmeringer E-Mail: (e-mail address removed)
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)

Always remember: The answer is forty-two, there can only be wrong
questions!
 
L

Lothar Kimmeringer

Karl said:
I have always
found that a solid design is much more effective at achieving high
performance than speculative optimization. The exception to this rule would
be if profiling revealed that you were spending an inordinate amount of time
calling getters.

And if that is the case, the use of a cached value (assuming
that the getter-method returned the same value all the time)
should be a much better solution than changing the access
from the call of a getter to the direct access of the field.


Regards, Lothar
--
Lothar Kimmeringer E-Mail: (e-mail address removed)
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)

Always remember: The answer is forty-two, there can only be wrong
questions!
 
A

Andreas Leitgeb

David Karr said:
If it matters, following this is my test class.
------Timings.java----------
package timings;
public class Timings {
[...]
// warmup loop.
for (int ctr = 0; ctr < 1000; ++ ctr) { ... }

Good, but I'd spend like 100000 iterations to warmup, or even
place two loops ... Probably not more than Voodoo, but I think
it helped in a previous case for me. (I had a loop over the
actual measurement loops, and the first two complete runs of
inner loops took noticeably more time than each of the following
ones)
int iters = 10000000;
for (int ctr = 0; ctr < iters; ++ ctr) {
setFoo(ctr + "");
long startTime = System.nanoTime();
String val = getFoo();
totalns += (System.nanoTime() - startTime);
}

I wouldn't do it that way, but rather take the nanos before and
after the inner loop. The loop-overhead is probably less than the
time-taking overhead. If it isn't then differences of getter-
timings compared to loop-overhead makes the matter even more moot.

Also, you could make the attribute an int and assign it the current
loop-counter. that will reduce the overhead for generating a new
value to set before getting it.

PS: Since a recent "adventure" with an oracle-sql query, my trust in
automatic optimizations is currently lower than ever. (although java-
optimizations have nothing to do with (absent) oracle-optimizations)
 
R

Roedy Green

Yes, I know, I was just pointing out the bytecode wasn't already pre-
optimized.

One of the amusing things is if you optimise the byte code it can make
the code SLOWER, because Hotspot and other optimisers don't have the
clutzy standard patterns to recognise.

I poked around quite a bit at the assembler generated by Jet. I was
blown away by what it did. It was faster than any sane human would
write. It took into account not just the official number of cycles
per instruction, but the internal parallelisation of the chips and the
pipelines.

Unfortunately, the Jet people were freaked by this and removed the
tool to display the assembler code. They sell Jet not so much as an
optimiser as an obfuscator. They felt my discussion of how it worked
inside make it look as if it were easy to disassemble, which it most
definitely is not.



--
Roedy Green Canadian Mind Products
http://mindprod.com

"People think of security as a noun, something you go buy. In reality, it’s an abstract concept like happiness. Openness is unbelievably helpful to security."
~ James Gosling (born: 1955-05-18 age: 54), inventor of Java.
 
L

Lew

Lothar said:
And if that is the case, the use of a cached value (assuming
that the getter-method returned the same value all the time)
should be a much better solution than changing the access
from the call of a getter to the direct access of the field.

This is an optimization of which HotSpot is capable.
 
R

Roedy Green

The compiler cannot do any inlining because called method implementation is
not actually known until runtime (IOW the class file containing method
implementation can be replaced after compilation).

Hotspot inlines even non final methods. If a class gets loaded that
overrides a method, it undoes the inlining on the fly -- talk about
trapeeze act without a net. It can do this even if it is the middle
of executing a method at the time. I have a hard time believing this
could possibly work.

A byte-code compiler could inline final methods, but not non-final
ones.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"People think of security as a noun, something you go buy. In reality, it’s an abstract concept like happiness. Openness is unbelievably helpful to security."
~ James Gosling (born: 1955-05-18 age: 54), inventor of Java.
 
L

Lothar Kimmeringer

Lew said:
This is an optimization of which HotSpot is capable.

To be honest, I don't care what the HotSpot is capable to do.
If a profiler shows me that the call of a specific get-method
is the reason why some code of mine takes significantly longer
than it should be, I don't hope that the HotSpot might take
care of it but do it for myself.

Or in other (well known) words: Premature optimization is the
root of all evil. David's giving a good example. Using a direct
field-access instead of a getter-method will lead to a lot of
trouble if at a later point of time you need additional logic
before handing out the result, e.g. cloning an internal array
instead of giving out the original, etc.


Regards, Lothar
--
Lothar Kimmeringer E-Mail: (e-mail address removed)
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)

Always remember: The answer is forty-two, there can only be wrong
questions!
 
D

David Karr

david.karr wrote:
[...]

My measurements show very tiny differences (perhaps .02% total
difference over all 100000000 iterations).  In fact, emphasizing the
fact that this isn't statistically significant, I saw several runs
where the "direct" test was slightly slower than the "getter" test.

Given the infinitesimal advantage of direct calls, it seems you could focus
your optimization efforts elsewhere to much more advantage. I have always
found that a solid design is much more effective at achieving high
performance than speculative optimization. The exception to this rule would
be if profiling revealed that you were spending an inordinate amount of time
calling getters.

You've missed the point, perhaps because I didn't make it clear why I
was experimenting with this. I prefer calling getters instead of
direct access. I did this research because I expect to be called on
this in code reviews with claims that calling getters would be slower
than direct access.
 
L

Lew

David said:
You've missed the point, perhaps because I didn't make it clear why I
was experimenting with this.  I prefer calling getters instead of
direct access.  I did this research because I expect to be called on
this in code reviews with claims that calling getters would be slower
than direct access.

If anyone did "call" you on using accessor methods based on some
imagined performance penalty, even without benchmarking yourself you
can counteract such a blatantly ridiculous criticism by pointing out
how blatantly ridiculous such a criticism is.

Start by asking them what proof they have that accessor methods are
even slower than direct access, let alone sufficiently slower that it
matters, then ask how such an unproven difference in speed compensates
for the loss of maintainability and encapsulation. Then suggest that
their skills would be of better use in an environment where they're
mostly asking, "Would you like fries with that?"
 
L

Lew

Eric Sosman said:
     In mathematics, this technique is known as Proof by Assertion.
(Some know it as the Because I Said So argument.)

Mitigated in this particular instance by the fact that the argument
the OP fears is actually blatantly ridiculous. Proof of the blatant
ridiculosity was left as an exercise. (A very popular pedagocical
dodge in all my old math textbooks.)

Lew:
Eric:
     In debate, this technique is known as Force the Adversary to
Hold His Ground No Matter What.  (Some know it as the Feel-Good
Moment Before the Roof Caves In.)

In the Bible it's called, "Never answer a fool in terms of his folly,
lest he think himself wise." Personally I get so disgusted with
people in code reviews trying to get me to do the wrong thing that I
lose the willingness to treat them as rational beings.

Don't misconstrue. Plenty of people disagree with me and can provide
intelligent reasoning for doing so. This newsgroup is a great
example. That is not a problem. It's people trying to make really
stupid cases, like, "You shouldn't use accessor methods in Java
because direct references to member variables is faster," that gets
me.

You ignored the expressed reasoning behind my points, that the
putative advantage of direct variable access asserted by the stupid
reviewers must be proven to exist at all, let alone to a degree that
justifies the sacrifice of accessors' advantages. Since you're good
at identifying the names for rhetorical dodges, what should such
omission be called?
 
D

David Karr

If anyone did "call" you on using accessor methods based on some
imagined performance penalty, even without benchmarking yourself you
can counteract such a blatantly ridiculous criticism by pointing out
how blatantly ridiculous such a criticism is.

Start by asking them what proof they have that accessor methods are
even slower than direct access, let alone sufficiently slower that it
matters, then ask how such an unproven difference in speed compensates
for the loss of maintainability and encapsulation.  Then suggest that
their skills would be of better use in an environment where they're
mostly asking, "Would you like fries with that?"

I started this experiment because I don't like to ask questions that I
don't know the answer to :), if I can help it. If I was challenged on
this, I would ask "have you measured it?". When they answer "no, it's
obvious", that's when I can say "I've measured it and researched it,
and it's not obvious."
 
L

Lew

Eric said:
     "Praeterition."

What a fabulous word!

As a rhetorical device, that usually involves bragging about the
omission, as the example at
<http://en.wiktionary.org/wiki/Praeterition>
shows.

The rhetorical device of praeterition also emphasizes the "omitted"
part, as in, "I do not intend to draw attention to the compelling and
irrefutable logic presented to support the rejection of bad advice in
code reviews. Instead I will focus on the rhetorical devices used to
express that logic."
 
E

Eric Sosman

Lew said:
[...]
Eric said:
"Praeterition."

What a fabulous word!

Tip the hat to my high school Latin teacher, Theodore
Hersey. He had a penchant for trying to simplify things by
explaining them in terms of things more abstruse. So when
we came to the verb "praetereo" (I pass over), he told us
tenth-graders, ever so soothingly, that this was where we got
the familiar English word "praeterition."

We were oh! so! grateful ...

(This is the same guy who explained a construction called
the "passive periphrastic" by telling us "Don't worry about that
word `periphrasis;' it's just Greek for `circumlocution'").

(On the more vital side, he promised an "A For Life" to
anyone who could render "Them ain't clams, them's quahogs"
in idiomatic Latin. Nobody ever collected.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,832
Latest member
UtaHetrick

Latest Threads

Top