/** * Copyright (C) 2014-2016 Typesafe Inc. */ package akka.persistence import java.io.File import java.util.concurrent.TimeUnit import scala.concurrent.Await import scala.concurrent.duration._ import akka.actor._ import akka.persistence.journal.AsyncWriteTarget._ import akka.persistence.journal.leveldb.{ SharedLeveldbJournal, SharedLeveldbStore } import akka.testkit.TestProbe import org.apache.commons.io.FileUtils import org.openjdk.jmh.annotations._ /* # OS: OSX 10.9.3 # CPU: Intel(R) Core(TM) i7-4850HQ CPU @ 2.30GHz # Date: Mon Jul 23 11:07:42 CEST 2014 This bench emulates what we provide with "Processor batching". As expected, batching writes is better than writing 1 by 1. The important thing though is that there didn't appear to be any "write latency spikes" throughout this bench. [info] Benchmark Mode Samples Score Score error Units [info] a.p.LevelDbBatchingBenchmark.write_1 avgt 20 0.799 0.011 ms/op [info] a.p.LevelDbBatchingBenchmark.writeBatch_10 avgt 20 0.117 0.001 ms/op [info] a.p.LevelDbBatchingBenchmark.writeBatch_100 avgt 20 0.050 0.000 ms/op [info] a.p.LevelDbBatchingBenchmark.writeBatch_200 avgt 20 0.041 0.001 ms/op */ @Fork(1) @Threads(10) @State(Scope.Benchmark) @BenchmarkMode(Array(Mode.AverageTime)) class LevelDbBatchingBenchmark { var sys: ActorSystem = _ var probe: TestProbe = _ var store: ActorRef = _ val batch_1 = List.fill(1) { AtomicWrite(PersistentRepr("data", 12, "pa")) } val batch_10 = List.fill(10) { AtomicWrite(PersistentRepr("data", 12, "pa")) } val batch_100 = List.fill(100) { AtomicWrite(PersistentRepr("data", 12, "pa")) } val batch_200 = List.fill(200) { AtomicWrite(PersistentRepr("data", 12, "pa")) } @Setup(Level.Trial) def setup() { sys = ActorSystem("sys") deleteStorage(sys) SharedLeveldbJournal.setStore(store, sys) probe = TestProbe()(sys) store = sys.actorOf(Props[SharedLeveldbStore], "store") } @TearDown(Level.Trial) def tearDown() { store ! PoisonPill Thread.sleep(500) sys.terminate() Await.ready(sys.whenTerminated, 10.seconds) } @Benchmark @Measurement(timeUnit = TimeUnit.MICROSECONDS) @OperationsPerInvocation(1) def write_1() = { probe.send(store, WriteMessages(batch_1)) probe.expectMsgType[Any] } @Benchmark @Measurement(timeUnit = TimeUnit.MICROSECONDS) @OperationsPerInvocation(10) def writeBatch_10() = { probe.send(store, WriteMessages(batch_10)) probe.expectMsgType[Any] } @Benchmark @Measurement(timeUnit = TimeUnit.MICROSECONDS) @OperationsPerInvocation(100) def writeBatch_100() = { probe.send(store, WriteMessages(batch_100)) probe.expectMsgType[Any] } @Benchmark @Measurement(timeUnit = TimeUnit.MICROSECONDS) @OperationsPerInvocation(200) def writeBatch_200() = { probe.send(store, WriteMessages(batch_200)) probe.expectMsgType[Any] } // TOOLS private def deleteStorage(sys: ActorSystem) { val storageLocations = List( "akka.persistence.journal.leveldb.dir", "akka.persistence.journal.leveldb-shared.store.dir", "akka.persistence.snapshot-store.local.dir").map(s ⇒ new File(sys.settings.config.getString(s))) storageLocations.foreach(FileUtils.deleteDirectory) } }