New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding microbenchmarks for encoder/decoder. #24
Conversation
@jpinner I went with the multi-module approach ... just thought it was simpler than profiles with a custom artifact. This code was taken from the work @Scottmitch had done in the Netty Http2FrameWriterBenchmark. |
Early results on my machine:
|
decoder.decode(new ByteArrayInputStream(input), new HeaderListener() { | ||
@Override | ||
public void addHeader(byte[] name, byte[] value, boolean sensitive) { | ||
// Do nothing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this will get optimized away? Perhaps we should do something in here...BlackHole
or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@nmittler - Not sure if you saw netty/netty#3503 (comment) but that describes some stuff that may be limiting with what I had in Netty. Looks like you already are exercising the |
@Scottmitch good point. In particular your points 1 and 2 might be worth exploring in these benchmarks. @buchgr in your benchmarking for grpc have you put any thought into "representational" header name/values? |
@nmittler I collected some grpc headers for my headers benchmarks https://github.com/netty/netty/pull/3681/files#diff-ca4f23f3c28ec164487afb498dc26e5dR37 other than that I don't have any, but if you collect a few headers I am interested to also include them in the Netty PR :-). |
@nmittler at least in GRPC we are not spending much time in hpack in our load tests (~2%), but then again we also don't use many headers. Before starting to do micro optimizations, I thinkt it would make sense to do some load tests with a small client / server that uses lots of headers and is build on top of Netty's HTTP/2 codec. We could then look at it with a profiler and see what the total optimization potential is and where the time is going. |
Since Encoder only uses huffman if it makes string strictly shorter, Encoder does not use huffman encoding in Decoder benchmark since we have 0-255 value range for each byte and not frequently used byte not in ascii range is very long huffman code. To get more realistic benchmark, perhaps we can limit the random value range into printable ascii? |
When I did some benchmarking I used two sets of random strings -- one across all range of bytes and one limited to ascii characters. |
PTAL, I've added an extra parameter to |
@buchgr I understand that grpc isn't spending a lot of time in hpack, but I still think it's useful to have the benchmarks to get a basic feel for how well it performs overall and so that we have a basis for comparison going forward. |
@nmittler yeah absolutely. I think those benchmarks are great. I guess what I wanted to say is that, before as a next step you and @Scottmitch start spending time on micro optimizations it might make sense to see what the optimization potential is, in order to see if this is high priority or not. My guess would be that, since this stuff runs in production at Twitter it likely performs pretty decent. |
@Scottmitch we use this with the http/2 codec. For decoding there is some copying on decode into a "cumulation" buffer like in most of the netty frame decoders and then we wrap the buffer in a ByteBufInputStream. For encoding we create a ByteBufOutputStream. See: |
@buchgr +1 :) @jpinner thanks for the links! @Scottmitch I've raised netty/netty#3700 to compare Netty against the Twitter encoder/decoder. |
@buchgr @Scottmitch @jpinner any other changes you'd like to see? |
public void addHeader(byte[] name, byte[] value, boolean sensitive) { | ||
bh.consume(name); | ||
bh.consume(value); | ||
bh.consume(sensitive); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nmittler nit: it should be enough to consume just one i.e. the boolean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@nmittler LGTM. |
|
||
private static final Map<HeadersKey, List<Header>> headersMap; | ||
static { | ||
headersMap = new HashMap<HeadersKey, List<Header>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialize size to HeadersSize.values().size()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
OutputStream outputStream = new ByteArrayOutputStream(1048576); | ||
for (int i = 0; i < headers.size(); ++i) { | ||
// If duplicates is set, re-add the same header each time. | ||
Header header = duplicates ? headers.get(0) : headers.get(i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe have 2 loops based upon this condition? We don't need the conditional overhead in each loop iteration to be part of the benchmark, and duplicates
shouldn't be changing in the benchmark.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@nmittler - LGTM! |
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.twitter.hpack.microbench; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason these files don't follow the maven directory hierarchy?
the netty version uses the src/test/java/pacakge-name.../microbench directory structure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jpinner oof, good catch! I've replaced com.twitter.hpack.microbench
with com/twitter/hpack/microbench
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it also need to be moved under src/test like in netty?
On Tue, Apr 28, 2015 at 1:26 PM, Nathan Mittler notifications@github.com
wrote:
In
microbench/main/java/com.twitter.hpack.microbench/AbstractMicrobenchmarkBase.java
#24 (comment):+/*
- * Copyright 2015 Twitter, Inc.
- * Licensed 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 com.twitter.hpack.microbench;@jpinner https://github.com/jpinner oof, good catch! I've replaced
com.twitter.hpack.microbench with com/twitter/hpack/microbench.—
Reply to this email directly or view it on GitHub
https://github.com/twitter/hpack/pull/24/files#r29284441.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, Netty has it under src/main
: https://github.com/netty/netty/tree/master/microbench/src
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so we need to move it under "src" still?
On Tue, Apr 28, 2015 at 1:38 PM, Nathan Mittler notifications@github.com
wrote:
In
microbench/main/java/com.twitter.hpack.microbench/AbstractMicrobenchmarkBase.java
#24 (comment):+/*
- * Copyright 2015 Twitter, Inc.
- * Licensed 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 com.twitter.hpack.microbench;Actually, Netty has it under src/main:
https://github.com/netty/netty/tree/master/microbench/src—
Reply to this email directly or view it on GitHub
https://github.com/twitter/hpack/pull/24/files#r29285752.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah missed that ... done.
@BenchmarkMode(Mode.Throughput) | ||
public void encode(Blackhole bh) throws IOException { | ||
Encoder encoder = new Encoder(maxTableSize); | ||
OutputStream outputStream = new ByteArrayOutputStream(1048576); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nmittler - Is this number significant, or is it just 1 << 20
which is assumed to be big enough? Maybe add a comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous reply.
@Scottmitch @jpinner PTAL |
<parent> | ||
<groupId>com.twitter</groupId> | ||
<artifactId>hpack-parent</artifactId> | ||
<version>0.10.2-SNAPSHOT</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's update this to 0.11.0-SNAPSHOT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@nmittler looks great! just a few nits above -- thanks for getting this all set up! |
/** | ||
* Enum that indicates the size of the headers to be used for the benchmark. | ||
*/ | ||
public enum HeadersSize { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enum is private but all methods are package protected. Should we just make class package protected and methods public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has to be public for use with JMH. I can make the methods public for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Yah just make the methods public too I guess.
@nmittler - LGTM! Just a few cleanup questions. |
@Scottmitch @jpinner committed changes ... anything else? |
Great! thanks for the review, guys! :) |
Fixes #23