diff --git a/akka-actor-typed-tests/src/test/scala/akka/actor/typed/internal/adpater/PropsAdapterSpec.scala b/akka-actor-typed-tests/src/test/scala/akka/actor/typed/internal/adpater/PropsAdapterSpec.scala new file mode 100644 index 0000000000..4ab1b180ae --- /dev/null +++ b/akka-actor-typed-tests/src/test/scala/akka/actor/typed/internal/adpater/PropsAdapterSpec.scala @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019 Lightbend Inc. + */ + +package akka.actor.typed.internal.adpater + +import akka.actor +import akka.actor.typed.Props +import akka.actor.typed.internal.adapter.PropsAdapter +import akka.actor.typed.scaladsl.Behaviors +import org.scalatest.Matchers +import org.scalatest.WordSpec + +class PropsAdapterSpec extends WordSpec with Matchers { + + "PropsAdapter" should { + "default to akka.dispatch.SingleConsumerOnlyUnboundedMailbox" in { + val props: Props = Props.empty + val pa: actor.Props = PropsAdapter(() => Behaviors.empty, props) + pa.mailbox shouldEqual "akka.actor.typed.default-mailbox" + } + } +} diff --git a/akka-actor-typed/src/main/resources/reference.conf b/akka-actor-typed/src/main/resources/reference.conf index a9de17de7f..c92f7b1639 100644 --- a/akka-actor-typed/src/main/resources/reference.conf +++ b/akka-actor-typed/src/main/resources/reference.conf @@ -23,6 +23,11 @@ akka.actor.typed { # behavior. This property defines the capacity in number of messages of the stash # buffer. If the capacity is exceed then additional incoming messages are dropped. restart-stash-capacity = 1000 + + # Typed mailbox defaults to the single consumber mailbox as balancing dispatcher is not supported + default-mailbox { + mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox" + } } # Load typed extensions by a classic extension. diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/Props.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/Props.scala index bcc23df2f0..6d41d781c8 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/Props.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/Props.scala @@ -189,12 +189,12 @@ abstract class MailboxSelector extends Props object MailboxSelector { /** - * Scala API: The default mailbox is unbounded and backed by a [[java.util.concurrent.ConcurrentLinkedQueue]] + * Scala API: The default mailbox is SingleConsumerOnlyUnboundedMailbox */ - def default(): MailboxSelector = DefaultMailboxSelector.empty + def default(): MailboxSelector = fromConfig("akka.actor.typed.default-mailbox") /** - * Java API: The default mailbox is unbounded and backed by a [[java.util.concurrent.ConcurrentLinkedQueue]] + * Java API: The default mailbox is SingleConsumerOnlyUnboundedMailbox */ def defaultMailbox(): MailboxSelector = default() diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/PropsAdapter.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/PropsAdapter.scala index 7f32a122b3..c4d4b94166 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/PropsAdapter.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/PropsAdapter.scala @@ -23,22 +23,22 @@ import akka.dispatch.Mailboxes rethrowTypedFailure: Boolean = true): akka.actor.Props = { val props = akka.actor.Props(new ActorAdapter(behavior(), rethrowTypedFailure)) - val p1 = (deploy.firstOrElse[DispatcherSelector](DispatcherDefault.empty) match { + val dispatcherProps = (deploy.firstOrElse[DispatcherSelector](DispatcherDefault.empty) match { case _: DispatcherDefault => props case DispatcherFromConfig(name, _) => props.withDispatcher(name) case _: DispatcherSameAsParent => props.withDispatcher(Deploy.DispatcherSameAsParent) }).withDeploy(Deploy.local) // disallow remote deployment for typed actors - val p2 = deploy.firstOrElse[MailboxSelector](MailboxSelector.default()) match { - case _: DefaultMailboxSelector => p1 + val mailboxProps = deploy.firstOrElse[MailboxSelector](MailboxSelector.default()) match { + case _: DefaultMailboxSelector => dispatcherProps case BoundedMailboxSelector(capacity, _) => // specific support in classic Mailboxes - p1.withMailbox(s"${Mailboxes.BoundedCapacityPrefix}$capacity") + dispatcherProps.withMailbox(s"${Mailboxes.BoundedCapacityPrefix}$capacity") case MailboxFromConfigSelector(path, _) => - props.withMailbox(path) + dispatcherProps.withMailbox(path) } - p2.withDeploy(Deploy.local) // disallow remote deployment for typed actors + mailboxProps.withDeploy(Deploy.local) // disallow remote deployment for typed actors } } diff --git a/akka-bench-jmh-typed/README.md b/akka-bench-jmh-typed/README.md deleted file mode 100644 index 1bfae92d7b..0000000000 --- a/akka-bench-jmh-typed/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Akka Microbenchmarks - -This subproject contains some microbenchmarks excercising key parts of Akka Typed. - -You can run them like: - - project akka-bench-jmh-typed - jmh:run -i 3 -wi 3 -f 1 .*ActorCreationBenchmark - -Use 'jmh:run -h' to get an overview of the available options. diff --git a/akka-bench-jmh-typed/src/main/scala/akka/BenchRunner.scala b/akka-bench-jmh-typed/src/main/scala/akka/BenchRunner.scala deleted file mode 100644 index 221765fe87..0000000000 --- a/akka-bench-jmh-typed/src/main/scala/akka/BenchRunner.scala +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2018-2019 Lightbend Inc. - */ - -package akka - -import org.openjdk.jmh.results.RunResult -import org.openjdk.jmh.runner.Runner -import org.openjdk.jmh.runner.options.CommandLineOptions - -object BenchRunner { - def main(args: Array[String]) = { - import akka.util.ccompat.JavaConverters._ - - val args2 = args.toList.flatMap { - case "quick" => "-i 1 -wi 1 -f1 -t1".split(" ").toList - case "full" => "-i 10 -wi 4 -f3 -t1".split(" ").toList - case "jitwatch" => "-jvmArgs=-XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation" :: Nil - case other => other :: Nil - } - - val opts = new CommandLineOptions(args2: _*) - val results = new Runner(opts).run() - - val report = results.asScala.map { result: RunResult => - val bench = result.getParams.getBenchmark - val params = - result.getParams.getParamsKeys.asScala.map(key => s"$key=${result.getParams.getParam(key)}").mkString("_") - val score = result.getAggregatedResult.getPrimaryResult.getScore.round - val unit = result.getAggregatedResult.getPrimaryResult.getScoreUnit - s"\t${bench}_${params}\t$score\t$unit" - } - - report.toList.sorted.foreach(println) - } -} diff --git a/akka-bench-jmh/README.md b/akka-bench-jmh/README.md index 6b7446739c..48774c8eca 100644 --- a/akka-bench-jmh/README.md +++ b/akka-bench-jmh/README.md @@ -10,3 +10,8 @@ You can run them like: jmh:run -i 3 -wi 3 -f 1 .*ActorCreationBenchmark Use 'jmh:run -h' to get an overview of the available options. + +Some potentially out of date resources for writing JMH benchmarks: + +* [Studying what's wrong with JMH benchmarks](https://www.researchgate.net/publication/333825812_What's_Wrong_With_My_Benchmark_Results_Studying_Bad_Practices_in_JMH_Benchmarks) +* [Writing good benchmarks](http://tutorials.jenkov.com/java-performance/jmh.html#writing-good-benchmarks) diff --git a/akka-bench-jmh-typed/src/main/resources/logback-test.xml b/akka-bench-jmh/src/main/resources/logback-test.xml similarity index 100% rename from akka-bench-jmh-typed/src/main/resources/logback-test.xml rename to akka-bench-jmh/src/main/resources/logback-test.xml diff --git a/akka-bench-jmh-typed/src/main/scala/akka/actor/typed/TypedActorBenchmark.scala b/akka-bench-jmh/src/main/scala/akka/actor/typed/TypedActorBenchmark.scala similarity index 98% rename from akka-bench-jmh-typed/src/main/scala/akka/actor/typed/TypedActorBenchmark.scala rename to akka-bench-jmh/src/main/scala/akka/actor/typed/TypedActorBenchmark.scala index 9aff40ecf2..e43115dcf2 100644 --- a/akka-bench-jmh-typed/src/main/scala/akka/actor/typed/TypedActorBenchmark.scala +++ b/akka-bench-jmh/src/main/scala/akka/actor/typed/TypedActorBenchmark.scala @@ -39,7 +39,7 @@ class TypedActorBenchmark { @Param(Array("50")) var batchSize = 0 - @Param(Array("akka.dispatch.SingleConsumerOnlyUnboundedMailbox")) + @Param(Array("akka.dispatch.SingleConsumerOnlyUnboundedMailbox", "akka.dispatch.UnboundedMailbox")) var mailbox = "" @Param(Array("fjp-dispatcher")) // @Param(Array("fjp-dispatcher", "affinity-dispatcher")) diff --git a/akka-bench-jmh-typed/src/main/scala/akka/actor/typed/TypedBenchmarkActors.scala b/akka-bench-jmh/src/main/scala/akka/actor/typed/TypedBenchmarkActors.scala similarity index 100% rename from akka-bench-jmh-typed/src/main/scala/akka/actor/typed/TypedBenchmarkActors.scala rename to akka-bench-jmh/src/main/scala/akka/actor/typed/TypedBenchmarkActors.scala diff --git a/akka-bench-jmh-typed/src/main/scala/akka/actor/typed/TypedForkJoinActorBenchmark.scala b/akka-bench-jmh/src/main/scala/akka/actor/typed/TypedForkJoinActorBenchmark.scala similarity index 100% rename from akka-bench-jmh-typed/src/main/scala/akka/actor/typed/TypedForkJoinActorBenchmark.scala rename to akka-bench-jmh/src/main/scala/akka/actor/typed/TypedForkJoinActorBenchmark.scala diff --git a/akka-docs/src/main/paradox/mailboxes.md b/akka-docs/src/main/paradox/mailboxes.md index 314901b661..53267dbd55 100644 --- a/akka-docs/src/main/paradox/mailboxes.md +++ b/akka-docs/src/main/paradox/mailboxes.md @@ -23,6 +23,23 @@ For more details on advanced mailbox config and custom mailbox implementations, ## Mailbox Selection +### Default Mailbox + +The default mailbox is used when the mailbox is not specified. +This is an unbounded mailbox, backed by a +`java.util.concurrent.ConcurrentLinkedQueue`. + +`SingleConsumerOnlyUnboundedMailbox` is an even more efficient mailbox, and +it can be used as the default mailbox, but it cannot be used with a BalancingDispatcher. + +Configuration of `SingleConsumerOnlyUnboundedMailbox` as default mailbox: + +``` +akka.actor.default-mailbox { + mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox" +} +``` + ### Requiring a Message Queue Type for an Actor It is possible to require a certain type of message queue for a certain type of actor diff --git a/akka-docs/src/main/paradox/typed/mailboxes.md b/akka-docs/src/main/paradox/typed/mailboxes.md index 7926aaa2ae..d21c7f5cc5 100644 --- a/akka-docs/src/main/paradox/typed/mailboxes.md +++ b/akka-docs/src/main/paradox/typed/mailboxes.md @@ -46,20 +46,7 @@ Java ### Default Mailbox -The default mailbox is used when the mailbox is not specified. -This is an unbounded mailbox, backed by a -`java.util.concurrent.ConcurrentLinkedQueue`. - -`SingleConsumerOnlyUnboundedMailbox` is an even more efficient mailbox, and -it can be used as the default mailbox, but it cannot be used with a BalancingDispatcher. - -Configuration of `SingleConsumerOnlyUnboundedMailbox` as default mailbox: - -``` -akka.actor.default-mailbox { - mailbox-type = "akka.dispatch.SingleConsumerOnlyUnboundedMailbox" -} -``` +The default mailbox is used when the mailbox is not specified and is the **SingleConsumerOnlyUnboundedMailbox**> ### Which Configuration is passed to the Mailbox Type @@ -75,19 +62,19 @@ fall-back to the default mailbox configuration section. Akka ships with a number of mailbox implementations: * - **UnboundedMailbox** (default) - * The default mailbox - * Backed by a `java.util.concurrent.ConcurrentLinkedQueue` - * Blocking: No - * Bounded: No - * Configuration name: `"unbounded"` or `"akka.dispatch.UnboundedMailbox"` - * - **SingleConsumerOnlyUnboundedMailbox** - Depending on your use case, this queue may or may not be faster than the default one — be sure to benchmark properly! + **SingleConsumerOnlyUnboundedMailbox** (default) + * This is the default * Backed by a Multiple-Producer Single-Consumer queue, cannot be used with `BalancingDispatcher` * Blocking: No * Bounded: No * Configuration name: `"akka.dispatch.SingleConsumerOnlyUnboundedMailbox"` + * + **UnboundedMailbox** + * Backed by a `java.util.concurrent.ConcurrentLinkedQueue` + * Blocking: No + * Bounded: No + * Configuration name: `"unbounded"` or `"akka.dispatch.UnboundedMailbox"` + * **NonBlockingBoundedMailbox** * Backed by a very efficient Multiple-Producer Single-Consumer queue diff --git a/build.sbt b/build.sbt index dd3d7b4a25..aabe622b7b 100644 --- a/build.sbt +++ b/build.sbt @@ -42,7 +42,6 @@ lazy val aggregatedProjects: Seq[ProjectReference] = List[ProjectReference]( actorTyped, actorTypedTests, benchJmh, - benchJmhTyped, cluster, clusterMetrics, clusterSharding, @@ -77,7 +76,7 @@ lazy val root = Project(id = "akka", base = file(".")) .aggregate(aggregatedProjects: _*) .settings(rootSettings: _*) .settings( - unidocRootIgnoreProjects := Seq(remoteTests, benchJmh, benchJmhTyped, protobuf, protobufV3, akkaScalaNightly, docs)) + unidocRootIgnoreProjects := Seq(remoteTests, benchJmh, protobuf, protobufV3, akkaScalaNightly, docs)) .settings(unmanagedSources in (Compile, headerCreate) := (baseDirectory.value / "project").**("*.scala").get) .enablePlugins(CopyrightHeaderForBuild) @@ -104,21 +103,13 @@ lazy val akkaScalaNightly = akkaModule("akka-scala-nightly") .disablePlugins(ValidatePullRequest, MimaPlugin, CopyrightHeaderInPr) lazy val benchJmh = akkaModule("akka-bench-jmh") - .dependsOn(Seq(actor, stream, streamTests, persistence, distributedData, jackson, testkit).map( + .dependsOn(Seq(actor, actorTyped, stream, streamTests, persistence, distributedData, jackson, testkit).map( _ % "compile->compile;compile->test"): _*) .settings(Dependencies.benchJmh) .settings(javacOptions += "-parameters") // for Jackson .enablePlugins(JmhPlugin, ScaladocNoVerificationOfDiagrams, NoPublish, CopyrightHeader) .disablePlugins(MimaPlugin, WhiteSourcePlugin, ValidatePullRequest, CopyrightHeaderInPr) -// typed benchmarks only on 2.12+ -lazy val benchJmhTyped = akkaModule("akka-bench-jmh-typed") - .dependsOn(Seq(persistenceTyped, distributedData, clusterTyped, testkit, benchJmh).map( - _ % "compile->compile;compile->test"): _*) - .settings(Dependencies.benchJmh) - .enablePlugins(JmhPlugin, ScaladocNoVerificationOfDiagrams, NoPublish, CopyrightHeader) - .disablePlugins(MimaPlugin, WhiteSourcePlugin, ValidatePullRequest, CopyrightHeaderInPr) - lazy val cluster = akkaModule("akka-cluster") .dependsOn(remote, remoteTests % "test->test", testkit % "test->test", jackson % "test->test") .settings(Dependencies.cluster)