pekko/akka-bench-jmh/src/main/scala/akka/http/HttpRequestParsingBenchmark.scala
Konrad Malawski bb701d1725 HTTP: Optimise response rendering and response parsing (#21046)
* +htp,ben HttpBlueprint benchmark

* +act bring OptionVal from artery-dev
+htc raw benchmarks

* =htc request parsing benchmark

* +htc,ben add benchmark for longer (raw) json response

* =htc optimise renderHeaders, less Option allocs

* -htc remove FastClock, not quite worth it
2016-07-28 22:32:40 +02:00

102 lines
3.4 KiB
Scala

/**
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
*/
package akka.http
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import akka.Done
import akka.actor.ActorSystem
import akka.event.NoLogging
import akka.http.impl.engine.parsing.{ HttpHeaderParser, HttpRequestParser }
import akka.http.scaladsl.settings.ParserSettings
import akka.event.NoLogging
import akka.stream.ActorMaterializer
import akka.stream.TLSProtocol.SessionBytes
import akka.stream.scaladsl._
import akka.util.ByteString
import org.openjdk.jmh.annotations.{ OperationsPerInvocation, _ }
import org.openjdk.jmh.infra.Blackhole
import scala.concurrent.duration._
import scala.concurrent.{ Await, Future }
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.SECONDS)
@BenchmarkMode(Array(Mode.Throughput))
class HttpRequestParsingBenchmark {
implicit val system: ActorSystem = ActorSystem("HttpRequestParsingBenchmark")
implicit val materializer = ActorMaterializer()(system)
val parserSettings = ParserSettings(system)
val parser = new HttpRequestParser(parserSettings, false, HttpHeaderParser(parserSettings, NoLogging)())
val dummySession = SSLContext.getDefault.createSSLEngine.getSession
@Param(Array("small", "large"))
var req: String = ""
def request = req match {
case "small" => requestBytesSmall
case "large" => requestBytesLarge
}
val requestBytesSmall: SessionBytes = SessionBytes(
dummySession,
ByteString(
"""|GET / HTTP/1.1
|Accept: */*
|Accept-Encoding: gzip, deflate
|Connection: keep-alive
|Host: example.com
|User-Agent: HTTPie/0.9.3
|
|""".stripMargin.replaceAll("\n", "\r\n")
)
)
val requestBytesLarge: SessionBytes = SessionBytes(
dummySession,
ByteString(
"""|GET /json HTTP/1.1
|Host: server
|User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00
|Cookie: uid=12345678901234567890; __utma=1.1234567890.1234567890.1234567890.1234567890.12; wd=2560x1600
|Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|Accept-Language: en-US,en;q=0.5
|Connection: keep-alive
|
|""".stripMargin.replaceAll("\n", "\r\n")
)
)
/*
// before:
[info] Benchmark (req) Mode Cnt Score Error Units
[info] HttpRequestParsingBenchmark.parse_10000_requests small thrpt 20 358 982.157 ± 93745.863 ops/s
[info] HttpRequestParsingBenchmark.parse_10000_requests large thrpt 20 388 335.666 ± 16990.715 ops/s
// after:
[info] HttpRequestParsingBenchmark.parse_10000_requests_val small thrpt 20 623 975.879 ± 6191.897 ops/s
[info] HttpRequestParsingBenchmark.parse_10000_requests_val large thrpt 20 507 460.283 ± 4735.843 ops/s
*/
val httpMessageParser = Flow.fromGraph(parser)
def flow(bytes: SessionBytes, n: Int): RunnableGraph[Future[Done]] =
Source.repeat(request).take(n)
.via(httpMessageParser)
.toMat(Sink.ignore)(Keep.right)
@Benchmark
@OperationsPerInvocation(10000)
def parse_10000_requests_val(blackhole: Blackhole): Unit = {
val done = flow(requestBytesSmall, 10000).run()
Await.ready(done, 32.days)
}
@TearDown
def shutdown(): Unit = {
Await.result(system.terminate(), 5.seconds)
}
}