View Javadoc
1   /*
2    * Copyright 2022 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.handler.codec.http2;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.Unpooled;
20  import io.netty.microbench.util.AbstractMicrobenchmark;
21  import io.netty.util.AsciiString;
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.Scope;
30  import org.openjdk.jmh.annotations.Setup;
31  import org.openjdk.jmh.annotations.State;
32  import org.openjdk.jmh.annotations.Threads;
33  import org.openjdk.jmh.annotations.Warmup;
34  import org.openjdk.jmh.infra.Blackhole;
35  
36  import java.util.Random;
37  import java.util.concurrent.TimeUnit;
38  
39  @Fork(5)
40  @Threads(1)
41  @State(Scope.Benchmark)
42  @Warmup(iterations = 5)
43  @Measurement(iterations = 5)
44  @OutputTimeUnit(TimeUnit.NANOSECONDS)
45  @BenchmarkMode(Mode.AverageTime)
46  public class HpackEncoderBenchmarkUniqueValues extends AbstractMicrobenchmark {
47  
48      @Param({"fewHeaders", "manyPaths", "tracesWithUniqueValues"})
49      private String type;
50  
51      private final AsciiString[] PATHS = generateRandomPaths(20);
52  
53      private final Random r = new Random();
54  
55      private final Http2Headers[] http2Headers = new Http2Headers[1000];
56  
57      private final HpackEncoder[] hpackEncoder = new HpackEncoder[1000];
58  
59      private final ByteBuf output = Unpooled.buffer(10, 10000);
60  
61      @Setup
62      public void setup() throws Http2Exception {
63          for (int i = 0; i < http2Headers.length; i++) {
64              DefaultHttp2Headers headers = new DefaultHttp2Headers();
65              if (type.equals("tracesWithUniqueValues")) {
66                  headers.add(AsciiString.of("traceid"), randomAsciiString(20));
67              }
68              headers.add(AsciiString.of("key1"), AsciiString.of("value1"));
69              headers.add(AsciiString.of("key12"), AsciiString.of("value12"));
70              headers.add(AsciiString.of("key123"), AsciiString.of("value123"));
71              if (type.equals("manyPaths")) {
72                  headers.add(AsciiString.of(":path"), AsciiString.of("/path/to/" + PATHS[r.nextInt(PATHS.length)]));
73              }
74              headers.add(AsciiString.of(":method"), AsciiString.of("POST"));
75              headers.add(AsciiString.of("content-encoding"), AsciiString.of("grpc-encoding"));
76              http2Headers[i] = headers;
77          }
78  
79          for (int i = 0; i < hpackEncoder.length; i++) {
80              hpackEncoder[i] = new HpackEncoder();
81              for (Http2Headers headers: http2Headers) {
82                  output.clear();
83                  hpackEncoder[i].encodeHeaders(3, output, headers, Http2HeadersEncoder.NEVER_SENSITIVE);
84              }
85          }
86      }
87  
88      @Benchmark
89      public void encode(Blackhole bh) throws Exception {
90          output.clear();
91  
92          Http2Headers headers = http2Headers[r.nextInt(http2Headers.length)];
93  
94          // select between many encoders to prevent the encoder state from staying in the cpu L1 cache.
95          HpackEncoder encoder = hpackEncoder[r.nextInt(hpackEncoder.length)];
96          encoder.encodeHeaders(3, output, headers, Http2HeadersEncoder.NEVER_SENSITIVE);
97  
98          bh.consume(output);
99      }
100 
101     private static AsciiString[] generateRandomPaths(int size) {
102         AsciiString[] paths = new AsciiString[size];
103         for (int i = 0; i < size; i++) {
104             paths[i] = randomAsciiString(20);
105         }
106         return paths;
107     }
108 
109     private static AsciiString randomAsciiString(int length) {
110         return AsciiString.of(HpackHeader.createHeaders(1, 10, length, true).get(0).value);
111     }
112 
113 }