Skip to content

Commit 1e814cf

Browse files
committed
Benchmarks for binary streaming mode
1 parent d4192a5 commit 1e814cf

File tree

3 files changed

+144
-55
lines changed

3 files changed

+144
-55
lines changed

benchmarks/src/main/scala/io/udash/rest/RestApi.scala

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,38 @@
11
package io.udash.rest
22

3+
import com.avsystem.commons.serialization.json.JsonStringOutput
34
import io.udash.rest.RestExampleData.RestResponseSize
45
import io.udash.rest.raw.RawRest
56
import monix.eval.Task
67
import monix.execution.Scheduler
78
import org.openjdk.jmh.annotations.*
89

10+
import java.nio.charset.StandardCharsets
911
import java.util.concurrent.TimeUnit
1012
import scala.concurrent.Await
1113
import scala.concurrent.duration.Duration
1214

1315
private object RestApi {
1416
trait RestTestApi {
1517
@GET def exampleEndpoint(size: RestResponseSize): Task[List[RestExampleData]]
18+
@GET def exampleBinaryEndpoint(size: RestResponseSize): Task[List[Array[Byte]]]
1619
}
1720

1821
object RestTestApi extends DefaultRestApiCompanion[RestTestApi] {
1922
final class Impl extends RestTestApi {
20-
private var responses: Map[RestResponseSize, List[RestExampleData]] =
21-
Map.empty
23+
private var responses: Map[RestResponseSize, List[RestExampleData]] = Map.empty
2224

2325
def exampleEndpoint(size: RestResponseSize): Task[List[RestExampleData]] =
24-
Task.eval(responses(size))
26+
Task.eval(getResponse(size))
2527

26-
def generateResponses(): Unit = {
28+
override def exampleBinaryEndpoint(size: RestResponseSize): Task[List[Array[Byte]]] =
29+
Task.eval(getResponse(size).iterator.map(JsonStringOutput.write(_).getBytes(StandardCharsets.UTF_8)).toList)
30+
31+
private def getResponse(size: RestResponseSize): List[RestExampleData] =
32+
responses(size)
33+
34+
def generateResponses(): Unit =
2735
this.responses = RestResponseSize.values.map(size => size -> RestExampleData.generateRandomList(size)).toMap
28-
}
2936
}
3037
}
3138

@@ -52,21 +59,38 @@ class RestApi {
5259
}
5360

5461
@Benchmark
55-
def smallArray(): Unit = {
62+
def smallArrayJsonList(): Unit = {
5663
waitEndpoint(RestResponseSize.Small)
5764
}
5865

5966
@Benchmark
60-
def mediumArray(): Unit = {
67+
def mediumArrayJsonList(): Unit = {
6168
waitEndpoint(RestResponseSize.Medium)
6269
}
6370

6471
@Benchmark
65-
def hugeArray(): Unit = {
72+
def hugeArrayJsonList(): Unit = {
6673
waitEndpoint(RestResponseSize.Huge)
6774
}
6875

69-
private def waitEndpoint(size: RestResponseSize): Unit = {
70-
Await.result(this.proxy.exampleEndpoint(size).runToFuture, Duration.apply(10, TimeUnit.SECONDS))
76+
@Benchmark
77+
def smallArrayBinary(): Unit = {
78+
waitEndpointBinary(RestResponseSize.Small)
79+
}
80+
81+
@Benchmark
82+
def mediumArrayBinary(): Unit = {
83+
waitEndpointBinary(RestResponseSize.Medium)
7184
}
72-
}
85+
86+
@Benchmark
87+
def hugeArrayBinary(): Unit = {
88+
waitEndpointBinary(RestResponseSize.Huge)
89+
}
90+
91+
private def waitEndpoint(size: RestResponseSize): Unit =
92+
Await.result(this.proxy.exampleEndpoint(size).runToFuture, Duration.apply(10, TimeUnit.SECONDS))
93+
94+
private def waitEndpointBinary(size: RestResponseSize): Unit =
95+
Await.result(this.proxy.exampleBinaryEndpoint(size).runToFuture, Duration.apply(10, TimeUnit.SECONDS))
96+
}
Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
package io.udash.rest
22

3-
import com.avsystem.commons.misc.{AbstractValueEnum, EnumCtx, ValueEnum}
4-
import monix.eval.Task
5-
import monix.reactive.Observable
3+
import com.avsystem.commons.misc.{AbstractValueEnum, EnumCtx}
64

75
import scala.util.Random
86

9-
case class RestExampleData(number: Long, string: String)
10-
11-
object RestExampleData extends RestDataCompanion[RestExampleData]{
7+
final case class RestExampleData(number: Long, string: String)
8+
object RestExampleData extends RestDataCompanion[RestExampleData] {
129
final case class RestResponseSize(value: Int)(implicit enumCtx: EnumCtx) extends AbstractValueEnum
1310
object RestResponseSize extends RestValueEnumCompanion[RestResponseSize] {
1411
final val Small: Value = new RestResponseSize(10)
15-
final val Medium: Value = new RestResponseSize(200)
16-
final val Huge: Value = new RestResponseSize(5000)
12+
final val Medium: Value = new RestResponseSize(500)
13+
final val Huge: Value = new RestResponseSize(10000)
1714
}
1815

19-
private def random() = {
16+
private def random() =
2017
RestExampleData(
2118
Random.nextLong(),
2219
Iterator.continually(Random.nextPrintableChar()).take(200).mkString
2320
)
24-
}
2521

2622
def generateRandomList(size: RestResponseSize): List[RestExampleData] =
2723
Range(0, size.value).toList.map(_ => RestExampleData.random())
28-
29-
}
24+
}

benchmarks/src/main/scala/io/udash/rest/StreamingRestApi.scala

Lines changed: 102 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,71 @@
11
package io.udash.rest
22

3+
import com.avsystem.commons.serialization.json.JsonStringOutput
34
import io.udash.rest.RestExampleData.RestResponseSize
45
import io.udash.rest.raw.{RawRest, RestRequest, RestResponse, StreamedRestResponse}
56
import monix.eval.Task
67
import monix.execution.Scheduler
78
import monix.reactive.Observable
89
import org.openjdk.jmh.annotations.*
910

11+
import java.nio.charset.StandardCharsets
1012
import java.util.concurrent.TimeUnit
1113
import scala.concurrent.Await
1214
import scala.concurrent.duration.Duration
1315

1416
private object StreamingRestApi {
1517
trait RestTestApi {
1618
@GET def exampleEndpoint(size: RestResponseSize): Observable[RestExampleData]
19+
@GET def exampleEndpointBinary(size: RestResponseSize): Observable[Array[Byte]]
1720

1821
@streamingResponseBatchSize(10)
1922
@GET def exampleEndpointBatch10(size: RestResponseSize): Observable[RestExampleData]
2023

24+
@streamingResponseBatchSize(10)
25+
@GET def exampleEndpointBatch10Binary(size: RestResponseSize): Observable[Array[Byte]]
26+
2127
@streamingResponseBatchSize(500)
2228
@GET def exampleEndpointBatch500(size: RestResponseSize): Observable[RestExampleData]
2329

30+
@streamingResponseBatchSize(500)
31+
@GET def exampleEndpointBatch500Binary(size: RestResponseSize): Observable[Array[Byte]]
32+
2433
@GET def exampleEndpointWithoutStreaming(size: RestResponseSize): Task[List[RestExampleData]]
2534
}
2635

2736
object RestTestApi extends DefaultRestApiCompanion[RestTestApi] {
2837
final class Impl extends RestTestApi {
29-
private var responses: Map[RestResponseSize, List[RestExampleData]] =
30-
Map.empty
38+
private var responses: Map[RestResponseSize, List[RestExampleData]] = Map.empty
3139

3240
def exampleEndpoint(size: RestResponseSize): Observable[RestExampleData] =
33-
Observable.fromIterable(responses(size))
41+
Observable.fromIterable(getResponse(size))
42+
43+
def exampleEndpointBinary(size: RestResponseSize): Observable[Array[Byte]] =
44+
getResponseBinary(size)
3445

3546
def exampleEndpointBatch10(size: RestResponseSize): Observable[RestExampleData] =
36-
Observable.fromIterable(responses(size))
47+
Observable.fromIterable(getResponse(size))
48+
49+
def exampleEndpointBatch10Binary(size: RestResponseSize): Observable[Array[Byte]] =
50+
getResponseBinary(size)
3751

3852
def exampleEndpointBatch500(size: RestResponseSize): Observable[RestExampleData] =
39-
Observable.fromIterable(responses(size))
53+
Observable.fromIterable(getResponse(size))
54+
55+
def exampleEndpointBatch500Binary(size: RestResponseSize): Observable[Array[Byte]] =
56+
getResponseBinary(size)
4057

4158
def exampleEndpointWithoutStreaming(size: RestResponseSize): Task[List[RestExampleData]] =
42-
Task.eval(responses(size))
59+
Task.eval(getResponse(size))
60+
61+
private def getResponse(size: RestResponseSize): List[RestExampleData] =
62+
responses(size)
63+
64+
private def getResponseBinary(size: RestResponseSize): Observable[Array[Byte]] =
65+
Observable.fromIterable(getResponse(size)).map(JsonStringOutput.write(_).getBytes(StandardCharsets.UTF_8))
4366

44-
def generateResponses(): Unit = {
67+
def generateResponses(): Unit =
4568
this.responses = RestResponseSize.values.map(size => size -> RestExampleData.generateRandomList(size)).toMap
46-
}
4769
}
4870
}
4971

@@ -76,48 +98,93 @@ class StreamingRestApi {
7698
}
7799

78100
@Benchmark
79-
def smallArray(): Unit = {
101+
def smallArrayJsonList(): Unit = {
80102
waitStreamingEndpoint(RestResponseSize.Small)
81103
}
82104

83105
@Benchmark
84-
def mediumArray(): Unit = {
106+
def mediumArrayJsonList(): Unit = {
85107
waitStreamingEndpoint(RestResponseSize.Medium)
86108
}
87109

88110
@Benchmark
89-
def hugeArray(): Unit = {
111+
def hugeArrayJsonList(): Unit = {
90112
waitStreamingEndpoint(RestResponseSize.Huge)
91113
}
92114

93115
@Benchmark
94-
def smallArrayBatch10(): Unit = {
95-
wait(this.proxy.exampleEndpointBatch10(RestResponseSize.Small).toListL)
116+
def smallArrayBinary(): Unit = {
117+
waitStreamingEndpointBinary(RestResponseSize.Small)
118+
}
119+
120+
@Benchmark
121+
def mediumArrayBinary(): Unit = {
122+
waitStreamingEndpointBinary(RestResponseSize.Medium)
123+
}
124+
125+
@Benchmark
126+
def hugeArrayBinary(): Unit = {
127+
waitStreamingEndpointBinary(RestResponseSize.Huge)
128+
}
129+
130+
@Benchmark
131+
def smallArrayBatch10JsonList(): Unit = {
132+
waitObservable(this.proxy.exampleEndpointBatch10(RestResponseSize.Small))
133+
}
134+
135+
@Benchmark
136+
def mediumArrayBatch10JsonList(): Unit = {
137+
waitObservable(this.proxy.exampleEndpointBatch10(RestResponseSize.Medium))
96138
}
97139

98140
@Benchmark
99-
def mediumArrayBatch10(): Unit = {
100-
wait(this.proxy.exampleEndpointBatch10(RestResponseSize.Medium).toListL)
141+
def hugeArrayBatch10JsonList(): Unit = {
142+
waitObservable(this.proxy.exampleEndpointBatch10(RestResponseSize.Huge))
101143
}
102144

103145
@Benchmark
104-
def hugeArrayBatch10(): Unit = {
105-
wait(this.proxy.exampleEndpointBatch10(RestResponseSize.Huge).toListL)
146+
def smallArrayBatch10Binary(): Unit = {
147+
waitObservable(this.proxy.exampleEndpointBatch10Binary(RestResponseSize.Small))
106148
}
107149

108150
@Benchmark
109-
def smallArrayBatch500(): Unit = {
110-
wait(this.proxy.exampleEndpointBatch500(RestResponseSize.Small).toListL)
151+
def mediumArrayBatch10Binary(): Unit = {
152+
waitObservable(this.proxy.exampleEndpointBatch10Binary(RestResponseSize.Medium))
111153
}
112154

113155
@Benchmark
114-
def mediumArrayBatch500(): Unit = {
115-
wait(this.proxy.exampleEndpointBatch500(RestResponseSize.Medium).toListL)
156+
def hugeArrayBatch10Binary(): Unit = {
157+
waitObservable(this.proxy.exampleEndpointBatch10Binary(RestResponseSize.Huge))
116158
}
117159

118160
@Benchmark
119-
def hugeArrayBatch500(): Unit = {
120-
wait(this.proxy.exampleEndpointBatch500(RestResponseSize.Huge).toListL)
161+
def smallArrayBatch500JsonList(): Unit = {
162+
waitObservable(this.proxy.exampleEndpointBatch500(RestResponseSize.Small))
163+
}
164+
165+
@Benchmark
166+
def mediumArrayBatch500JsonList(): Unit = {
167+
waitObservable(this.proxy.exampleEndpointBatch500(RestResponseSize.Medium))
168+
}
169+
170+
@Benchmark
171+
def hugeArrayBatch500JsonList(): Unit = {
172+
waitObservable(this.proxy.exampleEndpointBatch500(RestResponseSize.Huge))
173+
}
174+
175+
@Benchmark
176+
def smallArrayBatch500Binary(): Unit = {
177+
waitObservable(this.proxy.exampleEndpointBatch500Binary(RestResponseSize.Small))
178+
}
179+
180+
@Benchmark
181+
def mediumArrayBatch500Binary(): Unit = {
182+
waitObservable(this.proxy.exampleEndpointBatch500Binary(RestResponseSize.Medium))
183+
}
184+
185+
@Benchmark
186+
def hugeArrayBatch500Binary(): Unit = {
187+
waitObservable(this.proxy.exampleEndpointBatch500Binary(RestResponseSize.Huge))
121188
}
122189

123190
@Benchmark
@@ -135,15 +202,18 @@ class StreamingRestApi {
135202
waitEndpointWithoutStreaming(RestResponseSize.Huge)
136203
}
137204

138-
private def waitEndpointWithoutStreaming(samples: RestResponseSize): Unit = {
205+
private def waitEndpointWithoutStreaming(samples: RestResponseSize): Unit =
139206
wait(this.proxy.exampleEndpointWithoutStreaming(samples))
140-
}
141207

142-
private def waitStreamingEndpoint(samples: RestResponseSize): Unit = {
143-
wait(this.proxy.exampleEndpoint(samples).toListL)
144-
}
208+
private def waitStreamingEndpoint(samples: RestResponseSize): Unit =
209+
wait(this.proxy.exampleEndpoint(samples).completedL)
145210

146-
private def wait[T](task: Task[List[T]]): Unit = {
147-
Await.result(task.runToFuture, Duration.apply(10, TimeUnit.SECONDS))
148-
}
149-
}
211+
private def waitStreamingEndpointBinary(samples: RestResponseSize): Unit =
212+
wait(this.proxy.exampleEndpointBinary(samples).completedL)
213+
214+
private def wait[T](task: Task[T]): Unit =
215+
Await.result(task.runToFuture, Duration.apply(15, TimeUnit.SECONDS))
216+
217+
private def waitObservable[T](obs: Observable[T]): Unit =
218+
Await.result(obs.completedL.runToFuture, Duration.apply(15, TimeUnit.SECONDS))
219+
}

0 commit comments

Comments
 (0)