Skip to content

Commit 16f795a

Browse files
committed
Tuning of HashMap operations
- Increase load factor to 0.5 -- the miss rate seems to be still OK (around one miss per hit or better) while re-sizing costs and go down. - Don't lose lowest hashCode bit.
1 parent 86fbade commit 16f795a

File tree

3 files changed

+20
-10
lines changed

3 files changed

+20
-10
lines changed

compiler/src/dotty/tools/dotc/util/GenericHashMap.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ abstract class GenericHashMap[Key <: AnyRef, Value >: Null <: AnyRef]
5656
/** Equality, to be implemented in subclass */
5757
protected def isEqual(x: Key, y: Key): Boolean
5858

59-
/** Turn hashcode `x` into a table index */
59+
/** Turn successor index or hash code `x` into a table index */
6060
private def index(x: Int): Int = x & (table.length - 2)
6161

6262
private def firstIndex(key: Key) = if isDense then 0 else index(hash(key))

compiler/src/dotty/tools/dotc/util/HashMap.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@ package dotty.tools.dotc.util
44
* as comparison
55
*/
66
class HashMap[Key <: AnyRef, Value >: Null <: AnyRef]
7-
(initialCapacity: Int = 8, capacityMultiple: Int = 3)
7+
(initialCapacity: Int = 8, capacityMultiple: Int = 2)
88
extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
99
import GenericHashMap.DenseLimit
1010

11-
final def hash(x: Key): Int = x.hashCode
11+
/** Hashcode is left-shifted by 1, so lowest bit is not lost
12+
* when taking the index.
13+
*/
14+
final def hash(x: Key): Int = x.hashCode << 1
15+
1216
final def isEqual(x: Key, y: Key): Boolean = x.equals(y)
1317

1418
// The following methods are duplicated from GenericHashMap
1519
// to avoid polymorphic dispatches
1620

17-
/** Turn hashcode `x` into a table index */
21+
/** Turn successor index or hash code `x` into a table index */
1822
private def index(x: Int): Int = x & (table.length - 2)
1923

2024
private def firstIndex(key: Key) = if isDense then 0 else index(hash(key))
21-
private def nextIndex(idx: Int) = index(idx + 2)
25+
private def nextIndex(idx: Int) =
26+
Stats.record(statsItem("miss"))
27+
index(idx + 2)
2228

2329
private def keyAt(idx: Int): Key = table(idx).asInstanceOf[Key]
2430
private def valueAt(idx: Int): Value = table(idx + 1).asInstanceOf[Value]

compiler/src/dotty/tools/dotc/util/IdentityHashMap.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ package dotty.tools.dotc.util
44
* as comparison
55
*/
66
class IdentityHashMap[Key <: AnyRef, Value >: Null <: AnyRef]
7-
(initialCapacity: Int = 8, capacityMultiple: Int = 3)
7+
(initialCapacity: Int = 8, capacityMultiple: Int = 2)
88
extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
99
import GenericHashMap.DenseLimit
1010

11-
/** Hashcode, by default `System.identityHashCode`, but can be overriden */
12-
final def hash(x: Key): Int = System.identityHashCode(x)
11+
/** Hashcode is identityHashCode left-shifted by 1, so lowest bit is not lost
12+
* when taking the index.
13+
*/
14+
final def hash(x: Key): Int = System.identityHashCode(x) << 1
1315

1416
/** Equality, by default `eq`, but can be overridden */
1517
final def isEqual(x: Key, y: Key): Boolean = x eq y
@@ -19,11 +21,13 @@ extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
1921
// Aside: It would be nice to have a @specialized annotation that does
2022
// this automatically
2123

22-
/** Turn hashcode `x` into a table index */
24+
/** Turn successor index or hash code `x` into a table index */
2325
private def index(x: Int): Int = x & (table.length - 2)
2426

2527
private def firstIndex(key: Key) = if isDense then 0 else index(hash(key))
26-
private def nextIndex(idx: Int) = index(idx + 2)
28+
private def nextIndex(idx: Int) =
29+
Stats.record(statsItem("miss"))
30+
index(idx + 2)
2731

2832
private def keyAt(idx: Int): Key = table(idx).asInstanceOf[Key]
2933
private def valueAt(idx: Int): Value = table(idx + 1).asInstanceOf[Value]

0 commit comments

Comments
 (0)