1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.buffer;
17
18 import java.nio.ByteBuffer;
19 import java.util.concurrent.TimeUnit;
20
21 import io.netty.util.internal.CleanableDirectBuffer;
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.Mode;
27 import org.openjdk.jmh.annotations.OutputTimeUnit;
28 import org.openjdk.jmh.annotations.Param;
29 import org.openjdk.jmh.annotations.Setup;
30 import org.openjdk.jmh.annotations.TearDown;
31 import org.openjdk.jmh.annotations.Warmup;
32
33 import io.netty.microbench.util.AbstractMicrobenchmark;
34 import io.netty.util.internal.PlatformDependent;
35 import org.openjdk.jmh.infra.Blackhole;
36
37 @Warmup(iterations = 10, time = 1)
38 @Measurement(iterations = 10, time = 1)
39 @Fork(2)
40 @BenchmarkMode(Mode.AverageTime)
41 @OutputTimeUnit(TimeUnit.NANOSECONDS)
42 public class ByteBufAccessBenchmark extends AbstractMicrobenchmark {
43
44 static final class NioFacade extends WrappedByteBuf {
45 private final ByteBuffer byteBuffer;
46 private final CleanableDirectBuffer cleanable;
47
48 NioFacade(CleanableDirectBuffer buffer) {
49 super(Unpooled.EMPTY_BUFFER);
50 byteBuffer = buffer.buffer();
51 cleanable = buffer;
52 }
53 @Override
54 public ByteBuf setLong(int index, long value) {
55 byteBuffer.putLong(index, value);
56 return this;
57 }
58 @Override
59 public long getLong(int index) {
60 return byteBuffer.getLong(index);
61 }
62 @Override
63 public byte readByte() {
64 return byteBuffer.get();
65 }
66 @Override
67 public ByteBuf touch() {
68
69 byteBuffer.position(0);
70 return this;
71 }
72 @Override
73 public boolean release() {
74 cleanable.clean();
75 return true;
76 }
77 }
78
79 public enum ByteBufType {
80 UNSAFE {
81 @Override
82 ByteBuf newBuffer() {
83 return new UnpooledUnsafeDirectByteBuf(
84 UnpooledByteBufAllocator.DEFAULT, 64, 64).setIndex(0, 64);
85 }
86 },
87 DIRECT {
88 @Override
89 ByteBuf newBuffer() {
90 return new UnpooledDirectByteBuf(
91 UnpooledByteBufAllocator.DEFAULT, 64, 64).setIndex(0, 64);
92 }
93 },
94 UNSAFE_SLICE {
95 @Override
96 ByteBuf newBuffer() {
97 return UNSAFE.newBuffer().slice(16, 48);
98 }
99 },
100 UNSAFE_RETAINED_SLICE {
101 @Override
102 ByteBuf newBuffer() {
103 ByteBuf pooledBuffer = PooledByteBufAllocator.DEFAULT.directBuffer(64, 64)
104 .setIndex(0, 64);
105 if (!(pooledBuffer instanceof PooledUnsafeDirectByteBuf)) {
106 throw new IllegalStateException("Expected PooledUnsafeDirectByteBuf");
107 }
108 try {
109 return pooledBuffer.retainedSlice(16, 48);
110 } finally {
111 pooledBuffer.release();
112 }
113 }
114 },
115 HEAP {
116 @Override
117 ByteBuf newBuffer() {
118 if (PlatformDependent.hasUnsafe()) {
119 return new UnpooledUnsafeHeapByteBuf(
120 UnpooledByteBufAllocator.DEFAULT, 64, 64).setIndex(0, 64);
121 } else {
122 return new UnpooledHeapByteBuf(
123 UnpooledByteBufAllocator.DEFAULT, 64, 64).setIndex(0, 64);
124 }
125 }
126 },
127 COMPOSITE {
128 @Override
129 ByteBuf newBuffer() {
130 return Unpooled.wrappedBuffer(UNSAFE.newBuffer(), HEAP.newBuffer());
131 }
132 },
133 NIO {
134 @Override
135 ByteBuf newBuffer() {
136 return new NioFacade(PlatformDependent.allocateDirect(64));
137 }
138 };
139 abstract ByteBuf newBuffer();
140 }
141
142 @Param
143 public ByteBufType bufferType;
144
145 @Param({
146 "true",
147 "false",
148 })
149 public String checkAccessible;
150
151 @Param({
152 "true",
153 "false",
154 })
155 public String checkBounds;
156
157 @Param({
158 "8",
159 })
160 public int batchSize;
161
162 @Setup
163 public void setup() {
164 System.setProperty("io.netty.buffer.checkAccessible", checkAccessible);
165 System.setProperty("io.netty.buffer.checkBounds", checkBounds);
166 buffer = bufferType.newBuffer();
167 }
168
169 private ByteBuf buffer;
170 private byte byteToWrite;
171 private int intToWrite;
172 private long longToWrite;
173 private short shortToWrite;
174
175 @TearDown
176 public void tearDown() {
177 buffer.release();
178 System.clearProperty("io.netty.buffer.checkAccessible");
179 System.clearProperty("io.netty.buffer.checkBounds");
180 }
181
182 @Benchmark
183 public long setGetLong() {
184 return buffer.setLong(0, 1).getLong(0);
185 }
186
187 @Benchmark
188 public ByteBuf setLong() {
189 return buffer.setLong(0, 1);
190 }
191
192 @Benchmark
193 public int readBatch() {
194 buffer.readerIndex(0);
195 int result = 0;
196
197
198
199
200
201
202
203
204 for (int i = 0, size = batchSize; i < size; i++) {
205 result += buffer.readByte();
206 }
207 return result;
208 }
209
210 @Benchmark
211 public void getByteBatch(Blackhole bh) {
212 ByteBuf buffer = this.buffer;
213 for (int i = 0, size = batchSize; i < size; i++) {
214 bh.consume(buffer.getByte(i));
215 }
216 }
217 @Benchmark
218 public void setByteBatch(Blackhole bh) {
219 ByteBuf buffer = this.buffer;
220 byte byteToWrite = this.byteToWrite;
221 buffer.resetWriterIndex();
222 for (int i = 0, size = batchSize; i < size; i++) {
223 bh.consume(buffer.setByte(i, byteToWrite));
224 }
225 }
226
227 @Benchmark
228 public void readByteBatch(Blackhole bh) {
229 ByteBuf buffer = this.buffer;
230 buffer.readerIndex(0);
231 for (int i = 0, size = batchSize; i < size; i++) {
232 bh.consume(buffer.readByte());
233 }
234 }
235
236 @Benchmark
237 public void setBytes(Blackhole bh) {
238 ByteBuf buffer = this.buffer;
239 byte byteToWrite = this.byteToWrite;
240 int intToWrite = this.intToWrite;
241 long longToWrite = this.longToWrite;
242 short shortToWrite = this.shortToWrite;
243 buffer.resetWriterIndex();
244 int index = buffer.writerIndex();
245 bh.consume(buffer.setByte(index, byteToWrite));
246 index += 1;
247 bh.consume(buffer.setShortLE(index, shortToWrite));
248 index += 2;
249 bh.consume(buffer.setIntLE(index, intToWrite));
250 index += 4;
251 bh.consume(buffer.setLongLE(index, longToWrite));
252 }
253
254 @Benchmark
255 public void getBytes(Blackhole bh) {
256 ByteBuf buffer = this.buffer;
257 int readerIndex = buffer.readerIndex();
258 bh.consume(buffer.getByte(readerIndex));
259 readerIndex += 1;
260 bh.consume(buffer.getShortLE(readerIndex));
261 readerIndex += 2;
262 bh.consume(buffer.getIntLE(readerIndex));
263 readerIndex += 4;
264 bh.consume(buffer.getLongLE(readerIndex));
265 }
266
267 @Benchmark
268 public void setBytesConstantOffset(Blackhole bh) {
269 ByteBuf buffer = this.buffer;
270 buffer.resetWriterIndex();
271 byte byteToWrite = this.byteToWrite;
272 int intToWrite = this.intToWrite;
273 long longToWrite = this.longToWrite;
274 short shortToWrite = this.shortToWrite;
275 bh.consume(buffer.setByte(0, byteToWrite));
276 bh.consume(buffer.setShortLE(1, shortToWrite));
277 bh.consume(buffer.setIntLE(3, intToWrite));
278 bh.consume(buffer.setLongLE(7, longToWrite));
279 }
280
281 @Benchmark
282 public void getBytesConstantOffset(Blackhole bh) {
283 ByteBuf buffer = this.buffer;
284 bh.consume(buffer.getByte(0));
285 bh.consume(buffer.getShortLE(1));
286 bh.consume(buffer.getIntLE(3));
287 bh.consume(buffer.getLongLE(7));
288 }
289
290 @Benchmark
291 public void readBytes(Blackhole bh) {
292 buffer.readerIndex(0);
293 ByteBuf buffer = this.buffer;
294 bh.consume(buffer.readByte());
295 bh.consume(buffer.readShortLE());
296 bh.consume(buffer.readIntLE());
297 bh.consume(buffer.readLongLE());
298 }
299 }