1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.protobuf;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.Unpooled;
20 import io.netty.handler.codec.CorruptedFrameException;
21 import io.netty.microbench.util.AbstractMicrobenchmark;
22 import org.openjdk.jmh.annotations.Benchmark;
23 import org.openjdk.jmh.annotations.BenchmarkMode;
24 import org.openjdk.jmh.annotations.Fork;
25 import org.openjdk.jmh.annotations.Measurement;
26 import org.openjdk.jmh.annotations.OutputTimeUnit;
27 import org.openjdk.jmh.annotations.Param;
28 import org.openjdk.jmh.annotations.Scope;
29 import org.openjdk.jmh.annotations.Setup;
30 import org.openjdk.jmh.annotations.State;
31 import org.openjdk.jmh.annotations.Warmup;
32
33 import java.util.Random;
34 import java.util.concurrent.TimeUnit;
35
36 @State(Scope.Benchmark)
37 @OutputTimeUnit(TimeUnit.NANOSECONDS)
38 @BenchmarkMode(org.openjdk.jmh.annotations.Mode.AverageTime)
39 @Fork(2)
40 @Warmup(iterations = 10, time = 400, timeUnit = java.util.concurrent.TimeUnit.MILLISECONDS)
41 @Measurement(iterations = 5, time = 400, timeUnit = java.util.concurrent.TimeUnit.MILLISECONDS)
42 public class VarintDecodingBenchmark extends AbstractMicrobenchmark {
43
44 private static final int SEED = 0;
45
46
47 @Param({ "1", "128", "128000" })
48 int inputs;
49
50 public enum InputDistribution {
51 SMALL,
52 LARGE,
53 MEDIUM,
54 ALL
55 }
56
57 @Param
58 InputDistribution inputDistribution;
59 ByteBuf[] data;
60 int index;
61
62 @Setup
63 public void init() {
64 ByteBuf[] dataSet;
65 switch (inputDistribution) {
66 case SMALL:
67 dataSet = new ByteBuf[] {
68 generateData(1, 1),
69 generateData(2, 2),
70 generateData(3, 3)
71 };
72 break;
73 case LARGE:
74 dataSet = new ByteBuf[] {
75 generateData(5, 5)
76 };
77 if (inputs > 1) {
78 System.exit(1);
79 }
80 break;
81 case MEDIUM:
82 dataSet = new ByteBuf[] {
83 generateData(1, 5),
84 generateData(2, 5),
85 generateData(3, 5),
86 generateData(4, 5)
87 };
88 break;
89 case ALL:
90 dataSet = new ByteBuf[] {
91 generateData(1, 1),
92 generateData(2, 2),
93 generateData(3, 3),
94 generateData(1, 5),
95 generateData(2, 5),
96 generateData(3, 5),
97 generateData(4, 5),
98 generateData(5, 5)
99 };
100 break;
101 default:
102 throw new RuntimeException("Unknown distribution");
103 }
104 data = new ByteBuf[inputs];
105 Random rnd = new Random(SEED);
106 for (int i = 0; i < inputs; i++) {
107 data[i] = dataSet[rnd.nextInt(dataSet.length)];
108 }
109 index = 0;
110 }
111
112 public static ByteBuf generateData(int varintLength, int capacity) {
113 byte[] bytes = new byte[capacity];
114 for (int i = 0; i < (varintLength - 1); i++) {
115 bytes[i] = (byte) 150;
116 }
117
118 bytes[varintLength - 1] = (byte) 1;
119 return Unpooled.wrappedBuffer(bytes);
120 }
121
122 public ByteBuf nextData() {
123 index++;
124 if (index == data.length) {
125 index = 0;
126 }
127 return data[index].resetReaderIndex();
128 }
129
130 @Benchmark
131 public int oldReadRawVarint32() {
132 return oldReadRawVarint32(nextData());
133 }
134
135 @Benchmark
136 public int readRawVarint32() {
137 return ProtobufVarint32FrameDecoder.readRawVarint32(nextData());
138 }
139
140
141
142
143
144
145 private static int oldReadRawVarint32(ByteBuf buffer) {
146 if (!buffer.isReadable()) {
147 return 0;
148 }
149 buffer.markReaderIndex();
150
151 byte tmp = buffer.readByte();
152 if (tmp >= 0) {
153 return tmp;
154 } else {
155 int result = tmp & 127;
156 if (!buffer.isReadable()) {
157 buffer.resetReaderIndex();
158 return 0;
159 }
160 if ((tmp = buffer.readByte()) >= 0) {
161 result |= tmp << 7;
162 } else {
163 result |= (tmp & 127) << 7;
164 if (!buffer.isReadable()) {
165 buffer.resetReaderIndex();
166 return 0;
167 }
168 if ((tmp = buffer.readByte()) >= 0) {
169 result |= tmp << 14;
170 } else {
171 result |= (tmp & 127) << 14;
172 if (!buffer.isReadable()) {
173 buffer.resetReaderIndex();
174 return 0;
175 }
176 if ((tmp = buffer.readByte()) >= 0) {
177 result |= tmp << 21;
178 } else {
179 result |= (tmp & 127) << 21;
180 if (!buffer.isReadable()) {
181 buffer.resetReaderIndex();
182 return 0;
183 }
184 result |= (tmp = buffer.readByte()) << 28;
185 if (tmp < 0) {
186 throw new CorruptedFrameException("malformed varint.");
187 }
188 }
189 }
190 }
191 return result;
192 }
193 }
194
195 }