Use ByteBuf#writeShort/writeMedium instead of writeBytes

Motivation:

1. Some encoders used a `ByteBuf#writeBytes` to write short constant byte array (2-3 bytes). This can be replaced with more faster `ByteBuf#writeShort` or `ByteBuf#writeMedium` which do not access the memory.
2. Two chained calls of the `ByteBuf#setByte` with constants can be replaced with one `ByteBuf#setShort` to reduce index checks.
3. The signature of method `HttpHeadersEncoder#encoderHeader` has an unnecessary `throws`.

Modifications:

1. Use `ByteBuf#writeShort` or `ByteBuf#writeMedium` instead of `ByteBuf#writeBytes` for the constants.
2. Use `ByteBuf#setShort` instead of chained call of the `ByteBuf#setByte` with constants.
3. Remove an unnecessary `throws` from `HttpHeadersEncoder#encoderHeader`.

Result:

A bit faster writes constants into buffers.
This commit is contained in:
Nikolay Fedorovskikh 2017-07-04 01:57:07 +05:00 committed by Norman Maurer
parent 83db2b07b4
commit df568c739e
11 changed files with 280 additions and 100 deletions

View File

@ -387,6 +387,30 @@ public final class ByteBufUtil {
return Long.reverseBytes(value);
}
/**
* Writes a big-endian 16-bit short integer to the buffer.
*/
@SuppressWarnings("deprecation")
public static ByteBuf writeShortBE(ByteBuf buf, int shortValue) {
return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeShort(shortValue) : buf.writeShortLE(shortValue);
}
/**
* Sets a big-endian 16-bit short integer to the buffer.
*/
@SuppressWarnings("deprecation")
public static ByteBuf setShortBE(ByteBuf buf, int index, int shortValue) {
return buf.order() == ByteOrder.BIG_ENDIAN? buf.setShort(index, shortValue) : buf.setShortLE(index, shortValue);
}
/**
* Writes a big-endian 24-bit medium integer to the buffer.
*/
@SuppressWarnings("deprecation")
public static ByteBuf writeMediumBE(ByteBuf buf, int mediumValue) {
return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeMedium(mediumValue) : buf.writeMediumLE(mediumValue);
}
/**
* Read the given amount of bytes into a new {@link ByteBuf} that is allocated from the {@link ByteBufAllocator}.
*/

View File

@ -19,6 +19,7 @@ import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import org.junit.Test;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Random;
@ -129,6 +130,66 @@ public class ByteBufUtilTest {
-1));
}
@SuppressWarnings("deprecation")
@Test
public void writeShortBE() {
int expected = 0x1234;
ByteBuf buf = Unpooled.buffer(2).order(ByteOrder.BIG_ENDIAN);
ByteBufUtil.writeShortBE(buf, expected);
assertEquals(expected, buf.readShort());
buf.resetReaderIndex();
assertEquals(ByteBufUtil.swapShort((short) expected), buf.readShortLE());
buf.release();
buf = Unpooled.buffer(2).order(ByteOrder.LITTLE_ENDIAN);
ByteBufUtil.writeShortBE(buf, expected);
assertEquals((short) expected, buf.readShortLE());
buf.resetReaderIndex();
assertEquals(ByteBufUtil.swapShort((short) expected), buf.readShort());
buf.release();
}
@SuppressWarnings("deprecation")
@Test
public void setShortBE() {
int shortValue = 0x1234;
ByteBuf buf = Unpooled.wrappedBuffer(new byte[2]).order(ByteOrder.BIG_ENDIAN);
ByteBufUtil.setShortBE(buf, 0, shortValue);
assertEquals(shortValue, buf.readShort());
buf.resetReaderIndex();
assertEquals(ByteBufUtil.swapShort((short) shortValue), buf.readShortLE());
buf.release();
buf = Unpooled.wrappedBuffer(new byte[2]).order(ByteOrder.LITTLE_ENDIAN);
ByteBufUtil.setShortBE(buf, 0, shortValue);
assertEquals((short) shortValue, buf.readShortLE());
buf.resetReaderIndex();
assertEquals(ByteBufUtil.swapShort((short) shortValue), buf.readShort());
buf.release();
}
@SuppressWarnings("deprecation")
@Test
public void writeMediumBE() {
int mediumValue = 0x123456;
ByteBuf buf = Unpooled.buffer(4).order(ByteOrder.BIG_ENDIAN);
ByteBufUtil.writeMediumBE(buf, mediumValue);
assertEquals(mediumValue, buf.readMedium());
buf.resetReaderIndex();
assertEquals(ByteBufUtil.swapMedium(mediumValue), buf.readMediumLE());
buf.release();
buf = Unpooled.buffer(4).order(ByteOrder.LITTLE_ENDIAN);
ByteBufUtil.writeMediumBE(buf, mediumValue);
assertEquals(mediumValue, buf.readMediumLE());
buf.resetReaderIndex();
assertEquals(ByteBufUtil.swapMedium(mediumValue), buf.readMedium());
buf.release();
}
@Test
public void testWriteUsAscii() {
String usAscii = "NettyRocks";

View File

@ -21,12 +21,16 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpConstants.*;
import static io.netty.handler.codec.http.HttpObjectEncoder.CRLF_SHORT;
final class HttpHeadersEncoder {
private static final int COLON_AND_SPACE_SHORT = (COLON << 8) | SP;
private HttpHeadersEncoder() {
}
static void encoderHeader(CharSequence name, CharSequence value, ByteBuf buf) throws Exception {
static void encoderHeader(CharSequence name, CharSequence value, ByteBuf buf) {
final int nameLen = name.length();
final int valueLen = value.length();
final int entryLen = nameLen + valueLen + 4;
@ -34,12 +38,12 @@ final class HttpHeadersEncoder {
int offset = buf.writerIndex();
writeAscii(buf, offset, name);
offset += nameLen;
buf.setByte(offset ++, ':');
buf.setByte(offset ++, ' ');
ByteBufUtil.setShortBE(buf, offset, COLON_AND_SPACE_SHORT);
offset += 2;
writeAscii(buf, offset, value);
offset += valueLen;
buf.setByte(offset ++, '\r');
buf.setByte(offset ++, '\n');
ByteBufUtil.setShortBE(buf, offset, CRLF_SHORT);
offset += 2;
buf.writerIndex(offset);
}

View File

@ -16,11 +16,11 @@
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.FileRegion;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import java.util.Iterator;
@ -47,10 +47,10 @@ import static io.netty.handler.codec.http.HttpConstants.LF;
* implement all abstract methods properly.
*/
public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageToMessageEncoder<Object> {
static final byte[] CRLF = { CR, LF };
private static final byte[] ZERO_CRLF = { '0', CR, LF };
static final int CRLF_SHORT = (CR << 8) | LF;
private static final int ZERO_CRLF_MEDIUM = ('0' << 16) | CRLF_SHORT;
private static final byte[] ZERO_CRLF_CRLF = { '0', CR, LF, CR, LF };
private static final ByteBuf CRLF_BUF = unreleasableBuffer(directBuffer(CRLF.length).writeBytes(CRLF));
private static final ByteBuf CRLF_BUF = unreleasableBuffer(directBuffer(2).writeByte(CR).writeByte(LF));
private static final ByteBuf ZERO_CRLF_CRLF_BUF = unreleasableBuffer(directBuffer(ZERO_CRLF_CRLF.length)
.writeBytes(ZERO_CRLF_CRLF));
@ -77,7 +77,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
// Encode the message.
encodeInitialLine(buf, m);
encodeHeaders(m.headers(), buf);
buf.writeBytes(CRLF);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
state = isContentAlwaysEmpty(m) ? ST_CONTENT_ALWAYS_EMPTY :
HttpUtil.isTransferEncodingChunked(m) ? ST_CONTENT_CHUNK : ST_CONTENT_NON_CHUNK;
}
@ -153,7 +153,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
/**
* Encode the {@link HttpHeaders} into a {@link ByteBuf}.
*/
protected void encodeHeaders(HttpHeaders headers, ByteBuf buf) throws Exception {
protected void encodeHeaders(HttpHeaders headers, ByteBuf buf) {
Iterator<Entry<CharSequence, CharSequence>> iter = headers.iteratorCharSequence();
while (iter.hasNext()) {
Entry<CharSequence, CharSequence> header = iter.next();
@ -166,7 +166,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
String lengthHex = Long.toHexString(contentLength);
ByteBuf buf = ctx.alloc().buffer(lengthHex.length() + 2);
buf.writeCharSequence(lengthHex, CharsetUtil.US_ASCII);
buf.writeBytes(CRLF);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
out.add(buf);
out.add(encodeAndRetain(msg));
out.add(CRLF_BUF.duplicate());
@ -178,19 +178,14 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
out.add(ZERO_CRLF_CRLF_BUF.duplicate());
} else {
ByteBuf buf = ctx.alloc().buffer();
buf.writeBytes(ZERO_CRLF);
try {
encodeHeaders(headers, buf);
} catch (Exception ex) {
buf.release();
PlatformDependent.throwException(ex);
}
buf.writeBytes(CRLF);
ByteBufUtil.writeMediumBE(buf, ZERO_CRLF_MEDIUM);
encodeHeaders(headers, buf);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
out.add(buf);
}
} else if (contentLength == 0) {
// Need to produce some output otherwise an
// IllegalstateException will be thrown
// IllegalStateException will be thrown
out.add(EMPTY_BUFFER);
}
}

View File

@ -28,6 +28,8 @@ import static io.netty.handler.codec.http.HttpConstants.SP;
public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
private static final char SLASH = '/';
private static final char QUESTION_MARK = '?';
private static final int SLASH_AND_SPACE_SHORT = (SLASH << 8) | SP;
private static final int SPACE_SLASH_AND_SPACE_MEDIUM = (SP << 16) | SLASH_AND_SPACE_SHORT;
@Override
public boolean acceptOutboundMessage(Object msg) throws Exception {
@ -37,37 +39,42 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
ByteBufUtil.copy(request.method().asciiName(), buf);
buf.writeByte(SP);
// Add / as absolute path if no is present.
// See http://tools.ietf.org/html/rfc2616#section-5.1.2
String uri = request.uri();
if (uri.isEmpty()) {
uri += SLASH;
// Add " / " as absolute path if uri is not present.
// See http://tools.ietf.org/html/rfc2616#section-5.1.2
ByteBufUtil.writeMediumBE(buf, SPACE_SLASH_AND_SPACE_MEDIUM);
} else {
CharSequence uriCharSequence = uri;
boolean needSlash = false;
int start = uri.indexOf("://");
if (start != -1 && uri.charAt(0) != SLASH) {
int startIndex = start + 3;
start += 3;
// Correctly handle query params.
// See https://github.com/netty/netty/issues/2732
int index = uri.indexOf(QUESTION_MARK, startIndex);
int index = uri.indexOf(QUESTION_MARK, start);
if (index == -1) {
if (uri.lastIndexOf(SLASH) <= startIndex) {
uri += SLASH;
if (uri.lastIndexOf(SLASH) <= start) {
needSlash = true;
}
} else {
if (uri.lastIndexOf(SLASH, index) <= startIndex) {
uri = new StringBuilder(uri).insert(index, SLASH).toString();
if (uri.lastIndexOf(SLASH, index) <= start) {
uriCharSequence = new StringBuilder(uri).insert(index, SLASH);
}
}
}
buf.writeByte(SP).writeCharSequence(uriCharSequence, CharsetUtil.UTF_8);
if (needSlash) {
// write "/ " after uri
ByteBufUtil.writeShortBE(buf, SLASH_AND_SPACE_SHORT);
} else {
buf.writeByte(SP);
}
}
buf.writeCharSequence(uri, CharsetUtil.UTF_8);
buf.writeByte(SP);
request.protocolVersion().encode(buf);
buf.writeBytes(CRLF);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
}
}

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import static io.netty.handler.codec.http.HttpConstants.*;
@ -35,6 +36,6 @@ public class HttpResponseEncoder extends HttpObjectEncoder<HttpResponse> {
response.protocolVersion().encode(buf);
buf.writeByte(SP);
response.status().encode(buf);
buf.writeBytes(CRLF);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
}
}

View File

@ -15,9 +15,6 @@
*/
package io.netty.handler.codec.rtsp;
import static io.netty.handler.codec.http.HttpConstants.CR;
import static io.netty.handler.codec.http.HttpConstants.LF;
import static io.netty.handler.codec.http.HttpConstants.SP;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.handler.codec.UnsupportedMessageTypeException;
@ -29,15 +26,14 @@ import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.StringUtil;
import static io.netty.handler.codec.http.HttpConstants.*;
/**
* Encodes an RTSP message represented in {@link HttpMessage} or an {@link HttpContent} into
* a {@link ByteBuf}.
*/
public class RtspEncoder extends HttpObjectEncoder<HttpMessage> {
/**
* Constant for CRLF.
*/
private static final byte[] CRLF = {CR, LF};
private static final int CRLF_SHORT = (CR << 8) | LF;
@Override
public boolean acceptOutboundMessage(final Object msg)
@ -55,7 +51,7 @@ public class RtspEncoder extends HttpObjectEncoder<HttpMessage> {
buf.writeCharSequence(request.uri(), CharsetUtil.UTF_8);
buf.writeByte(SP);
buf.writeCharSequence(request.protocolVersion().toString(), CharsetUtil.US_ASCII);
buf.writeBytes(CRLF);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
} else if (message instanceof HttpResponse) {
HttpResponse response = (HttpResponse) message;
buf.writeCharSequence(response.protocolVersion().toString(), CharsetUtil.US_ASCII);
@ -63,7 +59,7 @@ public class RtspEncoder extends HttpObjectEncoder<HttpMessage> {
ByteBufUtil.copy(response.status().codeAsText(), buf);
buf.writeByte(SP);
buf.writeCharSequence(response.status().reasonPhrase(), CharsetUtil.US_ASCII);
buf.writeBytes(CRLF);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
} else {
throw new UnsupportedMessageTypeException("Unsupported type "
+ StringUtil.simpleClassName(message));

View File

@ -19,6 +19,8 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import static org.junit.Assert.*;
@ -27,80 +29,97 @@ import static org.junit.Assert.*;
*/
public class HttpRequestEncoderTest {
@SuppressWarnings("deprecation")
private static ByteBuf[] getBuffers() {
return new ByteBuf[]{
Unpooled.buffer(128).order(ByteOrder.BIG_ENDIAN),
Unpooled.buffer(128).order(ByteOrder.LITTLE_ENDIAN),
Unpooled.wrappedBuffer(ByteBuffer.allocate(128).order(ByteOrder.BIG_ENDIAN)).resetWriterIndex(),
Unpooled.wrappedBuffer(ByteBuffer.allocate(128).order(ByteOrder.LITTLE_ENDIAN)).resetWriterIndex()
};
}
@Test
public void testUriWithoutPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
buffer.release();
for (ByteBuf buffer : getBuffers()) {
HttpRequestEncoder encoder = new HttpRequestEncoder();
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
buffer.release();
}
}
@Test
public void testUriWithoutPath2() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
"http://localhost:9999?p1=v1"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
buffer.release();
for (ByteBuf buffer : getBuffers()) {
HttpRequestEncoder encoder = new HttpRequestEncoder();
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
"http://localhost:9999?p1=v1"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
buffer.release();
}
}
@Test
public void testUriWithEmptyPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
"http://localhost:9999/?p1=v1"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
buffer.release();
for (ByteBuf buffer : getBuffers()) {
HttpRequestEncoder encoder = new HttpRequestEncoder();
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
"http://localhost:9999/?p1=v1"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost:9999/?p1=v1 HTTP/1.1\r\n", req);
buffer.release();
}
}
@Test
public void testUriWithPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost/"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
buffer.release();
for (ByteBuf buffer : getBuffers()) {
HttpRequestEncoder encoder = new HttpRequestEncoder();
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost/"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
buffer.release();
}
}
@Test
public void testAbsPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "/"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET / HTTP/1.1\r\n", req);
buffer.release();
for (ByteBuf buffer : getBuffers()) {
HttpRequestEncoder encoder = new HttpRequestEncoder();
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "/"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET / HTTP/1.1\r\n", req);
buffer.release();
}
}
@Test
public void testEmptyAbsPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, ""));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET / HTTP/1.1\r\n", req);
buffer.release();
for (ByteBuf buffer : getBuffers()) {
HttpRequestEncoder encoder = new HttpRequestEncoder();
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, ""));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET / HTTP/1.1\r\n", req);
buffer.release();
}
}
@Test
public void testQueryStringPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "/?url=http://example.com"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET /?url=http://example.com HTTP/1.1\r\n", req);
buffer.release();
for (ByteBuf buffer : getBuffers()) {
HttpRequestEncoder encoder = new HttpRequestEncoder();
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "/?url=http://example.com"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET /?url=http://example.com HTTP/1.1\r\n", req);
buffer.release();
}
}
}

View File

@ -31,11 +31,10 @@ import java.util.RandomAccess;
*/
@UnstableApi
public final class SmtpRequestEncoder extends MessageToMessageEncoder<Object> {
private static final byte[] CRLF = {'\r', '\n'};
private static final byte[] DOT_CRLF = {'.', '\r', '\n'};
private static final int CRLF_SHORT = ('\r' << 8) | '\n';
private static final byte SP = ' ';
private static final ByteBuf DOT_CRLF_BUFFER = Unpooled.unreleasableBuffer(
Unpooled.directBuffer(3).writeBytes(DOT_CRLF));
Unpooled.directBuffer(3).writeByte('.').writeByte('\r').writeByte('\n'));
private boolean contentExpected;
@ -60,7 +59,7 @@ public final class SmtpRequestEncoder extends MessageToMessageEncoder<Object> {
try {
req.command().encode(buffer);
writeParameters(req.parameters(), buffer);
buffer.writeBytes(CRLF);
ByteBufUtil.writeShortBE(buffer, CRLF_SHORT);
out.add(buffer);
release = false;
if (req.command().isContentExpected()) {

View File

@ -27,7 +27,7 @@ import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import static io.netty.handler.codec.http.HttpConstants.SP;
import static io.netty.handler.codec.http.HttpConstants.*;
@State(Scope.Benchmark)
@Warmup(iterations = 10)
@ -62,7 +62,8 @@ public class HttpRequestEncoderInsertBenchmark extends AbstractMicrobenchmark {
}
}
private class OldHttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
private static class OldHttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
private static final byte[] CRLF = {CR, LF};
private static final char SLASH = '/';
private static final char QUESTION_MARK = '?';

View File

@ -0,0 +1,73 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.microbench.util.AbstractMicrobenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import java.util.concurrent.TimeUnit;
import static io.netty.handler.codec.http.HttpConstants.*;
@Threads(1)
@Warmup(iterations = 3)
@Measurement(iterations = 3)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class WriteBytesVsShortOrMediumBenchmark extends AbstractMicrobenchmark {
private static final int CRLF_SHORT = (CR << 8) + LF;
private static final byte[] CRLF = { CR, LF };
private static final int ZERO_CRLF_MEDIUM = ('0' << 16) + (CR << 8) + LF;
private static final byte[] ZERO_CRLF = { '0', CR, LF };
private final ByteBuf buf = Unpooled.directBuffer(16);
@Benchmark
public ByteBuf shortInt() {
return ByteBufUtil.writeShortBE(buf, CRLF_SHORT).resetWriterIndex();
}
@Benchmark
public ByteBuf mediumInt() {
return ByteBufUtil.writeMediumBE(buf, ZERO_CRLF_MEDIUM).resetWriterIndex();
}
@Benchmark
public ByteBuf byteArray2() {
return buf.writeBytes(CRLF).resetWriterIndex();
}
@Benchmark
public ByteBuf byteArray3() {
return buf.writeBytes(ZERO_CRLF).resetWriterIndex();
}
@Benchmark
public ByteBuf chainedBytes2() {
return buf.writeByte(CR).writeByte(LF).resetWriterIndex();
}
@Benchmark
public ByteBuf chainedBytes3() {
return buf.writeByte('0').writeByte(CR).writeByte(LF).resetWriterIndex();
}
}