From b88933eb84f1f1f5215b0feb43f4ecfc12c8847d Mon Sep 17 00:00:00 2001 From: Performant Data LLC Date: Fri, 25 Mar 2016 21:44:50 -0700 Subject: Benchmark the OpenHashMap memory usage. Also add sbteclipse to the benchmark project. --- test/benchmarks/.gitignore | 8 ++++++ test/benchmarks/build.sbt | 5 +++- test/benchmarks/project/plugins.sbt | 1 + .../collection/mutable/OpenHashMapBenchmark.scala | 32 +++++++++++++++------- 4 files changed, 35 insertions(+), 11 deletions(-) (limited to 'test/benchmarks') diff --git a/test/benchmarks/.gitignore b/test/benchmarks/.gitignore index 6e3ddad6d2..ce4d893417 100644 --- a/test/benchmarks/.gitignore +++ b/test/benchmarks/.gitignore @@ -4,3 +4,11 @@ # what appears to be a Scala IDE-generated file .cache-main + +# standard Eclipse output directory +/bin/ + +# sbteclipse-generated Eclipse files +/.classpath +/.project +/.settings/ diff --git a/test/benchmarks/build.sbt b/test/benchmarks/build.sbt index 92a5fce177..2959e4986a 100644 --- a/test/benchmarks/build.sbt +++ b/test/benchmarks/build.sbt @@ -1,8 +1,11 @@ scalaHome := Some(file("../../build/pack")) +scalaVersion := "2.11.8" +scalacOptions += "-feature" lazy val root = (project in file(".")). enablePlugins(JmhPlugin). settings( name := "test-benchmarks", - version := "0.0.1" + version := "0.0.1", + libraryDependencies += "org.openjdk.jol" % "jol-core" % "0.4" ) diff --git a/test/benchmarks/project/plugins.sbt b/test/benchmarks/project/plugins.sbt index f5319fb187..e11aa29f3b 100644 --- a/test/benchmarks/project/plugins.sbt +++ b/test/benchmarks/project/plugins.sbt @@ -1 +1,2 @@ +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.2.6") diff --git a/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala b/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala index 73ab5e40d0..13be9e6206 100644 --- a/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala +++ b/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala @@ -4,6 +4,9 @@ import java.util.concurrent.TimeUnit import org.openjdk.jmh.annotations._ import org.openjdk.jmh.infra.Blackhole import org.openjdk.jmh.infra.BenchmarkParams +import org.openjdk.jol.info.GraphLayout +import org.openjdk.jol.info.GraphWalker +import org.openjdk.jol.info.GraphVisitor /** Utilities for the [[OpenHashMapBenchmark]]. * @@ -15,9 +18,11 @@ private object OpenHashMapBenchmark { * * Provides an array of adequately-sized, empty maps to each invocation, * so that hash table allocation won't be done during measurement. - * - * Empties the map and performs a GC after every invocation, + * Provides enough maps to make each invocation long enough to avoid timing artifacts. + * Performs a GC after re-creating the empty maps before every invocation, * so that only the GCs caused by the invocation contribute to the measurement. + * + * Records the memory used by all the maps in the last invocation of each iteration. */ @State(Scope.Thread) @AuxCounters @@ -28,24 +33,25 @@ private object OpenHashMapBenchmark { /** Minimum number of nanoseconds per invocation, so as to avoid timing artifacts. */ private[this] val minNanosPerInvocation = 1000000 // one millisecond - /** The minimum number of `put()` calls to make per invocation, so as to avoid timing artifacts. */ - private[this] val minPutsPerInvocation = minNanosPerInvocation / nanosPerPut - /** Size of the maps created in this trial. */ private[this] var size: Int = _ - /** Number of maps created in each invocation; the size of `maps`. */ - private[this] var n: Int = _ + /** Total number of entries in all of the `maps` combined. */ + var mapEntries: Int = _ /** Number of operations performed in the current invocation. */ var operations: Int = _ + /** Bytes of memory used in the object graphs of all the maps. */ + var memory: Long = _ + var maps: Array[OpenHashMap[Int,Int]] = null @Setup def threadSetup(params: BenchmarkParams) { size = params.getParam("size").toInt - n = math.ceil(minPutsPerInvocation / size).toInt + val n = math.ceil(minNanosPerInvocation / (nanosPerPut * size)).toInt + mapEntries = size * n maps = new Array(n) } @@ -56,10 +62,16 @@ private object OpenHashMapBenchmark { @Setup(Level.Invocation) def setup { - for (i <- 0 until n) maps(i) = new OpenHashMap[Int,Int](size) - operations += size * n + for (i <- 0 until maps.length) maps(i) = new OpenHashMap[Int,Int](size) + operations += mapEntries System.gc() // clean up after last invocation } + + @TearDown(Level.Iteration) + def iterationTeardown { + // limit to smaller cases to avoid OOM + memory = if (mapEntries <= 1000000) GraphLayout.parseInstance(maps(0), maps.tail).totalSize else 0 + } } /** State container for the `get()` bulk calling tests. -- cgit v1.2.3