2018-10-29 17:19:37 +08:00
|
|
|
/*
|
2021-01-08 17:55:38 +01:00
|
|
|
* Copyright (C) 2016-2021 Lightbend Inc. <https://www.lightbend.com>
|
2016-05-29 22:15:48 +02:00
|
|
|
*/
|
2018-03-13 23:45:55 +09:00
|
|
|
|
2016-05-29 22:15:48 +02:00
|
|
|
package akka.remote.artery
|
|
|
|
|
|
2019-09-04 13:37:06 +02:00
|
|
|
import java.util.concurrent.CountDownLatch
|
|
|
|
|
import java.util.concurrent.CyclicBarrier
|
2016-05-29 22:15:48 +02:00
|
|
|
import java.util.concurrent.TimeUnit
|
2019-09-04 13:37:06 +02:00
|
|
|
|
2020-04-27 20:32:18 +08:00
|
|
|
import scala.concurrent.Await
|
|
|
|
|
import scala.concurrent.duration._
|
|
|
|
|
|
|
|
|
|
import com.typesafe.config.ConfigFactory
|
|
|
|
|
import org.agrona.concurrent.ManyToOneConcurrentArrayQueue
|
|
|
|
|
import org.openjdk.jmh.annotations._
|
|
|
|
|
|
2016-05-29 22:15:48 +02:00
|
|
|
import akka.actor.ActorSystem
|
2019-09-04 13:37:06 +02:00
|
|
|
import akka.stream.KillSwitches
|
|
|
|
|
import akka.stream.OverflowStrategy
|
|
|
|
|
import akka.stream.SystemMaterializer
|
2016-05-29 22:15:48 +02:00
|
|
|
import akka.stream.scaladsl._
|
|
|
|
|
|
|
|
|
|
@State(Scope.Benchmark)
|
|
|
|
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
|
|
|
|
@BenchmarkMode(Array(Mode.Throughput))
|
|
|
|
|
@Fork(2)
|
|
|
|
|
@Warmup(iterations = 4)
|
|
|
|
|
@Measurement(iterations = 10)
|
|
|
|
|
class SendQueueBenchmark {
|
|
|
|
|
|
2019-03-11 10:38:24 +01:00
|
|
|
val config = ConfigFactory.parseString("""
|
|
|
|
|
""")
|
2016-05-29 22:15:48 +02:00
|
|
|
|
2020-04-05 11:55:25 +07:00
|
|
|
implicit val system: ActorSystem = ActorSystem("SendQueueBenchmark", config)
|
2016-05-29 22:15:48 +02:00
|
|
|
|
|
|
|
|
@Setup
|
|
|
|
|
def setup(): Unit = {
|
2019-09-04 13:37:06 +02:00
|
|
|
// eager init of materializer
|
|
|
|
|
SystemMaterializer(system).materializer
|
2016-05-29 22:15:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@TearDown
|
|
|
|
|
def shutdown(): Unit = {
|
|
|
|
|
Await.result(system.terminate(), 5.seconds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Benchmark
|
|
|
|
|
@OperationsPerInvocation(100000)
|
|
|
|
|
def queue(): Unit = {
|
|
|
|
|
val latch = new CountDownLatch(1)
|
|
|
|
|
val barrier = new CyclicBarrier(2)
|
|
|
|
|
val N = 100000
|
|
|
|
|
val burstSize = 1000
|
|
|
|
|
|
2021-05-27 10:53:18 +04:00
|
|
|
val source = Source.queue[Int](1024)
|
2016-05-29 22:15:48 +02:00
|
|
|
|
2019-03-11 10:38:24 +01:00
|
|
|
val (queue, killSwitch) = source
|
|
|
|
|
.viaMat(KillSwitches.single)(Keep.both)
|
|
|
|
|
.toMat(new BarrierSink(N, latch, burstSize, barrier))(Keep.left)
|
2019-09-04 13:37:06 +02:00
|
|
|
.run()
|
2016-05-29 22:15:48 +02:00
|
|
|
|
|
|
|
|
var n = 1
|
|
|
|
|
while (n <= N) {
|
|
|
|
|
queue.offer(n)
|
|
|
|
|
if (n % burstSize == 0 && n < N) {
|
|
|
|
|
barrier.await()
|
|
|
|
|
}
|
|
|
|
|
n += 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!latch.await(30, TimeUnit.SECONDS))
|
|
|
|
|
throw new RuntimeException("Latch didn't complete in time")
|
|
|
|
|
killSwitch.shutdown()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Benchmark
|
|
|
|
|
@OperationsPerInvocation(100000)
|
|
|
|
|
def actorRef(): Unit = {
|
|
|
|
|
val latch = new CountDownLatch(1)
|
|
|
|
|
val barrier = new CyclicBarrier(2)
|
|
|
|
|
val N = 100000
|
|
|
|
|
val burstSize = 1000
|
|
|
|
|
|
2019-09-10 11:59:19 +02:00
|
|
|
val source = Source.actorRef(PartialFunction.empty, PartialFunction.empty, 1024, OverflowStrategy.dropBuffer)
|
2016-05-29 22:15:48 +02:00
|
|
|
|
2019-03-11 10:38:24 +01:00
|
|
|
val (ref, killSwitch) = source
|
|
|
|
|
.viaMat(KillSwitches.single)(Keep.both)
|
|
|
|
|
.toMat(new BarrierSink(N, latch, burstSize, barrier))(Keep.left)
|
2019-09-04 13:37:06 +02:00
|
|
|
.run()
|
2016-05-29 22:15:48 +02:00
|
|
|
|
|
|
|
|
var n = 1
|
|
|
|
|
while (n <= N) {
|
|
|
|
|
ref ! n
|
|
|
|
|
if (n % burstSize == 0 && n < N) {
|
|
|
|
|
barrier.await()
|
|
|
|
|
}
|
|
|
|
|
n += 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!latch.await(30, TimeUnit.SECONDS))
|
|
|
|
|
throw new RuntimeException("Latch didn't complete in time")
|
|
|
|
|
killSwitch.shutdown()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Benchmark
|
|
|
|
|
@OperationsPerInvocation(100000)
|
|
|
|
|
def sendQueue(): Unit = {
|
|
|
|
|
val latch = new CountDownLatch(1)
|
|
|
|
|
val barrier = new CyclicBarrier(2)
|
|
|
|
|
val N = 100000
|
|
|
|
|
val burstSize = 1000
|
|
|
|
|
|
|
|
|
|
val queue = new ManyToOneConcurrentArrayQueue[Int](1024)
|
2019-02-09 15:25:39 +01:00
|
|
|
val source = Source.fromGraph(new SendQueue[Int](_ => ()))
|
2016-05-29 22:15:48 +02:00
|
|
|
|
2019-03-11 10:38:24 +01:00
|
|
|
val (sendQueue, killSwitch) = source
|
|
|
|
|
.viaMat(KillSwitches.single)(Keep.both)
|
|
|
|
|
.toMat(new BarrierSink(N, latch, burstSize, barrier))(Keep.left)
|
2019-09-04 13:37:06 +02:00
|
|
|
.run()
|
2016-05-29 22:15:48 +02:00
|
|
|
sendQueue.inject(queue)
|
|
|
|
|
|
|
|
|
|
var n = 1
|
|
|
|
|
while (n <= N) {
|
|
|
|
|
if (!sendQueue.offer(n))
|
|
|
|
|
println(s"offer failed $n") // should not happen
|
|
|
|
|
if (n % burstSize == 0 && n < N) {
|
|
|
|
|
barrier.await()
|
|
|
|
|
}
|
|
|
|
|
n += 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!latch.await(30, TimeUnit.SECONDS))
|
|
|
|
|
throw new RuntimeException("Latch didn't complete in time")
|
|
|
|
|
killSwitch.shutdown()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|