View Javadoc
1   /*
2    * Copyright 2018 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.buffer;
17  
18  import io.netty.microbench.util.AbstractMicrobenchmark;
19  import org.openjdk.jmh.annotations.Benchmark;
20  import org.openjdk.jmh.annotations.Measurement;
21  import org.openjdk.jmh.annotations.Param;
22  import org.openjdk.jmh.annotations.Setup;
23  import org.openjdk.jmh.annotations.TearDown;
24  import org.openjdk.jmh.annotations.Warmup;
25  
26  import java.nio.charset.Charset;
27  import java.util.Arrays;
28  import java.util.concurrent.TimeUnit;
29  
30  @Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
31  @Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
32  public class AbstractByteBufGetCharSequenceBenchmark extends AbstractMicrobenchmark {
33      private static final AdaptiveByteBufAllocator ADAPTIVE_ALLOC = new AdaptiveByteBufAllocator();
34  
35      public enum ByteBufType {
36          DIRECT {
37              @Override
38              ByteBuf newBuffer(byte[] bytes, int length) {
39                  ByteBuf buffer = Unpooled.directBuffer(length);
40                  buffer.writeBytes(bytes, 0, length);
41                  return buffer;
42              }
43          },
44          HEAP_OFFSET {
45              @Override
46              ByteBuf newBuffer(byte[] bytes, int length) {
47                  return Unpooled.wrappedBuffer(bytes, 1, length);
48              }
49          },
50          HEAP {
51              @Override
52              ByteBuf newBuffer(byte[] bytes, int length) {
53                  return Unpooled.wrappedBuffer(bytes, 0, length);
54              }
55          },
56          POOLED_HEAP {
57              @Override
58              ByteBuf newBuffer(byte[] bytes, int length) {
59                  return PooledByteBufAllocator.DEFAULT.heapBuffer(length).writeBytes(bytes, 0, length);
60              }
61          },
62          POOLED_DIRECT {
63              @Override
64              ByteBuf newBuffer(byte[] bytes, int length) {
65                  return PooledByteBufAllocator.DEFAULT.directBuffer(length).writeBytes(bytes, 0, length);
66              }
67          },
68          ADAPTIVE_HEAP {
69              @Override
70              ByteBuf newBuffer(byte[] bytes, int length) {
71                  return ADAPTIVE_ALLOC.heapBuffer(length).writeBytes(bytes, 0, length);
72              }
73          },
74          ADAPTIVE_DIRECT {
75              @Override
76              ByteBuf newBuffer(byte[] bytes, int length) {
77                  return ADAPTIVE_ALLOC.directBuffer(length).writeBytes(bytes, 0, length);
78              }
79          },
80          COMPOSITE {
81              @Override
82              ByteBuf newBuffer(byte[] bytes, int length) {
83                  CompositeByteBuf buffer = Unpooled.compositeBuffer();
84                  int offset = 0;
85                  // 8 buffers per composite.
86                  int capacity = length / 8;
87  
88                  while (length > 0) {
89                      buffer.addComponent(true, Unpooled.wrappedBuffer(bytes, offset, Math.min(length, capacity)));
90                      length -= capacity;
91                      offset += capacity;
92                  }
93                  return buffer;
94              }
95          }
96          ;
97          abstract ByteBuf newBuffer(byte[] bytes, int length);
98      }
99  
100     @Param({
101             "8",
102             "64",
103             "1024",
104             "10240",
105             "1073741824"
106     })
107     public int size;
108 
109     @Param({
110             "US-ASCII",
111             "ISO_8859_1",
112     })
113     public String charsetName;
114 
115     @Param
116     public ByteBufType bufferType;
117 
118     private ByteBuf buffer;
119     private String str;
120     private Charset charset;
121 
122     @Override
123     protected String[] jvmArgs() {
124         // Ensure we minimize the GC overhead by sizing the heap big enough.
125         return new String[] { "-XX:MaxDirectMemorySize=2g", "-Xmx8g", "-Xms8g", "-Xmn6g" };
126     }
127 
128     @Setup
129     public void setup() {
130         byte[] bytes = new byte[size + 2];
131         Arrays.fill(bytes, (byte) 'a');
132         str = new String(bytes, 0, size);
133 
134         // Use an offset to not allow any optimizations because we use the exact passed in byte[] for heap buffers.
135         buffer = bufferType.newBuffer(bytes, size);
136         charset = Charset.forName(charsetName);
137     }
138 
139     @TearDown
140     public void teardown() {
141         buffer.release();
142     }
143 
144     @Benchmark
145     public int getCharSequence() {
146         return traverse(buffer.getCharSequence(buffer.readerIndex(), size, charset));
147     }
148 
149     @Benchmark
150     public int setCharSequence() {
151         return buffer.setCharSequence(0, str, charset);
152     }
153 
154     @Benchmark
155     public int getCharSequenceOld() {
156         return traverse(buffer.toString(buffer.readerIndex(), size, charset));
157     }
158 
159     private static int traverse(CharSequence cs) {
160         int i = 0, len = cs.length();
161         while (i < len && cs.charAt(i++) != 0) {
162             // ensure result is "used"
163         }
164         return i;
165     }
166 }