rorygraves / scalac_perf

The Scala programming language
http://www.scala-lang.org/
16 stars 3 forks source link

object hash code #45

Open mkeskells opened 6 years ago

mkeskells commented 6 years ago

is it faster to default the hash code or stamp it in?

lots of objects hashcode are frequent, e.g. Nil

126256  scala.collection.immutable.Nil$::hashCode()I

small saving - but is an override faster that the default?

ackratos commented 6 years ago

no obvious benefit:

Index: src/library/scala/collection/immutable/List.scala
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/library/scala/collection/immutable/List.scala   (revision c35b69aad76d0f3da449585708f792268a93a2b0)
+++ src/library/scala/collection/immutable/List.scala   (revision )
@@ -433,6 +433,7 @@
     case that1: scala.collection.GenSeq[_] => that1.isEmpty
     case _ => false
   }
+  override def hashCode() = scala.util.hashing.MurmurHash3.seqSeed
 }

 /** A non empty list characterized by a head and a tail.

on benchmark:

package scala.collection.immutable

import java.util.concurrent.TimeUnit

import org.openjdk.jmh.annotations._
import org.openjdk.jmh.infra.Blackhole

@BenchmarkMode(Array(Mode.AverageTime))
@Fork(2)
@Threads(1)
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
class EmptyListBenchmark {
  @OperationsPerInvocation(10000000)
  @Benchmark def hashCode(bh: Blackhole): Any = {
    for (1 <- 1 to 10000000) {
      val hashCode = Nil.hashCode()
      bh.consume(hashCode)
    }
  }
}

above is optimized version, below is baseline:

[info] Benchmark                    Mode  Cnt  Score   Error  Units
[info] EmptyListBenchmark.hashCode  avgt   20  3.392 ± 0.082  ns/op

[info] Benchmark                    Mode  Cnt  Score   Error  Units
[info] EmptyListBenchmark.hashCode  avgt   20  3.436 ± 0.108  ns/op