I have updated the webrev to remove the useAltHashing boolean. http://cr.openjdk.java.net/~mduigou/JDK-8006593/5/webrev/
Mike On Mar 5 2013, at 00:43 , Peter Levart wrote: > Hi Mike, > > You could also get rid of boolean useAltHashing field in both HashMap and > Hashtable. It saves 8 bytes in both HM and HT objects in 32bit addressing > modes (64bit addressing modes are not affected due to different alignment). > Like the following (a patch against your webrev): > > Index: jdk/src/share/classes/java/util/Hashtable.java > =================================================================== > --- jdk/src/share/classes/java/util/Hashtable.java (date 1362469665000) > +++ jdk/src/share/classes/java/util/Hashtable.java (revision ) > @@ -213,12 +213,6 @@ > } > > /** > - * If {@code true} then perform alternative hashing of String keys to > reduce > - * the incidence of collisions due to weak hash code calculation. > - */ > - transient boolean useAltHashing = false; > - > - /** > * A randomizing value associated with this instance that is applied to > * hash code of keys to make hash collisions harder to find. > */ > @@ -228,8 +222,8 @@ > * Initialize the hashing mask value. > */ > final boolean initHashSeedAsNeeded(int capacity) { > - boolean currentAltHashing = useAltHashing; > - useAltHashing = sun.misc.VM.isBooted() && > + boolean currentAltHashing = hashSeed != 0; > + boolean useAltHashing = sun.misc.VM.isBooted() && > (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); > boolean switching = currentAltHashing ^ useAltHashing; > if (switching) { > Index: jdk/src/share/classes/java/util/HashMap.java > =================================================================== > --- jdk/src/share/classes/java/util/HashMap.java (date 1362472425000) > +++ jdk/src/share/classes/java/util/HashMap.java (revision ) > @@ -224,17 +224,11 @@ > } > > /** > - * If {@code true} then perform alternative hashing of String keys to > reduce > - * the incidence of collisions due to weak hash code calculation. > - */ > - transient boolean useAltHashing = false; > - > - /** > * A randomizing value associated with this instance that is applied to > - * hash code of keys to make hash collisions harder to find. Initialized > via > - * sun.misc.Unsafe when needed. > + * hash code of keys to make hash collisions harder to find. > + * Also used (when != 0) to indicate use of alternative String hashing. > */ > - transient int hashSeed = 0; > + transient int hashSeed; > > /** > * Constructs an empty <tt>HashMap</tt> with the specified initial > @@ -319,8 +313,8 @@ > * really need it. > */ > final boolean initHashSeedAsNeeded(int capacity) { > - boolean currentAltHashing = useAltHashing; > - useAltHashing = sun.misc.VM.isBooted() && > + boolean currentAltHashing = hashSeed != 0; > + boolean useAltHashing = sun.misc.VM.isBooted() && > (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); > boolean switching = currentAltHashing ^ useAltHashing; > if (switching) { > @@ -339,12 +333,9 @@ > * in lower bits. Note: Null keys always map to hash 0, thus index 0. > */ > final int hash(Object k) { > - int h = 0; > - if (useAltHashing) { > - if (k instanceof String) { > + int h = hashSeed; > + if (h != 0 && k instanceof String) { > - return sun.misc.Hashing.stringHash32((String) k); > + return sun.misc.Hashing.stringHash32((String) k); > - } > - h = hashSeed; > } > > h ^= k.hashCode(); > > > Regards, Peter > > On 03/05/2013 07:08 AM, Mike Duigou wrote: >> After looking more closely at the single read reference to hashSeed I >> decided to simplify things and make hashSeed non-final in both Hashtable and >> HashMap. >> >> I've posted a refreshed webrev. >> >> http://cr.openjdk.java.net/~mduigou/JDK-8006593/4/webrev/ >> >> Mike >> >> On Mar 4 2013, at 14:25 , Peter Levart wrote: >> >>> >>> On 03/04/2013 11:14 PM, Peter Levart wrote: >>>> Hi mike, >>>> >>>> I doubt (haven't tried it really with your code) that hashSeed will be >>>> seen by code to be anything else but 0, since it is initialized to a >>>> constant value. For example, this code: >>>> >>>> public class ModifyingFinalTest { >>>> static final Unsafe unsafe; >>>> static final long valueOffset; >>>> >>>> static { >>>> try { >>>> Field f = Unsafe.class.getDeclaredField("theUnsafe"); >>>> f.setAccessible(true); >>>> unsafe = (Unsafe)f.get(null); >>>> valueOffset = >>>> unsafe.objectFieldOffset(ModifyingFinalTest.class.getDeclaredField("value")); >>>> } >>>> catch (IllegalAccessException | NoSuchFieldException e) { >>>> throw new Error(e); >>>> } >>>> } >>>> >>>> final int value = 0; >>>> >>>> void test() { >>>> unsafe.putIntVolatile(this, valueOffset, 1); >>>> printValue(); >>>> unsafe.putIntVolatile(this, valueOffset, 2); >>>> printValue(); >>>> unsafe.putIntVolatile(this, valueOffset, 3); >>>> printValue(); >>>> } >>>> >>>> void printValue() { >>>> System.out.println(value); >>>> } >>>> >>>> public static void main(String[] args) { >>>> new ModifyingFinalTest().test(); >>>> } >>>> } >>>> >>>> >>>> Prints: >>>> >>>> 0 >>>> 0 >>>> 0 >>>> >>>> >>>> It's a different thing, if the initialization is changed to: >>>> >>>> final int value = "".length(); >>>> >>>> But I don't know if each access in source is actually guaranteed to >>>> translate to a real read of field in this case either. Is >>>> Unsafe.putIntVolatile() making this happen somehow magically? >>> >>> Well, that's not what I wanted to ask. I wanted to ask if the first access >>> in source that happens after Unsafe.putIntVolatile() in same thread is >>> guaranteed to read the field and not re-use a cached value ready in some >>> register for example. Is Unsafe.putIntVolatile() making this happen somehow >>> magically? >>> >>>> >>>> Regards, Peter >>>> >>>> >>>> On 03/04/2013 09:21 PM, Mike Duigou wrote: >>>>> Hello all; >>>>> >>>>> The alternative hashing implementation introduced in 7u6 added an >>>>> unfortunate bottleneck to the initialization of HashMap and Hashtable >>>>> instances. This patch avoids the performance bottleneck of using a shared >>>>> Random instance by using a ThreadLocalRandom instead. >>>>> >>>>> Along with this change are some additional performance improvements to >>>>> further reduce the overhead of the alternative hashing feature and >>>>> generally improve the performance of Hashtable or HashMap. >>>>> >>>>> c >>>>> >>>>> Once review is completed here this patch will be proposed to JDK7u-dev >>>>> for integration into the next 7u performance/feature release. >>>>> >>>>> Mike >>>>> >>>> >>> >> >