Skip to content

Commit

Permalink
Try fixing the performance issues of the "vertx-web-kotlinx" portion …
Browse files Browse the repository at this point in the history
…in the "single query" and "JSON serialization" tests in the [Continuous Benchmarking results](https://tfb-status.techempower.com/) by using static kotlinx.serialization serializers

The "vertx-web-kotlinx" results in the Continuous Benchmarking results are much lower than those of the "vertx-web-kotlin-coroutines" portion. See [the latest results](https://www.techempower.com/benchmarks/#section=test&runid=592cab59-a9db-463b-a9c9-33d2f9484e92&hw=ph&test=db) for example.

Looking at the "single query" results, I first suspected that it was caused by there being not enough memory for the JVM runtime, so I added some logging code that prints the memory usage using `Runtime.totalMemory` and `Runtime.maxMemory`. It showed that there was about 7 GB max memory available during the benchmark runs, and the program only used 400 MB to 1 GB. I then tried allocating a 4 GB array during the run to ensure that the memory was usable and it worked with no problem.

Then looking at the "JSON serialization" results again, I saw that "vertx-web-kotlinx" performs a lot worse in this test too, and decided that this is more likely to be the bottleneck. Therefore, the static serializers are provided explicitly and the performance is improved slightly as tested on my machine. (Also, see commit 315b4e3 for an attempt before.) I then copied the "JSON serialization" test code from "vertx-web-kotlin-coroutines" and ran the benchmark to see if there were other factors, such as project configuration differences, affecting the performance, and the answer was no. On my machine, the "JSON serialization" performance of "vertx-web-kotlinx" is about 80% - 85% of that of "vertx-web-kotlin-coroutines". And I think the bottleneck possibly lies in kotlinx.serialization serializing an object to a byte array first and then copying it to a Vert.x buffer.

Remove the broken tag in "vertx-web-kotlin-coroutines" BTW, which was added in commit e53e026, for the benchmark runs without problems now as I tested.
  • Loading branch information
ShreckYe committed Oct 28, 2024
1 parent 32ecdf0 commit 9add83e
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
"database_os": "Linux",
"display_name": "vertx-web-kotlin-coroutines",
"notes": "",
"versus": "vertx-web",
"tags": ["broken"]
"versus": "vertx-web"
},
"postgres": {
"db_url": "/db",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import kotlinx.coroutines.launch
import kotlinx.html.*
import kotlinx.html.stream.appendHTML
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.json.Json
import java.net.SocketException
import java.time.ZonedDateTime
Expand Down Expand Up @@ -111,11 +111,13 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() {
putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
}

inline fun <reified T : Any> Route.jsonResponseHandler(crossinline requestHandler: suspend (RoutingContext) -> @Serializable T) =
inline fun <reified T : Any> Route.jsonResponseHandler(
serializer: SerializationStrategy<T>, crossinline requestHandler: suspend (RoutingContext) -> @Serializable T
) =
checkedCoroutineHandlerUnconfined {
it.response().run {
putJsonResponseHeader()
end(Json.encodeToString(requestHandler(it)))/*.coAwait()*/
end(Json.encodeToString(serializer, requestHandler(it)))/*.coAwait()*/
}
}

Expand All @@ -127,16 +129,16 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() {
}

fun Router.routes() {
get("/json").jsonResponseHandler {
get("/json").jsonResponseHandler(Serializers.message) {
jsonSerializationMessage
}

get("/db").jsonResponseHandler {
get("/db").jsonResponseHandler(Serializers.world) {
val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).coAwait()
rowSet.single().toWorld()
}

get("/queries").jsonResponseHandler {
get("/queries").jsonResponseHandler(Serializers.worlds) {
val queries = it.request().getQueries()
selectRandomWorlds(queries)
}
Expand Down Expand Up @@ -178,7 +180,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() {
}
}

get("/updates").jsonResponseHandler {
get("/updates").jsonResponseHandler(Serializers.worlds) {
val queries = it.request().getQueries()
val worlds = selectRandomWorlds(queries)
val updatedWorlds = worlds.map { it.copy(randomNumber = randomIntBetween1And10000()) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import kotlinx.serialization.serializer

object Serializers {
val message = serializer<Message>()
val world = serializer<World>()
val worlds = serializer<List<World>>()
}

1 comment on commit 9add83e

@ShreckYe
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the JSON case, it's serialized to a string instead of a byte array.

Please sign in to comment.