Browse Source

Merge pull request #805 from lneves/master

Minor optimization tweaks:
jlucier-techempower 11 years ago
parent
commit
9a474496b1

+ 2 - 2
netty/README.md

@@ -8,8 +8,8 @@ This is the netty portion of a [benchmarking test suite](../) comparing a variet
 ## Versions
 ## Versions
 
 
 * [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
 * [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
-* [Netty 4.0.14.Beta1](http://netty.io/)
-* [Jackson 2.3.0](http://wiki.fasterxml.com/JacksonHome)
+* [Netty 4.0.16](http://netty.io/)
+* [Jackson 2.3.1](http://wiki.fasterxml.com/JacksonHome)
 
 
 ## References
 ## References
 * https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example/http/snoop
 * https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example/http/snoop

+ 74 - 68
netty/pom.xml

@@ -1,72 +1,78 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
 
-  <modelVersion>4.0.0</modelVersion>
+	<modelVersion>4.0.0</modelVersion>
 
 
-  <groupId>com.techempower</groupId>
-  <artifactId>netty-example</artifactId>
-  <version>0.1</version>
-  
-  <packaging>jar</packaging>
+	<groupId>com.techempower</groupId>
+	<artifactId>netty-example</artifactId>
+	<version>0.1</version>
 
 
-  <dependencies>
-    <dependency>
-      <groupId>io.netty</groupId>
-      <artifactId>netty-codec-http</artifactId>
-      <version>4.0.14.Beta1</version>
-    </dependency>
-	 <dependency>
-		<groupId>com.fasterxml.jackson.core</groupId>
-		<artifactId>jackson-databind</artifactId>
-		<version>2.3.0</version>
-	 </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
-      <version>2.1.1</version>
-    </dependency>
-    <dependency>
-      <groupId>org.javassist</groupId>
-      <artifactId>javassist</artifactId>
-      <version>3.18.0-GA</version>
-    </dependency>
-  </dependencies>
-  
-  <build>
-    <plugins>
-      <plugin>
-        <inherited>true</inherited>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <version>2.3.2</version>
-        <configuration>
-          <source>1.7</source>
-          <target>1.7</target>
-          <optimize>true</optimize>
-          <debug>false</debug>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifest>
-              <mainClass>hello.HelloWebServer</mainClass>
-            </manifest>
-          </archive>
-          <descriptorRefs>
-            <descriptorRef>jar-with-dependencies</descriptorRef>
-          </descriptorRefs>
-        </configuration>
-        <executions>
-          <execution>
-            <id>make-assembly</id> <!-- this is used for inheritance merges -->
-            <phase>package</phase> <!-- bind to the packaging phase -->
-            <goals>
-              <goal>single</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
+	<packaging>jar</packaging>
+
+	<dependencies>
+		<dependency>
+			<groupId>io.netty</groupId>
+			<artifactId>netty-codec-http</artifactId>
+			<version>4.0.17.Final</version>
+		</dependency>
+		<dependency>
+			<groupId>io.netty</groupId>
+			<artifactId>netty-transport-native-epoll</artifactId>
+			<version>4.0.17.Final</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+			<version>2.3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.module</groupId>
+			<artifactId>jackson-module-afterburner</artifactId>
+			<version>2.3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>javassist</groupId>
+			<artifactId>javassist</artifactId>
+			<version>RELEASE</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<inherited>true</inherited>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version>
+				<configuration>
+					<source>1.7</source>
+					<target>1.7</target>
+					<optimize>true</optimize>
+					<debug>false</debug>
+				</configuration>
+			</plugin>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifest>
+							<mainClass>hello.HelloWebServer</mainClass>
+						</manifest>
+					</archive>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-assembly</id> <!-- this is used for inheritance merges -->
+						<phase>package</phase> <!-- bind to the packaging phase -->
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
 </project>
 </project>

+ 1 - 1
netty/setup.py

@@ -6,7 +6,7 @@ import os
 def start(args, logfile, errfile):
 def start(args, logfile, errfile):
   try:
   try:
     subprocess.check_call("mvn clean compile assembly:single", shell=True, cwd="netty", stderr=errfile, stdout=logfile)
     subprocess.check_call("mvn clean compile assembly:single", shell=True, cwd="netty", stderr=errfile, stdout=logfile)
-    subprocess.Popen("java -jar netty-example-0.1-jar-with-dependencies.jar".rsplit(" "), cwd="netty/target", stderr=errfile, stdout=logfile)
+    subprocess.Popen("java -server -XX:+UseNUMA -XX:+UseParallelGC -XX:+AggressiveOpts -jar netty-example-0.1-jar-with-dependencies.jar".rsplit(" "), cwd="netty/target", stderr=errfile, stdout=logfile)
     return 0
     return 0
   except subprocess.CalledProcessError:
   except subprocess.CalledProcessError:
     return 1
     return 1

+ 1 - 0
netty/source_code

@@ -5,3 +5,4 @@
 ./netty/src/main/java/hello/HelloServerInitializer.java
 ./netty/src/main/java/hello/HelloServerInitializer.java
 ./netty/src/main/java/hello/HelloWebServer.java
 ./netty/src/main/java/hello/HelloWebServer.java
 ./netty/src/main/java/hello/HelloServerHandler.java
 ./netty/src/main/java/hello/HelloServerHandler.java
+./netty/src/main/java/hello/Message.java

+ 42 - 43
netty/src/main/java/hello/HelloServerHandler.java

@@ -2,16 +2,8 @@ package hello;
 
 
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import io.netty.buffer.Unpooled;
-
-import java.text.SimpleDateFormat;
-import java.util.*;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import com.fasterxml.jackson.databind.*;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
@@ -22,23 +14,56 @@ import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.HttpVersion;
 import io.netty.handler.codec.http.HttpVersion;
 import io.netty.util.CharsetUtil;
 import io.netty.util.CharsetUtil;
 
 
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
 
 
[email protected]
 public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
 public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
-    private final SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
-    private CharSequence date;
+	private static final ThreadLocal<DateFormat> FORMAT = new ThreadLocal<DateFormat>() {
+        @Override
+        protected DateFormat initialValue() {
+            return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
+        }
+    };
+
 
 
-    private static final ObjectMapper MAPPER = new ObjectMapper();
-    private final ByteBuf buffer = Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8));
-    private final CharSequence contentLength = HttpHeaders.newEntity(String.valueOf(buffer.readableBytes()));
+    private static final ByteBuf CONTENT_BUFFER = Unpooled.unreleasableBuffer(
+            Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8)));
+    private static final CharSequence contentLength = HttpHeaders.newEntity(
+            String.valueOf(CONTENT_BUFFER.readableBytes()));
 
 
     private static final CharSequence TYPE_PLAIN = HttpHeaders.newEntity("text/plain; charset=UTF-8");
     private static final CharSequence TYPE_PLAIN = HttpHeaders.newEntity("text/plain; charset=UTF-8");
     private static final CharSequence TYPE_JSON = HttpHeaders.newEntity("application/json; charset=UTF-8");
     private static final CharSequence TYPE_JSON = HttpHeaders.newEntity("application/json; charset=UTF-8");
-
     private static final CharSequence SERVER_NAME = HttpHeaders.newEntity("Netty");
     private static final CharSequence SERVER_NAME = HttpHeaders.newEntity("Netty");
     private static final CharSequence CONTENT_TYPE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_TYPE);
     private static final CharSequence CONTENT_TYPE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_TYPE);
     private static final CharSequence DATE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.DATE);
     private static final CharSequence DATE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.DATE);
     private static final CharSequence CONTENT_LENGTH_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_LENGTH);
     private static final CharSequence CONTENT_LENGTH_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_LENGTH);
     private static final CharSequence SERVER_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.SERVER);
     private static final CharSequence SERVER_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.SERVER);
+    private static final ObjectMapper MAPPER;
+    
+    static{
+    	MAPPER = new ObjectMapper();
+    	MAPPER.registerModule(new AfterburnerModule());
+    }
+    
+    private volatile CharSequence date = HttpHeaders.newEntity(FORMAT.get().format(new Date()));
+
+    HelloServerHandler(ScheduledExecutorService service) {
+        service.scheduleWithFixedDelay(new Runnable() {
+            private final DateFormat format = FORMAT.get();
+            @Override
+            public void run() {
+                date = HttpHeaders.newEntity(format.format(new Date()));
+            }
+        }, 1000, 1000, TimeUnit.MILLISECONDS);
+
+    }
 
 
     @Override
     @Override
     public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
     public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
@@ -47,10 +72,10 @@ public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
             String uri = request.getUri();
             String uri = request.getUri();
             switch (uri) {
             switch (uri) {
                 case "/plaintext":
                 case "/plaintext":
-                    writeResponse(ctx, request, buffer.duplicate().retain(), TYPE_PLAIN, contentLength);
+                    writeResponse(ctx, request, CONTENT_BUFFER.duplicate(), TYPE_PLAIN, contentLength);
                     return;
                     return;
                 case "/json":
                 case "/json":
-                    byte[] json = MAPPER.writeValueAsBytes(Collections.singletonMap("message", "Hello, World!"));
+                    byte[] json = MAPPER.writeValueAsBytes(new Message("Hello, World!"));
                     writeResponse(ctx, request, Unpooled.wrappedBuffer(json), TYPE_JSON,
                     writeResponse(ctx, request, Unpooled.wrappedBuffer(json), TYPE_JSON,
                             String.valueOf(json.length));
                             String.valueOf(json.length));
                     return;
                     return;
@@ -94,30 +119,4 @@ public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
         ctx.flush();
         ctx.flush();
     }
     }
-
-    @Override
-    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
-        super.handlerRemoved(ctx);
-        buffer.release();
-    }
-
-    @Override
-    public void channelActive(ChannelHandlerContext ctx) throws Exception {
-        date = HttpHeaders.newEntity(format.format(new Date()));
-
-        Channel channel = ctx.channel();
-        final ScheduledFuture<?> future = channel.eventLoop().scheduleWithFixedDelay(new Runnable() {
-            @Override
-            public void run() {
-                date = HttpHeaders.newEntity(format.format(new Date()));
-            }
-        }, 1000, 1000, TimeUnit.MILLISECONDS);
-
-        channel.closeFuture().addListener(new ChannelFutureListener() {
-            @Override
-            public void operationComplete(ChannelFuture channelFuture) throws Exception {
-                future.cancel(false);
-            }
-        });
-    }
 }
 }

+ 8 - 1
netty/src/main/java/hello/HelloServerInitializer.java

@@ -1,17 +1,24 @@
 package hello;
 package hello;
 
 
+import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
 import io.netty.channel.ChannelPipeline;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.handler.codec.http.HttpRequestDecoder;
 import io.netty.handler.codec.http.HttpRequestDecoder;
 import io.netty.handler.codec.http.HttpResponseEncoder;
 import io.netty.handler.codec.http.HttpResponseEncoder;
 
 
+import java.util.concurrent.ScheduledExecutorService;
+
 public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
 public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
+    private final ChannelHandler httpHandler;
+    public HelloServerInitializer(ScheduledExecutorService service) {
+        this.httpHandler = new HelloServerHandler(service);
+    }
     @Override
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
     public void initChannel(SocketChannel ch) throws Exception {
         ChannelPipeline p = ch.pipeline();
         ChannelPipeline p = ch.pipeline();
         p.addLast("encoder", new HttpResponseEncoder());
         p.addLast("encoder", new HttpResponseEncoder());
         p.addLast("decoder", new HttpRequestDecoder(4096, 8192, 8192, false));
         p.addLast("decoder", new HttpRequestDecoder(4096, 8192, 8192, false));
-        p.addLast("handler", new HelloServerHandler());
+        p.addLast("handler", httpHandler);
     }
     }
 }
 }

+ 37 - 16
netty/src/main/java/hello/HelloWebServer.java

@@ -5,14 +5,19 @@ import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.Channel;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.EventLoopGroup;
+import io.netty.channel.ServerChannel;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollServerSocketChannel;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.util.ResourceLeakDetector;
 import io.netty.util.ResourceLeakDetector;
+import io.netty.util.ResourceLeakDetector.Level;
 
 
 
 
 public class HelloWebServer {
 public class HelloWebServer {
+	private static int IO_THREADS = Runtime.getRuntime().availableProcessors() * 2;
     static {
     static {
-        ResourceLeakDetector.setEnabled(false);
+        ResourceLeakDetector.setLevel(Level.DISABLED);
     }
     }
 
 
     private final int port;
     private final int port;
@@ -22,22 +27,38 @@ public class HelloWebServer {
     }
     }
 
 
     public void run() throws Exception {
     public void run() throws Exception {
-        // Configure the server.
-        EventLoopGroup group = new NioEventLoopGroup();
-        try {
-            ServerBootstrap b = new ServerBootstrap();
-            b.group(group)
-             .childHandler(new HelloServerInitializer())
-             .channel(NioServerSocketChannel.class)
-             .option(ChannelOption.SO_BACKLOG, 1024)
-             .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
-             
-            Channel ch = b.bind(port).sync().channel();
-            ch.closeFuture().sync();
-        } finally {
-            group.shutdownGracefully().sync();
-        }
+		// Configure the server.
+
+		String os = System.getProperty("os.name").toLowerCase();
+
+		boolean is_linux = os.contains("linux");
+		
+		if (is_linux) {
+			doRun( new EpollEventLoopGroup(), EpollServerSocketChannel.class);
+		}
+		else {
+			doRun(new NioEventLoopGroup(), NioServerSocketChannel.class);
+		} 
     }
     }
+    
+	private void doRun(EventLoopGroup loupGroup, Class<? extends ServerChannel> serverChannelClass) throws InterruptedException	{
+		try {
+			ServerBootstrap b = new ServerBootstrap();
+			b.option(ChannelOption.SO_BACKLOG, 1024);
+			b.option(ChannelOption.SO_REUSEADDR, true);
+			b.group(loupGroup).channel(serverChannelClass).childHandler(new HelloServerInitializer(loupGroup.next()));			
+            b.option(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
+            b.childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(true, IO_THREADS, IO_THREADS, 8192, 11));
+            b.childOption(ChannelOption.SO_REUSEADDR, true);
+            b.childOption(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
+
+			Channel ch = b.bind(port).sync().channel();
+			ch.closeFuture().sync();
+		}
+		finally {
+			loupGroup.shutdownGracefully().sync();
+		}
+	}
 
 
     public static void main(String[] args) throws Exception {
     public static void main(String[] args) throws Exception {
         int port;
         int port;

+ 15 - 0
netty/src/main/java/hello/Message.java

@@ -0,0 +1,15 @@
+package hello;
+
+public class Message {
+	
+	private final String message;
+
+	public Message(String message) {
+		super();
+		this.message = message;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+}