瀏覽代碼

Keep the `vertx-web-kotlinx` portion updated (#10383)

* Bump all dependencies and toolchains to the latest

* Migrate to Vert.x 5 APIs and bump Kotlin to 2.3.0-RC2 to support Java 25

* Update catching the "connection" reset exceptions

* Try setting `date` with kotlinx-datetime but it doesn't work as expected

Got `java.lang.IllegalStateException: Field offsetHours is not set`.

* Remove the kotlinx-datetime dependency and update the comment

See commit 9cf28f15b6f1806b3ed75260adee8acd822cac91 for a failed attempt to try using kotlinx-datetime.

* Get setting `date` with `kotlinx-datetime` to work

ref: https://github.com/huanshankeji/FrameworkBenchmarks/pull/1

* Review and port some of the changes in `FrameworkBenchmarks/frameworks/Java/vertx/` from commit 057c25b234bae395b1228d6afe0a7fd1c225a74d to commit 1838aa5df242f103a335b74c9095bc88f22643b1, and fix some typos

Some changes are not ported.

There is about 5% performance improvement in the JSON test as tested on my device.

* Increase the io_uring completion queue size to resolve warnings and improve the plaintext test performance

```
io.netty.channel.uring.IoUringIoHandler processCompletionsAndHandleOverflow
vertx: WARNING: CompletionQueue overflow detected, consider increasing size: 4096
```

This is still one warning when the value is set to 8192 as tested on my device, instead of many for the default 4096.

* Benchmark Approach 1 and Approach 3 in `jsonResponseCoHandler` again and fix capitalization BTW

The "Requests/sec" result of Approach 1 is only 40% of Approach 3 as tested on my device.

* Remove an outdated comment as found by Gemini Code Assist

* Use the "connection reset" error code from Netty instead of hard-coding it and also catch Java NIO `SocketException` for developing on other OSs such as macOS and Windows

Tested with the `tfb` command on both macOS and Linux.

* Fix some errors and keep things updated in benchmark_config.json and README.md
Yongshun Ye 1 周之前
父節點
當前提交
975a93d576

+ 1 - 6
frameworks/Kotlin/vertx-web-kotlinx/README.md

@@ -2,7 +2,7 @@
 
 Vert.x-Web in Kotlin with request handling implemented as much with official kotlinx libraries as possible.
 
-Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 21.
+Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 25.
 
 ## Test Type Implementation Source Code
 
@@ -13,7 +13,6 @@ Code is written from scratch to be as concise as possible with common code extra
 * [PLAINTEXT](src/main/kotlin/MainVerticle.kt)
 * [DB](src/main/kotlin/MainVerticle.kt)
 * [QUERY](src/main/kotlin/MainVerticle.kt)
-* [CACHED QUERY](src/main/kotlin/MainVerticle.kt)
 * [UPDATE](src/main/kotlin/MainVerticle.kt)
 * [FORTUNES](src/main/kotlin/MainVerticle.kt)
 
@@ -48,10 +47,6 @@ http://localhost:8080/db
 
 http://localhost:8080/query?queries=
 
-### CACHED QUERY
-
-http://localhost:8080/cached_query?queries=
-
 ### UPDATE
 
 http://localhost:8080/update?queries=

+ 1 - 1
frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json

@@ -40,7 +40,7 @@
         "database_os": "Linux",
         "display_name": "vertx-web-kotlinx-postgresql",
         "notes": "",
-        "versus": "vertx-web"
+        "versus": "vertx-web-postgres"
       }
     }
   ]

+ 10 - 12
frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts

@@ -3,7 +3,7 @@ tasks.wrapper {
 }
 
 plugins {
-    val kotlinVersion = "2.0.21"
+    val kotlinVersion = "2.3.0-RC2"
     kotlin("jvm") version kotlinVersion
     kotlin("plugin.serialization") version kotlinVersion
     application
@@ -13,29 +13,27 @@ repositories {
     mavenCentral()
 }
 
-val vertxVersion = "4.5.10"
-val kotlinxSerializationVersion = "1.7.3"
+val vertxVersion = "5.0.5"
+val kotlinxSerializationVersion = "1.9.0"
 dependencies {
     implementation(platform("io.vertx:vertx-stack-depchain:$vertxVersion"))
     implementation("io.vertx:vertx-web")
     implementation("io.vertx:vertx-pg-client")
-    implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64")
+    //implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64")
+    implementation("io.netty", "netty-transport-native-io_uring", classifier = "linux-x86_64")
     implementation("io.vertx:vertx-lang-kotlin")
     implementation("io.vertx:vertx-lang-kotlin-coroutines")
-    runtimeOnly("io.vertx:vertx-io_uring-incubator")
-    // This dependency has to be added for io_uring to work.
-    runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64")
 
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
 
     implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion")
     implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-io:$kotlinxSerializationVersion")
-    implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.4")
+    implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.8.2")
 
-    implementation("org.jetbrains.kotlinx:kotlinx-html:0.11.0")
-    //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") // the latest version is 0.6.1
+    implementation("org.jetbrains.kotlinx:kotlinx-html:0.12.0")
+    implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1")
 }
 
-kotlin.jvmToolchain(21)
+kotlin.jvmToolchain(25)
 
 application.mainClass.set("MainKt")

二進制
frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar


+ 1 - 1
frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip
 networkTimeout=10000
 validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME

+ 4 - 8
frameworks/Kotlin/vertx-web-kotlinx/gradlew

@@ -1,7 +1,7 @@
 #!/bin/sh
 
 #
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -86,8 +86,7 @@ done
 # shellcheck disable=SC2034
 APP_BASE_NAME=${0##*/}
 # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
-' "$PWD" ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD=maximum
@@ -115,7 +114,6 @@ case "$( uname )" in                #(
   NONSTOP* )        nonstop=true ;;
 esac
 
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
 
 # Determine the Java command to use to start the JVM.
@@ -173,7 +171,6 @@ fi
 # For Cygwin or MSYS, switch paths to Windows format before running java
 if "$cygwin" || "$msys" ; then
     APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
-    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
 
     JAVACMD=$( cygpath --unix "$JAVACMD" )
 
@@ -206,15 +203,14 @@ fi
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Collect all arguments for the java command:
-#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
 #     and any embedded shellness will be escaped.
 #   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
 #     treated as '${Hostname}' itself on the command line.
 
 set -- \
         "-Dorg.gradle.appname=$APP_BASE_NAME" \
-        -classpath "$CLASSPATH" \
-        org.gradle.wrapper.GradleWrapperMain \
+        -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
         "$@"
 
 # Stop when "xargs" is not available.

+ 1 - 2
frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat

@@ -70,11 +70,10 @@ goto fail
 :execute
 @rem Setup the command line
 
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
 
 @rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
 
 :end
 @rem End local scope for the variables with windows NT shell

+ 11 - 3
frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt

@@ -3,9 +3,11 @@ import io.vertx.core.impl.cpu.CpuCoreSensor
 import io.vertx.kotlin.core.deploymentOptionsOf
 import io.vertx.kotlin.core.vertxOptionsOf
 import io.vertx.kotlin.coroutines.coAwait
+import java.util.function.Supplier
 import java.util.logging.Logger
 
 const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark server"
+val numProcessors = CpuCoreSensor.availableProcessors()
 
 val logger = Logger.getLogger("Vert.x-Web Kotlinx Benchmark")
 suspend fun main(args: Array<String>) {
@@ -13,12 +15,18 @@ suspend fun main(args: Array<String>) {
         ?: throw IllegalArgumentException("Specify the first `hasDb` Boolean argument")
 
     logger.info("$SERVER_NAME starting...")
-    val vertx = Vertx.vertx(vertxOptionsOf(preferNativeTransport = true))
+    val vertx = Vertx.vertx(
+        vertxOptionsOf(
+            eventLoopPoolSize = numProcessors, preferNativeTransport = true, disableTCCL = true
+        )
+    )
     vertx.exceptionHandler {
         logger.info("Vertx exception caught: $it")
         it.printStackTrace()
     }
-    vertx.deployVerticle({ MainVerticle(hasDb) }, deploymentOptionsOf(instances = CpuCoreSensor.availableProcessors()))
-        .coAwait()
+    vertx.deployVerticle(
+        Supplier { MainVerticle(hasDb) },
+        deploymentOptionsOf(instances = numProcessors)
+    ).coAwait()
     logger.info("$SERVER_NAME started.")
 }

+ 48 - 30
frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt

@@ -1,4 +1,6 @@
+import io.netty.channel.unix.Errors
 import io.netty.channel.unix.Errors.NativeIoException
+import io.vertx.core.MultiMap
 import io.vertx.core.buffer.Buffer
 import io.vertx.core.http.HttpHeaders
 import io.vertx.core.http.HttpServer
@@ -18,6 +20,9 @@ import io.vertx.sqlclient.Row
 import io.vertx.sqlclient.RowSet
 import io.vertx.sqlclient.Tuple
 import kotlinx.coroutines.Dispatchers
+import kotlinx.datetime.UtcOffset
+import kotlinx.datetime.format.DateTimeComponents
+import kotlinx.datetime.format.format
 import kotlinx.html.*
 import kotlinx.html.stream.appendHTML
 import kotlinx.io.buffered
@@ -26,10 +31,17 @@ import kotlinx.serialization.Serializable
 import kotlinx.serialization.SerializationStrategy
 import kotlinx.serialization.json.Json
 import kotlinx.serialization.json.io.encodeToSink
-import java.time.ZonedDateTime
-import java.time.format.DateTimeFormatter
+import java.net.SocketException
+import kotlin.time.Clock
 
 class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSupport {
+    object HttpHeaderValues {
+        val vertxWeb = HttpHeaders.createOptimized("Vert.x-Web")
+        val applicationJson = HttpHeaders.createOptimized("application/json")
+        val textHtmlCharsetUtf8 = HttpHeaders.createOptimized("text/html; charset=utf-8")
+        val textPlain = HttpHeaders.createOptimized("text/plain")
+    }
+
     // `PgConnection`s as used in the "vertx" portion offers better performance than `PgPool`s.
     lateinit var pgConnection: PgConnection
     lateinit var date: String
@@ -37,12 +49,13 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
 
     lateinit var selectWorldQuery: PreparedQuery<RowSet<Row>>
     lateinit var selectFortuneQuery: PreparedQuery<RowSet<Row>>
-    lateinit var updateWordQuery: PreparedQuery<RowSet<Row>>
+    lateinit var updateWorldQuery: PreparedQuery<RowSet<Row>>
 
     fun setCurrentDate() {
-        // kotlinx-datetime doesn't support the format yet.
-        //date = Clock.System.now().toString()
-        date = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())
+        date = DateTimeComponents.Formats.RFC_1123.format {
+            // We don't need a more complicated system `TimeZone` here (whose offset depends dynamically on the actual time due to DST) since UTC works.
+            setDateTimeOffset(Clock.System.now(), UtcOffset.ZERO)
+        }
     }
 
     override suspend fun start() {
@@ -56,27 +69,25 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
                     user = "benchmarkdbuser",
                     password = "benchmarkdbpass",
                     cachePreparedStatements = true,
-                    pipeliningLimit = 100000
+                    pipeliningLimit = 256
                 )
             ).coAwait()
 
             selectWorldQuery = pgConnection.preparedQuery(SELECT_WORLD_SQL)
             selectFortuneQuery = pgConnection.preparedQuery(SELECT_FORTUNE_SQL)
-            updateWordQuery = pgConnection.preparedQuery(UPDATE_WORLD_SQL)
+            updateWorldQuery = pgConnection.preparedQuery(UPDATE_WORLD_SQL)
         }
 
         setCurrentDate()
         vertx.setPeriodic(1000) { setCurrentDate() }
-        httpServer = vertx.createHttpServer(httpServerOptionsOf(port = 8080))
+        httpServer = vertx.createHttpServer(
+            httpServerOptionsOf(port = 8080, http2ClearTextEnabled = false, strictThreadMode = true)
+        )
             .requestHandler(Router.router(vertx).apply { routes() })
             .exceptionHandler {
                 // wrk resets the connections when benchmarking is finished.
-                if (
-                // for epoll
-                /*(it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer")
-                || (it is SocketException && it.message == "Connection reset")*/
-                // for io_uring
-                    it is NativeIoException && it.message == "io_uring read(..) failed: Connection reset by peer"
+                if ((/* for native transport */it is NativeIoException && it.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE) ||
+                    (/* for Java NIO */ it is SocketException && it.message == "Connection reset")
                 )
                     return@exceptionHandler
 
@@ -93,15 +104,17 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
     }
 
     @Suppress("NOTHING_TO_INLINE")
-    inline fun HttpServerResponse.putCommonHeaders() {
-        putHeader(HttpHeaders.SERVER, "Vert.x-Web")
-        putHeader(HttpHeaders.DATE, date)
+    inline fun MultiMap.addCommonHeaders() {
+        add(HttpHeaders.SERVER, HttpHeaderValues.vertxWeb)
+        add(HttpHeaders.DATE, date)
     }
 
     @Suppress("NOTHING_TO_INLINE")
-    inline fun HttpServerResponse.putJsonResponseHeader() {
-        putCommonHeaders()
-        putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
+    inline fun HttpServerResponse.addJsonResponseHeaders() {
+        headers().run {
+            addCommonHeaders()
+            add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.applicationJson)
+        }
     }
 
 
@@ -117,15 +130,15 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
     ) =
         coHandlerUnconfined {
             it.response().run {
-                putJsonResponseHeader()
+                addJsonResponseHeaders()
 
                 /*
-                // approach 1
+                // Approach 1
                 end(Json.encodeToString(serializer, requestHandler(it)))/*.coAwait()*/
                 */
 
                 /*
-                // approach 2
+                // Approach 2
                 // java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding.
                 toRawSink().buffered().use { bufferedSink ->
                     @OptIn(ExperimentalSerializationApi::class)
@@ -133,7 +146,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
                 }
                 */
 
-                // approach 3
+                // Approach 3
                 end(Buffer.buffer().apply {
                     toRawSink().buffered().use { bufferedSink ->
                         @OptIn(ExperimentalSerializationApi::class)
@@ -197,12 +210,15 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
             }
 
             it.response().run {
-                putCommonHeaders()
-                putHeader(HttpHeaders.CONTENT_TYPE, "text/html; charset=utf-8")
+                headers().run {
+                    addCommonHeaders()
+                    add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textHtmlCharsetUtf8)
+                }
                 end(htmlString)/*.coAwait()*/
             }
         }
 
+        // Some changes to this part in the `vertx` portion in #9142 are not ported.
         get("/updates").jsonResponseCoHandler(Serializers.worlds) {
             val queries = it.request().getQueries()
             val worlds = selectRandomWorlds(queries)
@@ -210,7 +226,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
 
             // Approach 1
             // The updated worlds need to be sorted first to avoid deadlocks.
-            updateWordQuery
+            updateWorldQuery
                 .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).coAwait()
 
             /*
@@ -225,8 +241,10 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup
 
         get("/plaintext").coHandlerUnconfined {
             it.response().run {
-                putCommonHeaders()
-                putHeader(HttpHeaders.CONTENT_TYPE, "text/plain")
+                headers().run {
+                    addCommonHeaders()
+                    add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textPlain)
+                }
                 end("Hello, World!")/*.coAwait()*/
             }
         }

+ 1 - 1
frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt

@@ -2,4 +2,4 @@ import io.vertx.core.Future
 import io.vertx.kotlin.coroutines.coAwait
 
 suspend fun <T> List<Future<T>>.awaitAll(): List<T> =
-    Future.all(this).coAwait().list()
+    Future.all<T>(this).coAwait().list()

+ 11 - 5
frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile

@@ -1,4 +1,4 @@
-FROM gradle:8.10.2-jdk21
+FROM gradle:9.2.1-jdk25
 
 WORKDIR /vertx-web-kotlinx
 COPY build.gradle.kts build.gradle.kts
@@ -10,18 +10,24 @@ RUN gradle --no-daemon installDist
 EXPOSE 8080
 
 CMD export JAVA_OPTS=" \
+    --enable-native-access=ALL-UNNAMED \
+    --sun-misc-unsafe-memory-access=allow \
+    --add-opens=java.base/java.lang=ALL-UNNAMED \
     -server \
     -XX:+UseNUMA \
     -XX:+UseParallelGC \
+    -XX:+UnlockDiagnosticVMOptions \
+    -XX:+DebugNonSafepoints \
+    -Djava.lang.Integer.IntegerCache.high=10000 \
     -Dvertx.disableMetrics=true \
-    -Dvertx.disableH2c=true \
     -Dvertx.disableWebsockets=true \
-    -Dvertx.flashPolicyHandler=false \
-    -Dvertx.threadChecks=false \
     -Dvertx.disableContextTimings=true \
-    -Dvertx.disableTCCL=true \
     -Dvertx.disableHttpHeadersValidation=true \
+    -Dvertx.cacheImmutableHttpResponseHeaders=true \
+    -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \
+    -Dio.netty.noUnsafe=false \
     -Dio.netty.buffer.checkBounds=false \
     -Dio.netty.buffer.checkAccessible=false \
+    -Dio.netty.iouring.ringSize=16384 \
     " && \
     build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true

+ 11 - 5
frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile

@@ -1,4 +1,4 @@
-FROM gradle:8.10.2-jdk21
+FROM gradle:9.2.1-jdk25
 
 WORKDIR /vertx-web-kotlinx
 COPY build.gradle.kts build.gradle.kts
@@ -10,18 +10,24 @@ RUN gradle --no-daemon installDist
 EXPOSE 8080
 
 CMD export JAVA_OPTS=" \
+    --enable-native-access=ALL-UNNAMED \
+    --sun-misc-unsafe-memory-access=allow \
+    --add-opens=java.base/java.lang=ALL-UNNAMED \
     -server \
     -XX:+UseNUMA \
     -XX:+UseParallelGC \
+    -XX:+UnlockDiagnosticVMOptions \
+    -XX:+DebugNonSafepoints \
+    -Djava.lang.Integer.IntegerCache.high=10000 \
     -Dvertx.disableMetrics=true \
-    -Dvertx.disableH2c=true \
     -Dvertx.disableWebsockets=true \
-    -Dvertx.flashPolicyHandler=false \
-    -Dvertx.threadChecks=false \
     -Dvertx.disableContextTimings=true \
-    -Dvertx.disableTCCL=true \
     -Dvertx.disableHttpHeadersValidation=true \
+    -Dvertx.cacheImmutableHttpResponseHeaders=true \
+    -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \
+    -Dio.netty.noUnsafe=false \
     -Dio.netty.buffer.checkBounds=false \
     -Dio.netty.buffer.checkAccessible=false \
+    -Dio.netty.iouring.ringSize=16384 \
     " && \
     build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false