• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright 2015 The gRPC Authors
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *     http://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,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package io.grpc.benchmarks.qps;
18  
19  import static io.grpc.benchmarks.Utils.parseBoolean;
20  import static java.lang.Integer.parseInt;
21  import static java.util.Arrays.asList;
22  
23  import io.grpc.ManagedChannel;
24  import io.grpc.benchmarks.Transport;
25  import io.grpc.benchmarks.Utils;
26  import io.grpc.benchmarks.proto.Control.RpcType;
27  import io.grpc.benchmarks.proto.Messages;
28  import io.grpc.benchmarks.proto.Messages.PayloadType;
29  import io.grpc.internal.testing.TestUtils;
30  import java.io.IOException;
31  import java.net.InetSocketAddress;
32  import java.net.SocketAddress;
33  import java.util.Collection;
34  import java.util.Collections;
35  import java.util.LinkedHashSet;
36  import java.util.Set;
37  
38  /**
39   * Configuration options for benchmark clients.
40   */
41  public class ClientConfiguration implements Configuration {
42    private static final ClientConfiguration DEFAULT = new ClientConfiguration();
43  
44    Transport transport = Transport.NETTY_NIO;
45    boolean tls;
46    boolean testca;
47    String authorityOverride = TestUtils.TEST_SERVER_HOST;
48    boolean useDefaultCiphers;
49    boolean directExecutor;
50    SocketAddress address;
51    int channels = 4;
52    int outstandingRpcsPerChannel = 10;
53    int serverPayload;
54    int clientPayload;
55    int flowControlWindow = Utils.DEFAULT_FLOW_CONTROL_WINDOW;
56    // seconds
57    int duration = 60;
58    // seconds
59    int warmupDuration = 10;
60    int targetQps;
61    String histogramFile;
62    RpcType rpcType = RpcType.UNARY;
63    PayloadType payloadType = PayloadType.COMPRESSABLE;
64  
ClientConfiguration()65    private ClientConfiguration() {
66    }
67  
newChannel()68    public ManagedChannel newChannel() throws IOException {
69      return Utils.newClientChannel(transport, address, tls, testca, authorityOverride,
70          flowControlWindow, directExecutor);
71    }
72  
newRequest()73    public Messages.SimpleRequest newRequest() {
74      return Utils.makeRequest(payloadType, clientPayload, serverPayload);
75    }
76  
77    /**
78     * Constructs a builder for configuring a client application with supported parameters. If no
79     * parameters are provided, all parameters are assumed to be supported.
80     */
newBuilder(ClientParam... supportedParams)81    static Builder newBuilder(ClientParam... supportedParams) {
82      return new Builder(supportedParams);
83    }
84  
85    static final class Builder extends AbstractConfigurationBuilder<ClientConfiguration> {
86      private final Collection<Param> supportedParams;
87  
Builder(ClientParam... supportedParams)88      private Builder(ClientParam... supportedParams) {
89        this.supportedParams = supportedOptionsSet(supportedParams);
90      }
91  
92      @Override
newConfiguration()93      protected ClientConfiguration newConfiguration() {
94        return new ClientConfiguration();
95      }
96  
97      @Override
getParams()98      protected Collection<Param> getParams() {
99        return supportedParams;
100      }
101  
102      @Override
build0(ClientConfiguration config)103      protected ClientConfiguration build0(ClientConfiguration config) {
104        if (config.tls) {
105          if (!config.transport.tlsSupported) {
106            throw new IllegalArgumentException(
107                "Transport " + config.transport.name().toLowerCase() + " does not support TLS.");
108          }
109  
110          if (config.transport != Transport.OK_HTTP
111              && config.testca && config.address instanceof InetSocketAddress) {
112            // Override the socket address with the host from the testca.
113            InetSocketAddress address = (InetSocketAddress) config.address;
114            config.address = TestUtils.testServerAddress(address.getHostName(),
115                    address.getPort());
116          }
117        }
118  
119        // Verify that the address type is correct for the transport type.
120        config.transport.validateSocketAddress(config.address);
121  
122        return config;
123      }
124  
supportedOptionsSet(ClientParam... supportedParams)125      private static Set<Param> supportedOptionsSet(ClientParam... supportedParams) {
126        if (supportedParams.length == 0) {
127          // If no options are supplied, default to including all options.
128          supportedParams = ClientParam.values();
129        }
130        return Collections.unmodifiableSet(new LinkedHashSet<Param>(asList(supportedParams)));
131      }
132    }
133  
134    enum ClientParam implements AbstractConfigurationBuilder.Param {
135      ADDRESS("STR", "Socket address (host:port) or Unix Domain Socket file name "
136          + "(unix:///path/to/file), depending on the transport selected.", null, true) {
137        @Override
setClientValue(ClientConfiguration config, String value)138        protected void setClientValue(ClientConfiguration config, String value) {
139          config.address = Utils.parseSocketAddress(value);
140        }
141      },
142      CHANNELS("INT", "Number of Channels.", "" + DEFAULT.channels) {
143        @Override
setClientValue(ClientConfiguration config, String value)144        protected void setClientValue(ClientConfiguration config, String value) {
145          config.channels = parseInt(value);
146        }
147      },
148      OUTSTANDING_RPCS("INT", "Number of outstanding RPCs per Channel.",
149          "" + DEFAULT.outstandingRpcsPerChannel) {
150        @Override
setClientValue(ClientConfiguration config, String value)151        protected void setClientValue(ClientConfiguration config, String value) {
152          config.outstandingRpcsPerChannel = parseInt(value);
153        }
154      },
155      CLIENT_PAYLOAD("BYTES", "Payload Size of the Request.", "" + DEFAULT.clientPayload) {
156        @Override
setClientValue(ClientConfiguration config, String value)157        protected void setClientValue(ClientConfiguration config, String value) {
158          config.clientPayload = parseInt(value);
159        }
160      },
161      SERVER_PAYLOAD("BYTES", "Payload Size of the Response.", "" + DEFAULT.serverPayload) {
162        @Override
setClientValue(ClientConfiguration config, String value)163        protected void setClientValue(ClientConfiguration config, String value) {
164          config.serverPayload = parseInt(value);
165        }
166      },
167      TLS("", "Enable TLS.", "" + DEFAULT.tls) {
168        @Override
setClientValue(ClientConfiguration config, String value)169        protected void setClientValue(ClientConfiguration config, String value) {
170          config.tls = parseBoolean(value);
171        }
172      },
173      TESTCA("", "Use the provided Test Certificate for TLS.", "" + DEFAULT.testca) {
174        @Override
setClientValue(ClientConfiguration config, String value)175        protected void setClientValue(ClientConfiguration config, String value) {
176          config.testca = parseBoolean(value);
177        }
178      },
179      TRANSPORT("STR", Transport.getDescriptionString(), DEFAULT.transport.name().toLowerCase()) {
180        @Override
setClientValue(ClientConfiguration config, String value)181        protected void setClientValue(ClientConfiguration config, String value) {
182          config.transport = Transport.valueOf(value.toUpperCase());
183        }
184      },
185      DURATION("SECONDS", "Duration of the benchmark.", "" + DEFAULT.duration) {
186        @Override
setClientValue(ClientConfiguration config, String value)187        protected void setClientValue(ClientConfiguration config, String value) {
188          config.duration = parseInt(value);
189        }
190      },
191      WARMUP_DURATION("SECONDS", "Warmup Duration of the benchmark.", "" + DEFAULT.warmupDuration) {
192        @Override
setClientValue(ClientConfiguration config, String value)193        protected void setClientValue(ClientConfiguration config, String value) {
194          config.warmupDuration = parseInt(value);
195        }
196      },
197      DIRECTEXECUTOR("",
198          "Don't use a threadpool for RPC calls, instead execute calls directly "
199              + "in the transport thread.", "" + DEFAULT.directExecutor) {
200        @Override
setClientValue(ClientConfiguration config, String value)201        protected void setClientValue(ClientConfiguration config, String value) {
202          config.directExecutor = parseBoolean(value);
203        }
204      },
205      SAVE_HISTOGRAM("FILE", "Write the histogram with the latency recordings to file.", null) {
206        @Override
setClientValue(ClientConfiguration config, String value)207        protected void setClientValue(ClientConfiguration config, String value) {
208          config.histogramFile = value;
209        }
210      },
211      STREAMING_RPCS("", "Use Streaming RPCs.", "false") {
212        @Override
setClientValue(ClientConfiguration config, String value)213        protected void setClientValue(ClientConfiguration config, String value) {
214          config.rpcType = RpcType.STREAMING;
215        }
216      },
217      FLOW_CONTROL_WINDOW("BYTES", "The HTTP/2 flow control window.",
218          "" + DEFAULT.flowControlWindow) {
219        @Override
setClientValue(ClientConfiguration config, String value)220        protected void setClientValue(ClientConfiguration config, String value) {
221          config.flowControlWindow = parseInt(value);
222        }
223      },
224      TARGET_QPS("INT", "Average number of QPS to shoot for.", "" + DEFAULT.targetQps, true) {
225        @Override
setClientValue(ClientConfiguration config, String value)226        protected void setClientValue(ClientConfiguration config, String value) {
227          config.targetQps = parseInt(value);
228        }
229      };
230  
231      private final String type;
232      private final String description;
233      private final String defaultValue;
234      private final boolean required;
235  
ClientParam(String type, String description, String defaultValue)236      ClientParam(String type, String description, String defaultValue) {
237        this(type, description, defaultValue, false);
238      }
239  
ClientParam(String type, String description, String defaultValue, boolean required)240      ClientParam(String type, String description, String defaultValue, boolean required) {
241        this.type = type;
242        this.description = description;
243        this.defaultValue = defaultValue;
244        this.required = required;
245      }
246  
247      @Override
getName()248      public String getName() {
249        return name().toLowerCase();
250      }
251  
252      @Override
getType()253      public String getType() {
254        return type;
255      }
256  
257      @Override
getDescription()258      public String getDescription() {
259        return description;
260      }
261  
262      @Override
getDefaultValue()263      public String getDefaultValue() {
264        return defaultValue;
265      }
266  
267      @Override
isRequired()268      public boolean isRequired() {
269        return required;
270      }
271  
272      @Override
setValue(Configuration config, String value)273      public void setValue(Configuration config, String value) {
274        setClientValue((ClientConfiguration) config, value);
275      }
276  
setClientValue(ClientConfiguration config, String value)277      protected abstract void setClientValue(ClientConfiguration config, String value);
278    }
279  }
280