• 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