<html><body><div style="color:#000; background-color:#fff; font-family:times new roman, new york, times, serif;font-size:12pt"><div><span>Here's my benchmarking code.&nbsp; I don't see at all why a virtual call to Integer.hashCode is so much slower than the base line loop skeleton + inline access to member value of Integer (3rd case) + 0.5 nanos of vtable call (measured in a separate benchmark).</span></div><div style="color: rgb(0, 0, 0); font-size: 16px; font-family: times new roman,new york,times,serif; background-color: transparent; font-style: normal;"><br><span></span></div><div style="color: rgb(0, 0, 0); font-size: 16px; font-family: times new roman,new york,times,serif; background-color: transparent; font-style: normal;"><span>To me, this indicates a serious design flaw in so-called intrinsic call on modern fast machines that could be corrected (were it possible) by making hashCode() a normal non-native function that forwards to
 System.identityHashCode().<br></span></div><div style="color: rgb(0, 0, 0); font-size: 16px; font-family: times new roman,new york,times,serif; background-color: transparent; font-style: normal;"><br><span></span></div><div style="color: rgb(0, 0, 0); font-size: 16px; font-family: times new roman,new york,times,serif; background-color: transparent; font-style: normal;"><span>...</span></div><div style="color: rgb(0, 0, 0); font-size: 16px; font-family: times new roman,new york,times,serif; background-color: transparent; font-style: normal;"><br><span></span></div><div style="color: rgb(0, 0, 0); font-size: 16px; font-family: times new roman,new york,times,serif; background-color: transparent; font-style: normal;"><span>package test;<br><br>public class Test {<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; private static final int&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; LEN = 64;<br>&nbsp;&nbsp;&nbsp; private static final int&nbsp;&nbsp;&nbsp;
 &nbsp;&nbsp;&nbsp; HALFLEN = LEN/2;<br>&nbsp;&nbsp;&nbsp; private static final int&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; MASK = HALFLEN-1;<br>&nbsp;&nbsp;&nbsp; private static final long&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; TENGIG = 10000000000L;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; private static int sum (Object[] ar, long cnt, int mask)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int sum = 0;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (long i = 0; i &lt; cnt; i++)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += ar[(int)i &amp; mask].hashCode();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return sum;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; private static int sum (Integer[] ar, long cnt, int mask)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int sum = 0;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (long i = 0; i &lt; cnt; i++)<br>&nbsp;&nbsp;&nbsp;
 &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += ar[(int)i &amp; mask].hashCode();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return sum;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; public static void main (String[] args)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Object[] ar1 = new Object[LEN];<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; LEN; i++)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ar1[i] = new Object();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Object[] ar2 = new Object[LEN];<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; LEN; i++)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ar2[i] = i &lt; HALFLEN ? new Integer(i) : new Object();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Integer[] ar3 = new Integer[LEN];<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; LEN; i++)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
 ar3[i] = new Integer(i);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; long m1, m2;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int sum = 0;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 10000; i++)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += sum(ar1, 10000, MASK);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m1 = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += sum(ar1, TENGIG, MASK);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m2 = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Object.hashCode() " + (m2-m1));<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 10000; i++)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += sum(ar2, 10000, MASK);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m1 =
 System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += sum(ar2, TENGIG, MASK);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m2 = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("vtable using Integer.hashCode() " + (m2-m1));<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 10000; i++)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += sum(ar3, 10000, MASK);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m1 = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sum += sum(ar3, TENGIG, MASK);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m2 = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("inline using Integer.hashCode() " + (m2-m1));<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("just to make sure everything executes " + sum);<br>&nbsp;&nbsp;&nbsp;
 }<br>}<br><br></span></div><div><br></div>  <div style="font-family: times new roman, new york, times, serif; font-size: 12pt;"> <div style="font-family: times new roman, new york, times, serif; font-size: 12pt;"> <div dir="ltr"> <hr size="1">  <font face="Arial" size="2"> <b><span style="font-weight:bold;">From:</span></b> Vitaly Davidovich &lt;vitalyd@gmail.com&gt;<br> <b><span style="font-weight: bold;">To:</span></b> Andy Nuss &lt;andrew_nuss@yahoo.com&gt; <br><b><span style="font-weight: bold;">Cc:</span></b> hotspot compiler &lt;hotspot-compiler-dev@openjdk.java.net&gt; <br> <b><span style="font-weight: bold;">Sent:</span></b> Monday, May 13, 2013 10:20 AM<br> <b><span style="font-weight: bold;">Subject:</span></b> Re: performance surprise with Object.hashCode()<br> </font> </div> <div class="y_msg_container"><br>
<div id="yiv1582620224"><div dir="ltr">Object.hashCode is an intrinsic (see libraryCall.cpp), so it makes sense you don't see any difference with your changes.</div>
<div dir="ltr">Looking at the assembly, when it knows statically that Integer is receiver it simply reads the value field inline.&nbsp; When it doesn't know, it loads the address of the receiver's hashCode method and compares against Object.hashCode.&nbsp; If equal, then it proceeds with pulling hash out of header.&nbsp; If it's not, it jumps to a vcall and then jumps again to function prologue.&nbsp; I don't really see why you'd get such a large discrepancy.&nbsp; The only thing is that if hashCode is overridden it jumps around a bit and may get icache miss, but that would happen with plain vcall too.&nbsp; So basically only thing "special" (in terms of vcall) I see for hashCode is a check against an immediate (for seeing if hashCode is overridden or not), a forward (short) jump to skip native object.hashCode impl and that's it.</div>

<div dir="ltr">Sent from my phone</div>
<div class="yiv1582620224gmail_quote">On May 13, 2013 11:45 AM, "Andy Nuss" &lt;<a rel="nofollow" ymailto="mailto:andrew_nuss@yahoo.com" target="_blank" href="mailto:andrew_nuss@yahoo.com">andrew_nuss@yahoo.com</a>&gt; wrote:<br><blockquote class="yiv1582620224gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div><div style="font-size:12pt;font-family:times new roman, new york, times, serif;"><div>Hi,</div><div><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
I was profiling various aspects of the JVM and hit a big surprise.</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
* on my corei7, virtual calls are about .5 nanos</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">* when a class has not derived a new behavior for hashCode(),
 this hashCode call is 1.5 nanos because native</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">* for java.lang.Integer, which just returns the intValue(), hashCode is zero time when hotspot can inline</div>
<div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">(that is about one clock cycle when testing hits the same Integer instances keeping them in L1 cache)<br>
</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">* but when you force HotSpot to go thru the vtable for Integer.hashCode, the call grows to 4 nanos!</div>
<div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
The last case was a big surprise, as I thought for Integer, a vcall to hashCode would only cost the 0.5 nanos of the vtable.</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
<br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">Somehow, native code is involved even when hashCode() has been subclassed to not be native.<br>
</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
...</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
Then I tried mucking with the code in openjdk.&nbsp; I compiled the sources.&nbsp; I edited Object.java to be this:</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
<br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">public class Object {</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
&nbsp;&nbsp;&nbsp; public int hashCode ()</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">&nbsp;&nbsp;&nbsp; {</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return System.identityHashCode(this);</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">&nbsp;&nbsp;&nbsp; }</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
}</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
To me, this seems like an ideal fix to this serious performance bug, making the entry point NON-native, but having the same effect by default.&nbsp; So that if you subclass, you are sure not to pay a doubled(!) native cost.</div>
<div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
But changing the source code had no effect on the results.&nbsp; Nor did it have any affect on /share/native/java/lang/Object.c.</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
<br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">In both cases, with and without my change to the definition of Object.java, Object.c has NO native function definition for the hashCode function.</div>
<div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
This leads me to believe that this performance defect is endemic to the hotspot compiler code itself, in that it special cases the Object.hashCode() function.</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
<br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">It seems that if somehow this performance defect (as I see it) where fixed, String hashing and Integer hashing and the like for classes which cache their hashvalue would be greatly improved.</div>
<div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
???</div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;"><br></div><div style="font-style:normal;font-size:16px;background-color:transparent;font-family:times new roman, new york, times, serif;">
Andy</div></div></div></blockquote></div>
</div><br><br></div> </div> </div>  </div></body></html>