diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index 437901a7c8..df47093499 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -32,9 +32,9 @@ trait LoggingBus extends ActorEventBus { import Logging._ - private val guard = new ReentrantGuard //Switch to ReentrantReadWrite + private val guard = new ReentrantGuard private var loggers = Seq.empty[ActorRef] - private var _logLevel: LogLevel = _ + @volatile private var _logLevel: LogLevel = _ /** * Query currently set log level. See object Logging for more information. @@ -52,16 +52,17 @@ trait LoggingBus extends ActorEventBus { * subscriptions! */ def setLogLevel(level: LogLevel): Unit = guard.withGuard { + val logLvl = _logLevel // saves (2 * AllLogLevel.size - 1) volatile reads (because of the loops below) for { l ← AllLogLevels // subscribe if previously ignored and now requested - if l > _logLevel && l <= level + if l > logLvl && l <= level log ← loggers } subscribe(log, classFor(l)) for { l ← AllLogLevels // unsubscribe if previously registered and now ignored - if l <= _logLevel && l > level + if l <= logLvl && l > level log ← loggers } unsubscribe(log, classFor(l)) _logLevel = level diff --git a/akka-bench-jmh/src/main/scala/akka/event/LogLevelAccessBenchmark.scala b/akka-bench-jmh/src/main/scala/akka/event/LogLevelAccessBenchmark.scala new file mode 100644 index 0000000000..7bd8c7ae36 --- /dev/null +++ b/akka-bench-jmh/src/main/scala/akka/event/LogLevelAccessBenchmark.scala @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2014 Typesafe Inc. + */ +package akka.event + +import java.util.concurrent.TimeUnit + +import akka.event.Logging.LogLevel +import org.openjdk.jmh.annotations._ + +@Fork(3) +@State(Scope.Benchmark) +@BenchmarkMode(Array(Mode.Throughput)) +@Warmup(iterations = 10) +@Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS) +class LogLevelAccessBenchmark { + + /* + volatile logLevel, guard on loggers + 20 readers, 2 writers + a.e.LogLevelAccessBenchmark.g thrpt 60 1862566.204 37860.541 ops/ms + a.e.LogLevelAccessBenchmark.g:readLogLevel thrpt 60 1860031.729 37834.335 ops/ms + a.e.LogLevelAccessBenchmark.g:writeLogLevel_1 thrpt 60 1289.452 45.403 ops/ms + a.e.LogLevelAccessBenchmark.g:writeLogLevel_2 thrpt 60 1245.023 51.071 ops/ms + */ + + val NoopBus = new LoggingBus { + override def subscribe(subscriber: Subscriber, to: Classifier): Boolean = true + override def publish(event: Event): Unit = () + override def unsubscribe(subscriber: Subscriber, from: Classifier): Boolean = true + override def unsubscribe(subscriber: Subscriber): Unit = () + } + + var log: BusLogging = akka.event.Logging(NoopBus, "").asInstanceOf[BusLogging] + + @Benchmark + @GroupThreads(20) + @Group("g") + def readLogLevel(): LogLevel = + log.bus.logLevel + + @Benchmark + @Group("g") + def setLogLevel_1(): Unit = + log.bus.setLogLevel(Logging.ErrorLevel) + + @Benchmark + @Group("g") + def setLogLevel_2(): Unit = + log.bus.setLogLevel(Logging.DebugLevel) + +} \ No newline at end of file