diff --git a/akka-multi-node-testkit/src/main/scala/akka/remote/testkit/MultiNodeSpec.scala b/akka-multi-node-testkit/src/main/scala/akka/remote/testkit/MultiNodeSpec.scala index 9e637341c1..dabd86f341 100644 --- a/akka-multi-node-testkit/src/main/scala/akka/remote/testkit/MultiNodeSpec.scala +++ b/akka-multi-node-testkit/src/main/scala/akka/remote/testkit/MultiNodeSpec.scala @@ -5,15 +5,18 @@ package akka.remote.testkit import language.implicitConversions import java.net.{ InetAddress, InetSocketAddress } -import com.typesafe.config.{ ConfigObject, ConfigFactory, Config } -import scala.concurrent.{ Await, Awaitable } + +import com.typesafe.config.{ Config, ConfigFactory, ConfigObject } + +import scala.concurrent.{ Await, Awaitable, Future } import scala.util.control.NonFatal import scala.collection.immutable import akka.actor._ import akka.util.Timeout -import akka.remote.testconductor.{ TestConductorExt, TestConductor, RoleName } +import akka.remote.testconductor.{ RoleName, TestConductor, TestConductorExt } import akka.testkit._ import akka.testkit.TestEvent._ + import scala.concurrent.duration._ import akka.remote.testconductor.RoleName import akka.actor.RootActorPath diff --git a/akka-multi-node-testkit/src/main/scala/akka/remote/testkit/PerfFlamesSupport.scala b/akka-multi-node-testkit/src/main/scala/akka/remote/testkit/PerfFlamesSupport.scala new file mode 100644 index 0000000000..34311bd1b1 --- /dev/null +++ b/akka-multi-node-testkit/src/main/scala/akka/remote/testkit/PerfFlamesSupport.scala @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 Lightbend Inc. + */ + +package akka.remote.testkit + +import java.io.File + +import akka.remote.testconductor.RoleName + +import scala.concurrent.Future +import scala.concurrent.duration._ + +/** + * INTERNAL API: Support trait allowing trivially recording perf metrics from [[MultiNodeSpec]]s + */ +private[akka] trait PerfFlamesSupport { _: MultiNodeSpec ⇒ + + /** + * Runs `perf-java-flames` script on given node (JVM process). + * Refer to https://github.com/jrudolph/perf-map-agent for options and manual. + * + * Options are currently to be passed in via `export PERF_MAP_OPTIONS` etc. + */ + def runPerfFlames(nodes: RoleName*)(delay: FiniteDuration, time: FiniteDuration = 15.seconds): Unit = { + if (isPerfJavaFlamesAvailable && isNode(nodes: _*)) { + import scala.concurrent.ExecutionContext.Implicits.global + + val afterDelay = akka.pattern.after(delay, system.scheduler)(Future.successful("GO!")) + afterDelay onComplete { it ⇒ + import java.lang.management._ + val name = ManagementFactory.getRuntimeMXBean.getName + val pid = name.substring(0, name.indexOf('@')).toInt + + val perfCommand = s"$perfJavaFlamesPath $pid" + println(s"[perf @ $myself($pid)][OUT]: " + perfCommand) + + import scala.sys.process._ + perfCommand.run(new ProcessLogger { + override def buffer[T](f: ⇒ T): T = f + override def out(s: ⇒ String): Unit = println(s"[perf @ $myself($pid)][OUT] " + s) + override def err(s: ⇒ String): Unit = println(s"[perf @ $myself($pid)][ERR] " + s) + }) + } + } + } + + def perfJavaFlamesPath: String = + "/home/ubuntu/perf-java-flames" + + def isPerfJavaFlamesAvailable: Boolean = { + val isIt = new File(perfJavaFlamesPath).exists() + if (!isIt) println(s"WARN: perf-java-flames not available under [$perfJavaFlamesPath]! Skipping perf profiling.") + isIt + } + + +} diff --git a/akka-remote-tests/src/multi-jvm/scala/akka/remote/artery/MaxThroughputSpec.scala b/akka-remote-tests/src/multi-jvm/scala/akka/remote/artery/MaxThroughputSpec.scala index 9e081ff638..19bf6c8e99 100644 --- a/akka-remote-tests/src/multi-jvm/scala/akka/remote/artery/MaxThroughputSpec.scala +++ b/akka-remote-tests/src/multi-jvm/scala/akka/remote/artery/MaxThroughputSpec.scala @@ -6,13 +6,14 @@ package akka.remote.artery import java.nio.ByteBuffer import java.util.concurrent.Executors import java.util.concurrent.TimeUnit.NANOSECONDS -import scala.concurrent.duration._ +import scala.concurrent.duration._ import akka.actor._ import akka.remote.RemoteActorRefProvider import akka.remote.testconductor.RoleName import akka.remote.testkit.MultiNodeConfig import akka.remote.testkit.MultiNodeSpec +import akka.remote.testkit.PerfFlamesSupport import akka.remote.testkit.STMultiNodeSpec import akka.serialization.ByteBufferSerializer import akka.serialization.SerializerWithStringManifest @@ -199,7 +200,8 @@ class MaxThroughputSpecMultiJvmNode2 extends MaxThroughputSpec abstract class MaxThroughputSpec extends MultiNodeSpec(MaxThroughputSpec) - with STMultiNodeSpec with ImplicitSender { + with STMultiNodeSpec with ImplicitSender + with PerfFlamesSupport { import MaxThroughputSpec._ @@ -269,6 +271,8 @@ abstract class MaxThroughputSpec import testSettings._ val receiverName = testName + "-rcv" + runPerfFlames(first, second)(delay = 5.seconds, time = 15.seconds) + runOn(second) { val rep = reporter(testName) for (n ← 1 to senderReceiverPairs) {