1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.multipart;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.Unpooled;
20 import io.netty.handler.codec.http.DefaultHttpContent;
21 import io.netty.handler.codec.http.DefaultHttpRequest;
22 import io.netty.handler.codec.http.DefaultLastHttpContent;
23 import io.netty.handler.codec.http.HttpHeaderNames;
24 import io.netty.handler.codec.http.HttpMethod;
25 import io.netty.handler.codec.http.HttpVersion;
26 import io.netty.microbench.util.AbstractMicrobenchmark;
27 import io.netty.util.CharsetUtil;
28 import io.netty.util.ResourceLeakDetector;
29 import io.netty.util.ResourceLeakDetector.Level;
30 import org.openjdk.jmh.annotations.Benchmark;
31 import org.openjdk.jmh.annotations.Measurement;
32 import org.openjdk.jmh.annotations.OutputTimeUnit;
33 import org.openjdk.jmh.annotations.Threads;
34 import org.openjdk.jmh.annotations.Warmup;
35
36 import java.util.concurrent.TimeUnit;
37
38
39 @Threads(1)
40 @Warmup(iterations = 2)
41 @Measurement(iterations = 3)
42 @OutputTimeUnit(TimeUnit.MILLISECONDS)
43 public class HttpPostMultipartRequestDecoderBenchmark
44 extends AbstractMicrobenchmark {
45
46 public double testHighNumberChunks(boolean big, boolean noDisk) {
47 String BOUNDARY = "01f136d9282f";
48 int size = 8 * 1024;
49 int chunkNumber = 64;
50 StringBuilder stringBuilder = new StringBuilder(size);
51 stringBuilder.setLength(size);
52 String data = stringBuilder.toString();
53
54 byte[] bodyStartBytes = ("--" + BOUNDARY + "\n" +
55 "Content-Disposition: form-data; name=\"msg_id\"\n\n15200\n--" +
56 BOUNDARY +
57 "\nContent-Disposition: form-data; name=\"msg1\"; filename=\"file1.txt\"\n\n" +
58 data).getBytes(CharsetUtil.UTF_8);
59 byte[] bodyPartBigBytes = data.getBytes(CharsetUtil.UTF_8);
60 byte[] intermediaryBytes = ("\n--" + BOUNDARY +
61 "\nContent-Disposition: form-data; name=\"msg2\"; filename=\"file2.txt\"\n\n" +
62 data).getBytes(CharsetUtil.UTF_8);
63 byte[] finalBigBytes = ("\n" + "--" + BOUNDARY + "--\n").getBytes(CharsetUtil.UTF_8);
64 ByteBuf firstBuf = Unpooled.wrappedBuffer(bodyStartBytes);
65 ByteBuf finalBuf = Unpooled.wrappedBuffer(finalBigBytes);
66 ByteBuf nextBuf;
67 if (big) {
68 nextBuf = Unpooled.wrappedBuffer(bodyPartBigBytes);
69 } else {
70 nextBuf = Unpooled.wrappedBuffer(intermediaryBytes);
71 }
72 DefaultHttpRequest req =
73 new DefaultHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.POST, "/up");
74 req.headers().add(HttpHeaderNames.CONTENT_TYPE,
75 "multipart/form-data; boundary=" + BOUNDARY);
76
77 long start = System.nanoTime();
78
79 DefaultHttpDataFactory defaultHttpDataFactory =
80 new DefaultHttpDataFactory(noDisk? 1024 * 1024 : 16 * 1024);
81 HttpPostRequestDecoder decoder =
82 new HttpPostRequestDecoder(defaultHttpDataFactory, req);
83 firstBuf.retain();
84 decoder.offer(new DefaultHttpContent(firstBuf));
85 firstBuf.release();
86 for (int i = 1; i < chunkNumber; i++) {
87 nextBuf.retain();
88 decoder.offer(new DefaultHttpContent(nextBuf));
89 nextBuf.release();
90 nextBuf.readerIndex(0);
91 }
92 finalBuf.retain();
93 decoder.offer(new DefaultLastHttpContent(finalBuf));
94 finalBuf.release();
95 while (decoder.hasNext()) {
96 InterfaceHttpData httpData = decoder.next();
97 }
98 while (finalBuf.refCnt() > 0) {
99 finalBuf.release();
100 }
101 while (nextBuf.refCnt() > 0) {
102 nextBuf.release();
103 }
104 while (finalBuf.refCnt() > 0) {
105 finalBuf.release();
106 }
107 long stop = System.nanoTime();
108 double time = (stop - start) / 1000000.0;
109 defaultHttpDataFactory.cleanAllHttpData();
110 defaultHttpDataFactory.cleanRequestHttpData(req);
111 decoder.destroy();
112 return time;
113 }
114
115 @Benchmark
116 public double multipartRequestDecoderHighDisabledLevel() {
117 final Level level = ResourceLeakDetector.getLevel();
118 try {
119 ResourceLeakDetector.setLevel(Level.DISABLED);
120 return testHighNumberChunks(false, true);
121 } finally {
122 ResourceLeakDetector.setLevel(level);
123 }
124 }
125
126 @Benchmark
127 public double multipartRequestDecoderBigDisabledLevel() {
128 final Level level = ResourceLeakDetector.getLevel();
129 try {
130 ResourceLeakDetector.setLevel(Level.DISABLED);
131 return testHighNumberChunks(true, true);
132 } finally {
133 ResourceLeakDetector.setLevel(level);
134 }
135 }
136
137 @Benchmark
138 public double multipartRequestDecoderHighSimpleLevel() {
139 final Level level = ResourceLeakDetector.getLevel();
140 try {
141 ResourceLeakDetector.setLevel(Level.SIMPLE);
142 return testHighNumberChunks(false, true);
143 } finally {
144 ResourceLeakDetector.setLevel(level);
145 }
146 }
147
148 @Benchmark
149 public double multipartRequestDecoderBigSimpleLevel() {
150 final Level level = ResourceLeakDetector.getLevel();
151 try {
152 ResourceLeakDetector.setLevel(Level.SIMPLE);
153 return testHighNumberChunks(true, true);
154 } finally {
155 ResourceLeakDetector.setLevel(level);
156 }
157 }
158
159 @Benchmark
160 public double multipartRequestDecoderHighAdvancedLevel() {
161 final Level level = ResourceLeakDetector.getLevel();
162 try {
163 ResourceLeakDetector.setLevel(Level.ADVANCED);
164 return testHighNumberChunks(false, true);
165 } finally {
166 ResourceLeakDetector.setLevel(level);
167 }
168 }
169
170 @Benchmark
171 public double multipartRequestDecoderBigAdvancedLevel() {
172 final Level level = ResourceLeakDetector.getLevel();
173 try {
174 ResourceLeakDetector.setLevel(Level.ADVANCED);
175 return testHighNumberChunks(true, true);
176 } finally {
177 ResourceLeakDetector.setLevel(level);
178 }
179 }
180
181 @Benchmark
182 public double multipartRequestDecoderHighParanoidLevel() {
183 final Level level = ResourceLeakDetector.getLevel();
184 try {
185 ResourceLeakDetector.setLevel(Level.PARANOID);
186 return testHighNumberChunks(false, true);
187 } finally {
188 ResourceLeakDetector.setLevel(level);
189 }
190 }
191
192 @Benchmark
193 public double multipartRequestDecoderBigParanoidLevel() {
194 final Level level = ResourceLeakDetector.getLevel();
195 try {
196 ResourceLeakDetector.setLevel(Level.PARANOID);
197 return testHighNumberChunks(true, true);
198 } finally {
199 ResourceLeakDetector.setLevel(level);
200 }
201 }
202
203 }