1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.buffer;
17
18 import io.netty.microbench.util.AbstractMicrobenchmark;
19 import io.netty.util.ByteProcessor;
20
21 import org.openjdk.jmh.annotations.Benchmark;
22 import org.openjdk.jmh.annotations.Measurement;
23 import org.openjdk.jmh.annotations.Param;
24 import org.openjdk.jmh.annotations.Setup;
25 import org.openjdk.jmh.annotations.TearDown;
26 import org.openjdk.jmh.annotations.Warmup;
27
28 import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
29 import static io.netty.buffer.Unpooled.directBuffer;
30 import static io.netty.buffer.Unpooled.wrappedBuffer;
31
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.concurrent.TimeUnit;
35
36 @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
37 @Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
38 public class CompositeByteBufSequentialBenchmark extends AbstractMicrobenchmark {
39
40 public enum ByteBufType {
41 SMALL_CHUNKS {
42 @Override
43 ByteBuf newBuffer(int length) {
44 return newBufferSmallChunks(length);
45 }
46 },
47 LARGE_CHUNKS {
48 @Override
49 ByteBuf newBuffer(int length) {
50 return newBufferLargeChunks(length);
51 }
52 },
53 SMALL_CHUNKS_DIRECT {
54 @Override
55 ByteBuf newBuffer(int length) {
56 return newBufferSmallChunksDirect(length);
57 }
58 },
59 LARGE_CHUNKS_DIRECT {
60 @Override
61 ByteBuf newBuffer(int length) {
62 return newBufferLargeChunksDirect(length);
63 }
64 };
65 abstract ByteBuf newBuffer(int length);
66 }
67
68 @Param({
69 "8",
70 "64",
71 "1024",
72 "10240",
73 "102400",
74 "1024000",
75 })
76 public int size;
77
78 @Param
79 public ByteBufType bufferType;
80
81 private ByteBuf buffer;
82
83 @Setup
84 public void setup() {
85 buffer = bufferType.newBuffer(size);
86
87 buffer.writerIndex(buffer.capacity());
88 }
89
90 @TearDown
91 public void teardown() {
92 buffer.release();
93 }
94
95 private static final ByteProcessor TEST_PROCESSOR = new ByteProcessor() {
96 @Override
97 public boolean process(byte value) throws Exception {
98 return value != 'b';
99 }
100 };
101
102 @Benchmark
103 public int forEachByte() {
104 buffer.setIndex(0, buffer.capacity());
105 buffer.forEachByte(TEST_PROCESSOR);
106 return buffer.forEachByteDesc(TEST_PROCESSOR);
107 }
108
109 @Benchmark
110 public int sequentialReadBytes() {
111 buffer.readerIndex(0);
112 int result = 0;
113 for (int i = 0, l = buffer.readableBytes(); i < l; i++) {
114 result += buffer.readByte();
115 }
116 return result;
117 }
118
119 @Benchmark
120 public int sequentialGetBytes() {
121 int result = 0;
122 for (int i = 0, l = buffer.capacity(); i < l; i++) {
123 result += buffer.getByte(i);
124 }
125 return result;
126 }
127
128 @Benchmark
129 public int sequentialWriteAndRead() {
130 buffer.clear();
131 for (int i = 0, l = buffer.writableBytes(); i < l; i++) {
132 buffer.writeByte('a');
133 }
134 for (int i = 0, l = buffer.readableBytes(); i < l; i++) {
135 if (buffer.readByte() == 'b') {
136 return -1;
137 }
138 }
139 return 1;
140 }
141
142 private static ByteBuf newBufferSmallChunks(int length) {
143
144 List<ByteBuf> buffers = new ArrayList<ByteBuf>(((length + 1) / 45) * 19);
145 for (int i = 0; i < length + 45; i += 45) {
146 for (int j = 1; j <= 9; j++) {
147 buffers.add(EMPTY_BUFFER);
148 buffers.add(wrappedBuffer(new byte[j]));
149 }
150 buffers.add(EMPTY_BUFFER);
151 }
152
153 ByteBuf buffer = wrappedBuffer(Integer.MAX_VALUE, buffers.toArray(new ByteBuf[0]));
154
155
156 return buffer.capacity(length).writerIndex(0);
157 }
158
159 private static ByteBuf newBufferLargeChunks(int length) {
160
161 List<ByteBuf> buffers = new ArrayList<ByteBuf>((length + 1) / 512);
162 for (int i = 0; i < length + 1536; i += 1536) {
163 buffers.add(wrappedBuffer(new byte[512]));
164 buffers.add(EMPTY_BUFFER);
165 buffers.add(wrappedBuffer(new byte[1024]));
166 }
167
168 ByteBuf buffer = wrappedBuffer(Integer.MAX_VALUE, buffers.toArray(new ByteBuf[0]));
169
170
171 return buffer.capacity(length).writerIndex(0);
172 }
173
174 private static ByteBuf newDirectChunk(int size) {
175 ByteBuf buf = directBuffer(size);
176 buf.writerIndex(size);
177 return buf;
178 }
179
180 private static ByteBuf newBufferSmallChunksDirect(int length) {
181
182 List<ByteBuf> buffers = new ArrayList<ByteBuf>(((length + 1) / 45) * 19);
183 for (int i = 0; i < length + 45; i += 45) {
184 for (int j = 1; j <= 9; j++) {
185 buffers.add(EMPTY_BUFFER);
186 buffers.add(newDirectChunk(j));
187 }
188 buffers.add(EMPTY_BUFFER);
189 }
190
191 ByteBuf buffer = wrappedBuffer(Integer.MAX_VALUE, buffers.toArray(new ByteBuf[0]));
192
193
194 return buffer.capacity(length).writerIndex(0);
195 }
196
197 private static ByteBuf newBufferLargeChunksDirect(int length) {
198
199 List<ByteBuf> buffers = new ArrayList<ByteBuf>((length + 1) / 512);
200 for (int i = 0; i < length + 1536; i += 1536) {
201 buffers.add(newDirectChunk(512));
202 buffers.add(EMPTY_BUFFER);
203 buffers.add(newDirectChunk(1024));
204 }
205
206 ByteBuf buffer = wrappedBuffer(Integer.MAX_VALUE, buffers.toArray(new ByteBuf[0]));
207
208
209 return buffer.capacity(length).writerIndex(0);
210 }
211 }