From 7a5f4721b9f6e5c9e9194167955d767c4e8655f4 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sat, 12 May 2012 08:31:13 +0900 Subject: [PATCH] Optimize LoggingHandler using lookup tables --- .../netty/handler/logging/LoggingHandler.java | 129 +++++++++++++----- 1 file changed, 93 insertions(+), 36 deletions(-) diff --git a/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java b/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java index 53833d4a11..f8ffa7a0b4 100644 --- a/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java +++ b/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java @@ -45,6 +45,64 @@ public class LoggingHandler extends ChannelHandlerAdapter { private static final InternalLogLevel DEFAULT_LEVEL = InternalLogLevel.DEBUG; private static final String NEWLINE = String.format("%n"); + private static final String[] BYTE2HEX = new String[256]; + private static final String[] HEXPADDING = new String[16]; + private static final String[] BYTEPADDING = new String[16]; + private static final char[] BYTE2CHAR = new char[256]; + + static { + int i; + + // Generate the lookup table for byte-to-hex-dump conversion + for (i = 0; i < 10; i ++) { + StringBuilder buf = new StringBuilder(3); + buf.append(" 0"); + buf.append(i); + BYTE2HEX[i] = buf.toString(); + } + for (;i < 16; i ++) { + StringBuilder buf = new StringBuilder(3); + buf.append(" 0"); + buf.append((char) ('a' + i - 10)); + BYTE2HEX[i] = buf.toString(); + } + for (; i < BYTE2HEX.length; i ++) { + StringBuilder buf = new StringBuilder(3); + buf.append(' '); + buf.append(Integer.toHexString(i)); + BYTE2HEX[i] = buf.toString(); + } + + // Generate the lookup table for hex dump paddings + for (i = 0; i < HEXPADDING.length; i ++) { + int padding = HEXPADDING.length - i; + StringBuilder buf = new StringBuilder(padding * 3); + for (int j = 0; j < padding; j ++) { + buf.append(" "); + } + HEXPADDING[i] = buf.toString(); + } + + // Generate the lookup table for byte dump paddings + for (i = 0; i < BYTEPADDING.length; i ++) { + int padding = BYTEPADDING.length - i; + StringBuilder buf = new StringBuilder(padding); + for (int j = 0; j < padding; j ++) { + buf.append(' '); + } + BYTEPADDING[i] = buf.toString(); + } + + // Generate the lookup table for byte-to-char conversion + for (i = 0; i < BYTE2CHAR.length; i ++) { + if (i <= 0x1f || i >= 0x7f) { + BYTE2CHAR[i] = '.'; + } else { + BYTE2CHAR[i] = (char) i; + } + } + } + private final InternalLogger logger; private final InternalLogLevel level; @@ -172,66 +230,65 @@ public class LoggingHandler extends ChannelHandlerAdapter { elemType = "Object"; } - return String.format("%s[%s](%d): %s", bufName, elemType, size, content); + StringBuilder buf = new StringBuilder(bufName.length() + elemType.length() + content.length() + 16); + buf.append(bufName); + buf.append('['); + buf.append(elemType); + buf.append("]("); + buf.append(size); + buf.append("): "); + buf.append(content); + return buf.toString(); } private static String hexdump(ChannelBuffer buf) { - // TODO: Optimize using lookup tables int length = buf.readableBytes(); int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4; StringBuilder dump = new StringBuilder(rows * 80); - dump.append(NEWLINE); - dump.append(" +-------------------------------------------------+"); - dump.append(NEWLINE); - dump.append(" | 0 1 2 3 4 5 6 7 8 9 a b c d e f |"); - dump.append(NEWLINE); - dump.append("+--------+-------------------------------------------------+----------------+"); + dump.append( + NEWLINE + " +-------------------------------------------------+" + + NEWLINE + " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |" + + NEWLINE + "+--------+-------------------------------------------------+----------------+"); + + final int startIndex = buf.readerIndex(); + final int endIndex = buf.writerIndex(); int i; - for (i = buf.readerIndex(); i < buf.writerIndex(); i ++) { - int relIdx = i - buf.readerIndex(); + for (i = startIndex; i < endIndex; i ++) { + int relIdx = i - startIndex; int relIdxMod16 = relIdx & 15; if (relIdxMod16 == 0) { dump.append(NEWLINE); - dump.append(String.format("|%8x|", relIdx)); + dump.append(Long.toHexString(relIdx & 0xFFFFFFFFL | 0x100000000L)); + dump.setCharAt(dump.length() - 9, '|'); + dump.append('|'); } - dump.append(String.format(" %02x", buf.getUnsignedByte(i))); + dump.append(BYTE2HEX[buf.getUnsignedByte(i)]); if (relIdxMod16 == 15) { dump.append(" |"); for (int j = i - 15; j <= i; j ++) { - dump.append(toChar(buf.getByte(j))); + dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]); } dump.append('|'); } } - if ((i - buf.readerIndex() & 15) != 0) { + + if ((i - startIndex & 15) != 0) { int remainder = length & 15; - for (int j = 16 - remainder; j > 0; j --) { - dump.append(" "); - } + dump.append(HEXPADDING[remainder]); dump.append(" |"); for (int j = i - remainder; j < i; j ++) { - dump.append(toChar(buf.getByte(j))); - } - for (int j = 16 - remainder; j > 0; j --) { - dump.append(' '); + dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]); } + dump.append(BYTEPADDING[remainder]); dump.append('|'); } - dump.append(NEWLINE); - dump.append("+--------+-------------------------------------------------+----------------+"); - return dump.toString(); - } + dump.append( + NEWLINE + "+--------+-------------------------------------------------+----------------+"); - private static char toChar(int ch) { - ch = ch & 0xff; - if (ch <= 0x1f || ch >= 0x7f) { - return '.'; - } else { - return (char) ch; - } + return dump.toString(); } @Override @@ -286,7 +343,7 @@ public class LoggingHandler extends ChannelHandlerAdapter { public void exceptionCaught(ChannelInboundHandlerContext ctx, Throwable cause) throws Exception { if (getLogger().isEnabled(level)) { - logger.log(level, format(ctx, String.format("EXCEPTION: %s", cause)), cause); + logger.log(level, format(ctx, "EXCEPTION: " + cause), cause); } super.exceptionCaught(ctx, cause); } @@ -295,7 +352,7 @@ public class LoggingHandler extends ChannelHandlerAdapter { public void userEventTriggered(ChannelInboundHandlerContext ctx, Object evt) throws Exception { if (getLogger().isEnabled(level)) { - logger.log(level, format(ctx, String.format("USER_EVENT: %s", evt))); + logger.log(level, format(ctx, "USER_EVENT: " + evt)); } super.userEventTriggered(ctx, evt); } @@ -313,7 +370,7 @@ public class LoggingHandler extends ChannelHandlerAdapter { public void bind(ChannelOutboundHandlerContext ctx, SocketAddress localAddress, ChannelFuture future) throws Exception { if (getLogger().isEnabled(level)) { - logger.log(level, format(ctx, String.format("BIND(%s)", localAddress))); + logger.log(level, format(ctx, "BIND(" + localAddress + ')')); } super.bind(ctx, localAddress, future); } @@ -323,7 +380,7 @@ public class LoggingHandler extends ChannelHandlerAdapter { SocketAddress remoteAddress, SocketAddress localAddress, ChannelFuture future) throws Exception { if (getLogger().isEnabled(level)) { - logger.log(level, format(ctx, String.format("CONNECT(%s, %s)", remoteAddress, localAddress))); + logger.log(level, format(ctx, "CONNECT(" + remoteAddress + ", " + localAddress + ')')); } super.connect(ctx, remoteAddress, localAddress, future); }