2015-09-03 15:26:49 +03:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2014 Typesafe Inc. <http://www.typesafe.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.stream.io
|
|
|
|
|
|
|
|
|
|
import java.io.{FileInputStream, File}
|
|
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
|
|
|
|
|
|
import akka.actor.ActorSystem
|
|
|
|
|
import akka.stream.{Attributes, ActorMaterializer}
|
|
|
|
|
import akka.stream.scaladsl._
|
|
|
|
|
import akka.util.ByteString
|
|
|
|
|
import org.openjdk.jmh.annotations._
|
|
|
|
|
|
|
|
|
|
import scala.concurrent.duration._
|
|
|
|
|
import scala.concurrent.{Promise, Await, Future}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Benchmark (bufSize) Mode Cnt Score Error Units
|
|
|
|
|
* FileSourcesBenchmark.fileChannel 2048 avgt 100 1140.192 ± 55.184 ms/op
|
|
|
|
|
*/
|
|
|
|
|
@State(Scope.Benchmark)
|
|
|
|
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
|
|
|
|
@BenchmarkMode(Array(Mode.AverageTime))
|
|
|
|
|
class FileSourcesBenchmark {
|
|
|
|
|
|
|
|
|
|
implicit val system = ActorSystem("file-sources-benchmark")
|
|
|
|
|
implicit val mat = ActorMaterializer()
|
|
|
|
|
|
|
|
|
|
val file: File = {
|
|
|
|
|
val line = ByteString("x" * 2048 + "\n")
|
|
|
|
|
|
|
|
|
|
val f = File.createTempFile(getClass.getName, ".bench.tmp")
|
|
|
|
|
f.deleteOnExit()
|
|
|
|
|
|
|
|
|
|
val ft = Source(() ⇒ Iterator.continually(line))
|
|
|
|
|
.take(10 * 39062) // adjust as needed
|
2015-11-14 22:42:22 +01:00
|
|
|
.runWith(Sink.file(f))
|
2015-09-03 15:26:49 +03:00
|
|
|
Await.result(ft, 30.seconds)
|
|
|
|
|
|
|
|
|
|
f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Param(Array("2048"))
|
|
|
|
|
val bufSize = 0
|
|
|
|
|
|
|
|
|
|
var fileChannelSource: Source[ByteString, Future[Long]] = _
|
|
|
|
|
var fileInputStreamSource: Source[ByteString, Future[Long]] = _
|
|
|
|
|
var ioSourceLinesIterator: Source[ByteString, Unit] = _
|
|
|
|
|
|
|
|
|
|
@Setup
|
|
|
|
|
def setup() {
|
2015-11-14 22:42:22 +01:00
|
|
|
fileChannelSource = Source.file(file, bufSize)
|
2015-11-17 13:17:30 +01:00
|
|
|
fileInputStreamSource = Source.inputStream(() ⇒ new FileInputStream(file), bufSize)
|
2015-09-03 15:26:49 +03:00
|
|
|
ioSourceLinesIterator = Source(() ⇒ scala.io.Source.fromFile(file).getLines()).map(ByteString(_))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@TearDown
|
|
|
|
|
def teardown(): Unit = {
|
|
|
|
|
file.delete()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@TearDown
|
|
|
|
|
def shutdown() {
|
|
|
|
|
system.shutdown()
|
|
|
|
|
system.awaitTermination()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Benchmark
|
|
|
|
|
def fileChannel() = {
|
|
|
|
|
val h = fileChannelSource.to(Sink.ignore).run()
|
|
|
|
|
|
|
|
|
|
Await.result(h, 30.seconds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Benchmark
|
|
|
|
|
def fileChannel_noReadAhead() = {
|
|
|
|
|
val h = fileChannelSource.withAttributes(Attributes.inputBuffer(1, 1)).to(Sink.ignore).run()
|
|
|
|
|
|
|
|
|
|
Await.result(h, 30.seconds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Benchmark
|
|
|
|
|
def inputStream() = {
|
|
|
|
|
val h = fileInputStreamSource.to(Sink.ignore).run()
|
|
|
|
|
|
|
|
|
|
Await.result(h, 30.seconds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The previous status quo was very slow:
|
|
|
|
|
* Benchmark Mode Cnt Score Error Units
|
|
|
|
|
* FileSourcesBenchmark.naive_ioSourceLinesIterator avgt 20 7067.944 ± 1341.847 ms/op
|
|
|
|
|
*/
|
|
|
|
|
@Benchmark
|
|
|
|
|
def naive_ioSourceLinesIterator() = {
|
|
|
|
|
val p = Promise[Unit]()
|
|
|
|
|
ioSourceLinesIterator.to(Sink.onComplete(p.complete(_))).run()
|
|
|
|
|
|
|
|
|
|
Await.result(p.future, 30.seconds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|