Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frameworks/Java/netty/.sdkmanrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=24-oracle
19 changes: 19 additions & 0 deletions frameworks/Java/netty/benchmark_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@
"display_name": "netty",
"notes": "",
"versus": "netty"
},
"loom": {
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 8080,
"approach": "Realistic",
"classification": "Platform",
"database": "None",
"framework": "netty",
"language": "Java",
"flavor": "None",
"orm": "Raw",
"platform": "Netty",
"webserver": "None",
"os": "Linux",
"database_os": "Linux",
"display_name": "netty",
"notes": "",
"versus": "netty"
}
}]
}
13 changes: 13 additions & 0 deletions frameworks/Java/netty/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,16 @@ orm = "Raw"
platform = "Netty"
webserver = "None"
versus = "netty"

[loom]
urls.plaintext = "/plaintext"
urls.json = "/json"
approach = "Realistic"
classification = "Platform"
database = "None"
database_os = "Linux"
os = "Linux"
orm = "Raw"
platform = "Netty"
webserver = "None"
versus = "netty"
15 changes: 15 additions & 0 deletions frameworks/Java/netty/netty-loom.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM maven:3.9.9-eclipse-temurin-24-noble as maven
WORKDIR /netty
COPY pom.xml pom.xml
COPY src src
RUN mvn compile assembly:single -q

FROM maven:3.9.9-eclipse-temurin-24-noble
WORKDIR /netty
COPY --from=maven /netty/target/app.jar app.jar
COPY run_netty_loom.sh run_netty_loom.sh

EXPOSE 8080
# see https://github.com/netty/netty/issues/14942
# remember to run this with --privileged since https://github.com/TechEmpower/FrameworkBenchmarks/blob/c94f7f95bd751f86a57dea8b63fb8f336bdbbde3/toolset/utils/docker_helper.py#L239 does it
ENTRYPOINT "./run_netty_loom.sh"
12 changes: 7 additions & 5 deletions frameworks/Java/netty/netty.dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
FROM maven:3.6.1-jdk-11-slim as maven
FROM maven:3.9.9-eclipse-temurin-24-noble as maven
WORKDIR /netty
COPY pom.xml pom.xml
COPY src src
RUN mvn compile assembly:single -q

FROM openjdk:11.0.3-jdk-slim
FROM maven:3.9.9-eclipse-temurin-24-noble
WORKDIR /netty
COPY --from=maven /netty/target/netty-example-0.1-jar-with-dependencies.jar app.jar
COPY --from=maven /netty/target/app.jar app.jar
COPY run_netty.sh run_netty.sh

EXPOSE 8080

CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.iouring.iosqeAsyncThreshold=32000", "-jar", "app.jar"]
# see https://github.com/netty/netty/issues/14942
# remember to run this with --privileged since https://github.com/TechEmpower/FrameworkBenchmarks/blob/c94f7f95bd751f86a57dea8b63fb8f336bdbbde3/toolset/utils/docker_helper.py#L239 does it
ENTRYPOINT "./run_netty.sh"
17 changes: 9 additions & 8 deletions frameworks/Java/netty/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
<version>0.1</version>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<netty.version>4.1.108.Final</netty.version>
<io_uring.version>0.0.21.Final</io_uring.version>
<maven.compiler.source>24</maven.compiler.source>
<maven.compiler.target>24</maven.compiler.target>
<netty.version>4.2.0.Final</netty.version>
</properties>

<packaging>jar</packaging>
Expand All @@ -21,7 +20,7 @@

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
</dependency>

Expand All @@ -40,9 +39,9 @@
</dependency>

<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-transport-native-io_uring</artifactId>
<version>${io_uring.version}</version>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-io_uring</artifactId>
<version>${netty.version}</version>
<classifier>linux-x86_64</classifier>
</dependency>

Expand Down Expand Up @@ -74,6 +73,7 @@
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>app</finalName>
<archive>
<manifest>
<mainClass>hello.HelloWebServer</mainClass>
Expand All @@ -82,6 +82,7 @@
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
Expand Down
14 changes: 14 additions & 0 deletions frameworks/Java/netty/run_netty.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

# PROFILING: -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints
JAVA_OPTIONS="--enable-native-access=ALL-UNNAMED \
-Dio.netty.noUnsafe=false \
--sun-misc-unsafe-memory-access=allow \
--add-opens=java.base/java.lang=ALL-UNNAMED \
-XX:+UseNUMA \
-XX:+UseParallelGC \
-Dio.netty.buffer.checkBounds=false \
-Dio.netty.buffer.checkAccessible=false \
$@"

java $JAVA_OPTIONS -jar app.jar
15 changes: 15 additions & 0 deletions frameworks/Java/netty/run_netty_loom.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# PROFILING: -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints
JAVA_OPTIONS="--enable-native-access=ALL-UNNAMED \
-Dio.netty.noUnsafe=false \
--sun-misc-unsafe-memory-access=allow \
--add-opens=java.base/java.lang=ALL-UNNAMED \
-XX:+UseNUMA \
-XX:+UseParallelGC \
-Dio.netty.buffer.checkBounds=false \
-Dio.netty.buffer.checkAccessible=false \
-Dhello.eventloop.carrier=true \
$@"

java $JAVA_OPTIONS -jar app.jar
24 changes: 24 additions & 0 deletions frameworks/Java/netty/src/main/java/hello/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package hello;

import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;

public class Constants {

public static final byte[] STATIC_PLAINTEXT = "Hello, World!".getBytes(CharsetUtil.UTF_8);
public static final int STATIC_PLAINTEXT_LEN = STATIC_PLAINTEXT.length;

public static final CharSequence PLAINTEXT_CLHEADER_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN));
public static final int JSON_LEN = jsonLen();
public static final CharSequence JSON_CLHEADER_VALUE = AsciiString.cached(String.valueOf(JSON_LEN));
public static final CharSequence SERVER_NAME = AsciiString.cached("Netty");

private static int jsonLen() {
return JsonUtils.serializeMsg(newMsg()).length;
}

public static Message newMsg() {
return new Message("Hello, World!");
}

}
101 changes: 32 additions & 69 deletions frameworks/Java/netty/src/main/java/hello/HelloServerHandler.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
package hello;

import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaderNames.DATE;
import static io.netty.handler.codec.http.HttpHeaderNames.SERVER;
import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON;
import static io.netty.handler.codec.http.HttpHeaderValues.TEXT_PLAIN;
import static hello.Constants.STATIC_PLAINTEXT;
import static hello.Constants.newMsg;
import static hello.HttpResponses.makeJsonResponse;
import static hello.HttpResponses.makePlaintextResponse;
import static hello.JsonUtils.acquireJsonStreamFromEventLoop;
import static hello.JsonUtils.releaseJsonStreamFromEventLoop;
import static hello.JsonUtils.serializeMsg;
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.jsoniter.output.JsonStream;
import com.jsoniter.output.JsonStreamPool;
import com.jsoniter.spi.JsonException;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
Expand All @@ -33,51 +29,21 @@
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.FastThreadLocal;

public class HelloServerHandler extends ChannelInboundHandlerAdapter {

private static final FastThreadLocal<DateFormat> FORMAT = new FastThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
}
};

private static Message newMsg() {
return new Message("Hello, World!");
}

private static byte[] serializeMsg(Message obj) {
JsonStream stream = JsonStreamPool.borrowJsonStream();
try {
stream.reset(null);
stream.writeVal(Message.class, obj);
return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
} catch (IOException e) {
throw new JsonException(e);
} finally {
JsonStreamPool.returnJsonStream(stream);
}
}

private static int jsonLen() {
return serializeMsg(newMsg()).length;
}
private static final FastThreadLocal<DateFormat> FORMAT = new FastThreadLocal<>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
}
};

private static final byte[] STATIC_PLAINTEXT = "Hello, World!".getBytes(CharsetUtil.UTF_8);
private static final int STATIC_PLAINTEXT_LEN = STATIC_PLAINTEXT.length;
protected volatile AsciiString date = new AsciiString(FORMAT.get().format(new Date()));

private static final CharSequence PLAINTEXT_CLHEADER_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN));
private static final int JSON_LEN = jsonLen();
private static final CharSequence JSON_CLHEADER_VALUE = AsciiString.cached(String.valueOf(JSON_LEN));
private static final CharSequence SERVER_NAME = AsciiString.cached("Netty");

private volatile CharSequence date = new AsciiString(FORMAT.get().format(new Date()));

HelloServerHandler(ScheduledExecutorService service) {
public HelloServerHandler(ScheduledExecutorService service) {
service.scheduleWithFixedDelay(new Runnable() {
private final DateFormat format = FORMAT.get();

Expand Down Expand Up @@ -118,42 +84,39 @@ private void process(ChannelHandlerContext ctx, HttpRequest request) throws Exce
String uri = request.uri();
switch (uri) {
case "/plaintext":
writePlainResponse(ctx, Unpooled.wrappedBuffer(STATIC_PLAINTEXT));
writePlainResponse(ctx, date);
return;
case "/json":
byte[] json = serializeMsg(newMsg());
writeJsonResponse(ctx, Unpooled.wrappedBuffer(json));
// even for the virtual thread case we expect virtual threads to be executed inlined!
var stream = acquireJsonStreamFromEventLoop();
try {
writeJsonResponse(ctx, stream, date);
} finally {
releaseJsonStreamFromEventLoop(stream);
}
return;
}
// we drain in-flight responses before closing the connection
channelReadComplete(ctx);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND, Unpooled.EMPTY_BUFFER, false);
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
}

private void writePlainResponse(ChannelHandlerContext ctx, ByteBuf buf) {
ctx.write(makeResponse(buf, TEXT_PLAIN, PLAINTEXT_CLHEADER_VALUE), ctx.voidPromise());
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}

private void writeJsonResponse(ChannelHandlerContext ctx, ByteBuf buf) {
ctx.write(makeResponse(buf, APPLICATION_JSON, JSON_CLHEADER_VALUE), ctx.voidPromise());
protected void writePlainResponse(ChannelHandlerContext ctx, AsciiString date) {
ctx.write(makePlaintextResponse(date), ctx.voidPromise());
}

private FullHttpResponse makeResponse(ByteBuf buf, CharSequence contentType, CharSequence contentLength) {
final FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, buf, false);
response.headers()
.set(CONTENT_TYPE, contentType)
.set(SERVER, SERVER_NAME)
.set(DATE, date)
.set(CONTENT_LENGTH, contentLength);
return response;
protected void writeJsonResponse(ChannelHandlerContext ctx, JsonStream stream, AsciiString date) {
ctx.write(makeJsonResponse(stream, date), ctx.voidPromise());
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close();
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {

private final ScheduledExecutorService service;
protected final ScheduledExecutorService service;

public HelloServerInitializer(ScheduledExecutorService service) {
this.service = service;
Expand Down Expand Up @@ -46,6 +46,10 @@ protected boolean isContentAlwaysEmpty(final HttpMessage msg) {
return false;
}
})
.addLast("handler", new HelloServerHandler(service));
.addLast("handler", newHelloServerHandler(service));
}

protected HelloServerHandler newHelloServerHandler(ScheduledExecutorService service) {
return new HelloServerHandler(service);
}
}
Loading
Loading