mirror of https://github.com/grpc/grpc-java.git
Add QPS Client to perform throughput and latency tests.
This commit is contained in:
parent
127270bd5f
commit
3fd7d0675c
|
|
@ -0,0 +1,41 @@
|
||||||
|
apply plugin: 'application'
|
||||||
|
apply plugin: 'protobuf'
|
||||||
|
|
||||||
|
description = "gRPC Benchmarks"
|
||||||
|
|
||||||
|
mainClassName = "io.grpc.benchmarks.qps.Client"
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath libraries.protobuf_plugin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':grpc-core'),
|
||||||
|
project(':grpc-netty'),
|
||||||
|
project(':grpc-okhttp'),
|
||||||
|
project(':grpc-stub'),
|
||||||
|
project(':grpc-testing'),
|
||||||
|
libraries.junit,
|
||||||
|
libraries.mockito,
|
||||||
|
libraries.hdrhistogram
|
||||||
|
}
|
||||||
|
|
||||||
|
protobufCodeGenPlugins = ["java_plugin:$rootDir/compiler/build/binaries/java_pluginExecutable/java_plugin"]
|
||||||
|
compileJava.dependsOn = ['generateProto']
|
||||||
|
|
||||||
|
// Allow execution of test client and server.
|
||||||
|
task execute(dependsOn: classes, type:JavaExec) {
|
||||||
|
main = project.hasProperty('mainClass') ? project.mainClass : 'io.grpc.benchmarks.qps.Client'
|
||||||
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
|
workingDir = project.rootDir
|
||||||
|
|
||||||
|
// If appArgs were provided, set the program arguments.
|
||||||
|
if (project.hasProperty("appArgs")) {
|
||||||
|
args = Eval.me(appArgs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,360 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015, Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.grpc.benchmarks.qps;
|
||||||
|
|
||||||
|
import static grpc.testing.TestServiceGrpc.TestServiceStub;
|
||||||
|
import static grpc.testing.Qpstest.SimpleRequest;
|
||||||
|
import static grpc.testing.Qpstest.SimpleResponse;
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
import grpc.testing.Qpstest.PayloadType;
|
||||||
|
import grpc.testing.TestServiceGrpc;
|
||||||
|
import io.grpc.Channel;
|
||||||
|
import io.grpc.ChannelImpl;
|
||||||
|
import io.grpc.Status;
|
||||||
|
import io.grpc.stub.StreamObserver;
|
||||||
|
import io.grpc.transport.netty.NegotiationType;
|
||||||
|
import io.grpc.transport.netty.NettyChannelBuilder;
|
||||||
|
import io.grpc.transport.okhttp.OkHttpChannelBuilder;
|
||||||
|
import org.HdrHistogram.Histogram;
|
||||||
|
import org.HdrHistogram.HistogramIterationValue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
// TODO: Add OkHttp and Netty TLS Support
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs lots of RPCs against a QPS Server to test for throughput and latency.
|
||||||
|
* It's a Java clone of the C version at
|
||||||
|
* https://github.com/grpc/grpc/blob/master/test/cpp/qps/client.cc
|
||||||
|
*/
|
||||||
|
public class Client {
|
||||||
|
private static final Logger log = Logger.getLogger(Client.class.getName());
|
||||||
|
|
||||||
|
// Can record values between 1 ns and 1 min (60 BILLION NS)
|
||||||
|
private static final long HISTOGRAM_MAX_VALUE = 60000000000L;
|
||||||
|
private static final int HISTOGRAM_PRECISION = 3;
|
||||||
|
// How long (in ns) to do RPCs before it counts
|
||||||
|
private static final long WARMUP_TIME = 5000000000L;
|
||||||
|
|
||||||
|
private int clientChannels = 4;
|
||||||
|
private int clientThreads = 4;
|
||||||
|
private int numRpcs = 100000;
|
||||||
|
private int payloadSize = 1;
|
||||||
|
private String serverHost = "127.0.0.1";
|
||||||
|
private int serverPort;
|
||||||
|
private boolean okhttp;
|
||||||
|
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
Client c = new Client();
|
||||||
|
c.run(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void run(String[] args) throws Exception {
|
||||||
|
if (!parseArgs(args)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleRequest req = SimpleRequest.newBuilder()
|
||||||
|
.setResponseType(PayloadType.COMPRESSABLE)
|
||||||
|
.setResponseSize(payloadSize)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Channel> channels = new ArrayList<Channel>(clientChannels);
|
||||||
|
for (int i = 0; i < clientChannels; i++) {
|
||||||
|
channels.add(newChannel());
|
||||||
|
}
|
||||||
|
|
||||||
|
long warmupEnd = System.nanoTime() + WARMUP_TIME;
|
||||||
|
do {
|
||||||
|
doRpcs(channels.get(0), req, 10000).get();
|
||||||
|
} while (System.nanoTime() < warmupEnd);
|
||||||
|
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
|
||||||
|
List<Future<Histogram>> futures = new ArrayList<Future<Histogram>>(clientThreads);
|
||||||
|
for (int i = 0; i < clientThreads; i++) {
|
||||||
|
// The channel to thread assignment works a bit different than in the C++ version.
|
||||||
|
// It's the same for the "interesting cases": clientThreads == clientChannels and
|
||||||
|
// clientChannels == 1.
|
||||||
|
// It however doesn't support "cache thrashing" as mentioned in the comments of the
|
||||||
|
// C++ client. That's because it's my understanding that it doesn't make sense for our API
|
||||||
|
// as we neither use fixed threads per call nor do we pin them to specific cores.
|
||||||
|
Channel channel = channels.get(i % clientChannels);
|
||||||
|
futures.add(doRpcs(channel, req, numRpcs));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Histogram> histograms = new ArrayList<Histogram>(futures.size());
|
||||||
|
for (Future<Histogram> future : futures) {
|
||||||
|
histograms.add(future.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
long elapsedTime = System.nanoTime() - startTime;
|
||||||
|
|
||||||
|
Histogram merged = merge(histograms);
|
||||||
|
|
||||||
|
assert merged.getTotalCount() == numRpcs * clientThreads;
|
||||||
|
|
||||||
|
printStats(merged, elapsedTime);
|
||||||
|
|
||||||
|
// shutdown
|
||||||
|
for (Channel channel : channels) {
|
||||||
|
((ChannelImpl) channel).shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Channel newChannel() {
|
||||||
|
if (okhttp) {
|
||||||
|
return OkHttpChannelBuilder.forAddress(serverHost, serverPort).build();
|
||||||
|
} else {
|
||||||
|
return NettyChannelBuilder.forAddress(serverHost, serverPort)
|
||||||
|
.negotiationType(NegotiationType.PLAINTEXT)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseArgs(String[] args) {
|
||||||
|
try {
|
||||||
|
boolean hasServerPort = false;
|
||||||
|
|
||||||
|
for (String arg : args) {
|
||||||
|
if (!arg.startsWith("--")) {
|
||||||
|
System.err.println("All arguments must start with '--': " + arg);
|
||||||
|
printUsage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] pair = arg.substring(2).split("=", 2);
|
||||||
|
if (pair.length < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String key = pair[0];
|
||||||
|
String value = pair[1];
|
||||||
|
|
||||||
|
if ("client_channels".equals(key)) {
|
||||||
|
clientChannels = max(Integer.parseInt(value), 1);
|
||||||
|
} else if ("client_threads".equals(key)) {
|
||||||
|
clientThreads = max(Integer.parseInt(value), 1);
|
||||||
|
} else if ("num_rpcs".equals(key)) {
|
||||||
|
numRpcs = max(Integer.parseInt(value), 1);
|
||||||
|
} else if ("payload_size".equals(key)) {
|
||||||
|
payloadSize = max(Integer.parseInt(value), 0);
|
||||||
|
} else if ("server_host".equals(key)) {
|
||||||
|
serverHost = value;
|
||||||
|
} else if ("server_port".equals(key)) {
|
||||||
|
serverPort = Integer.parseInt(value);
|
||||||
|
hasServerPort = true;
|
||||||
|
} else if ("transport".equals(key)) {
|
||||||
|
okhttp = "okhttp".equals(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasServerPort) {
|
||||||
|
System.err.println("'--server_port' was not specified.");
|
||||||
|
printUsage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
printUsage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printUsage() {
|
||||||
|
Client c = new Client();
|
||||||
|
System.out.println(
|
||||||
|
"Usage: [ARGS...]"
|
||||||
|
+ "\n"
|
||||||
|
+ "\n --server_port=INT Port of the server. Required. No default."
|
||||||
|
+ "\n --server_host=STR Hostname of the server. Default " + c.serverHost
|
||||||
|
+ "\n --client_channels=INT Number of client channels. Default " + c.clientChannels
|
||||||
|
+ "\n --client_threads=INT Number of client threads. Default " + c.clientThreads
|
||||||
|
+ "\n --num_rpcs=INT Number of RPCs per thread. Default " + c.numRpcs
|
||||||
|
+ "\n --payload_size=INT Payload size in bytes. Default " + c.payloadSize
|
||||||
|
+ "\n --transport=(okhttp|netty) The transport to use. Default netty"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Future<Histogram> doRpcs(Channel channel,
|
||||||
|
final SimpleRequest request,
|
||||||
|
final int numRpcs) {
|
||||||
|
final TestServiceStub stub = TestServiceGrpc.newStub(channel);
|
||||||
|
final CountDownLatch remainingRpcs = new CountDownLatch(numRpcs);
|
||||||
|
final Histogram histogram = new Histogram(HISTOGRAM_MAX_VALUE, HISTOGRAM_PRECISION);
|
||||||
|
final HistogramFuture future = new HistogramFuture(histogram, remainingRpcs);
|
||||||
|
|
||||||
|
stub.unaryCall(request, new StreamObserver<SimpleResponse>() {
|
||||||
|
long lastCall = System.nanoTime();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(SimpleResponse value) {
|
||||||
|
PayloadType type = value.getPayload().getType();
|
||||||
|
int actualSize = value.getPayload().getBody().size();
|
||||||
|
|
||||||
|
if (!PayloadType.COMPRESSABLE.equals(type)) {
|
||||||
|
throw new RuntimeException("type was '" + type + "', expected '" +
|
||||||
|
PayloadType.COMPRESSABLE + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payloadSize != actualSize) {
|
||||||
|
throw new RuntimeException("size was '" + actualSize + "', expected '" +
|
||||||
|
payloadSize + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
Status status = Status.fromThrowable(t);
|
||||||
|
System.err.println("onError called: " + status);
|
||||||
|
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
long now = System.nanoTime();
|
||||||
|
histogram.recordValue(now - lastCall);
|
||||||
|
lastCall = now;
|
||||||
|
|
||||||
|
remainingRpcs.countDown();
|
||||||
|
|
||||||
|
if (remainingRpcs.getCount() > 0) {
|
||||||
|
stub.unaryCall(request, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Histogram merge(List<Histogram> histograms) {
|
||||||
|
Histogram merged = new Histogram(HISTOGRAM_MAX_VALUE, HISTOGRAM_PRECISION);
|
||||||
|
for (Histogram histogram : histograms) {
|
||||||
|
for (HistogramIterationValue value : histogram.allValues()) {
|
||||||
|
long latency = value.getValueIteratedTo();
|
||||||
|
long count = value.getCountAtValueIteratedTo();
|
||||||
|
merged.recordValueWithCount(latency, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printStats(Histogram histogram, long elapsedTime) {
|
||||||
|
double percentiles[] = {50, 90, 95, 99, 99.9, 99.99};
|
||||||
|
|
||||||
|
// Generate a comma-separated string of percentiles
|
||||||
|
StringBuilder header = new StringBuilder();
|
||||||
|
StringBuilder values = new StringBuilder();
|
||||||
|
|
||||||
|
header.append("Threads, Channels, Payload Size, ");
|
||||||
|
values.append(String.format("%s, %d, %d, ", clientThreads, clientChannels, payloadSize));
|
||||||
|
|
||||||
|
for (double percentile : percentiles) {
|
||||||
|
header.append(percentile).append("%ile").append(", ");
|
||||||
|
values.append(histogram.getValueAtPercentile(percentile)).append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
header.append("QPS");
|
||||||
|
values.append((histogram.getTotalCount() * 1000000000L) / elapsedTime);
|
||||||
|
|
||||||
|
System.out.println(header.toString());
|
||||||
|
System.out.println(values.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HistogramFuture implements Future<Histogram> {
|
||||||
|
private final Histogram histogram;
|
||||||
|
private final CountDownLatch latch;
|
||||||
|
|
||||||
|
private final AtomicBoolean canceled = new AtomicBoolean();
|
||||||
|
|
||||||
|
HistogramFuture(Histogram histogram, CountDownLatch latch) {
|
||||||
|
Preconditions.checkNotNull(histogram, "histogram");
|
||||||
|
Preconditions.checkNotNull(histogram, "latch");
|
||||||
|
|
||||||
|
this.histogram = histogram;
|
||||||
|
this.latch = latch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||||
|
if (latch.getCount() > 0 && canceled.compareAndSet(false, true)) {
|
||||||
|
while (latch.getCount() > 0) {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return canceled.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return latch.getCount() == 0 || canceled.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Histogram get() throws InterruptedException, ExecutionException {
|
||||||
|
latch.await();
|
||||||
|
|
||||||
|
if (canceled.get()) {
|
||||||
|
throw new CancellationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return histogram;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Histogram get(long timeout, TimeUnit unit) throws InterruptedException,
|
||||||
|
ExecutionException,
|
||||||
|
TimeoutException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
// An integration test service that covers all the method signature permutations
|
||||||
|
// of unary/streaming requests/responses.
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package grpc.testing;
|
||||||
|
|
||||||
|
enum PayloadType {
|
||||||
|
// Compressable text format.
|
||||||
|
COMPRESSABLE= 1;
|
||||||
|
|
||||||
|
// Uncompressable binary format.
|
||||||
|
UNCOMPRESSABLE = 2;
|
||||||
|
|
||||||
|
// Randomly chosen from all other formats defined in this enum.
|
||||||
|
RANDOM = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StatsRequest {
|
||||||
|
// run number
|
||||||
|
optional int32 test_num = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ServerStats {
|
||||||
|
// wall clock time for timestamp
|
||||||
|
required double time_now = 1;
|
||||||
|
|
||||||
|
// user time used by the server process and threads
|
||||||
|
required double time_user = 2;
|
||||||
|
|
||||||
|
// server time used by the server process and all threads
|
||||||
|
required double time_system = 3;
|
||||||
|
|
||||||
|
// RPC count so far
|
||||||
|
optional int32 num_rpcs = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Payload {
|
||||||
|
// The type of data in body.
|
||||||
|
optional PayloadType type = 1;
|
||||||
|
// Primary contents of payload.
|
||||||
|
optional bytes body = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Latencies {
|
||||||
|
required double l_50 = 1;
|
||||||
|
required double l_90 = 2;
|
||||||
|
required double l_99 = 3;
|
||||||
|
required double l_999 = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StartArgs {
|
||||||
|
required string server_host = 1;
|
||||||
|
required int32 server_port = 2;
|
||||||
|
optional bool enable_ssl = 3 [default = false];
|
||||||
|
optional int32 client_threads = 4 [default = 1];
|
||||||
|
optional int32 client_channels = 5 [default = -1];
|
||||||
|
optional int32 num_rpcs = 6 [default = 1];
|
||||||
|
optional int32 payload_size = 7 [default = 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
message StartResult {
|
||||||
|
required Latencies latencies = 1;
|
||||||
|
required int32 num_rpcs = 2;
|
||||||
|
required double time_elapsed = 3;
|
||||||
|
required double time_user = 4;
|
||||||
|
required double time_system = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SimpleRequest {
|
||||||
|
// Desired payload type in the response from the server.
|
||||||
|
// If response_type is RANDOM, server randomly chooses one from other formats.
|
||||||
|
optional PayloadType response_type = 1 [default=COMPRESSABLE];
|
||||||
|
|
||||||
|
// Desired payload size in the response from the server.
|
||||||
|
// If response_type is COMPRESSABLE, this denotes the size before compression.
|
||||||
|
optional int32 response_size = 2;
|
||||||
|
|
||||||
|
// Optional input payload sent along with the request.
|
||||||
|
optional Payload payload = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SimpleResponse {
|
||||||
|
optional Payload payload = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StreamingInputCallRequest {
|
||||||
|
// Optional input payload sent along with the request.
|
||||||
|
optional Payload payload = 1;
|
||||||
|
|
||||||
|
// Not expecting any payload from the response.
|
||||||
|
}
|
||||||
|
|
||||||
|
message StreamingInputCallResponse {
|
||||||
|
// Aggregated size of payloads received from the client.
|
||||||
|
optional int32 aggregated_payload_size = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ResponseParameters {
|
||||||
|
// Desired payload sizes in responses from the server.
|
||||||
|
// If response_type is COMPRESSABLE, this denotes the size before compression.
|
||||||
|
required int32 size = 1;
|
||||||
|
|
||||||
|
// Desired interval between consecutive responses in the response stream in
|
||||||
|
// microseconds.
|
||||||
|
required int32 interval_us = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StreamingOutputCallRequest {
|
||||||
|
// Desired payload type in the response from the server.
|
||||||
|
// If response_type is RANDOM, the payload from each response in the stream
|
||||||
|
// might be of different types. This is to simulate a mixed type of payload
|
||||||
|
// stream.
|
||||||
|
optional PayloadType response_type = 1 [default=COMPRESSABLE];
|
||||||
|
|
||||||
|
repeated ResponseParameters response_parameters = 2;
|
||||||
|
|
||||||
|
// Optional input payload sent along with the request.
|
||||||
|
optional Payload payload = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StreamingOutputCallResponse {
|
||||||
|
optional Payload payload = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service TestService {
|
||||||
|
// Start test with specified workload
|
||||||
|
rpc StartTest(StartArgs) returns (Latencies);
|
||||||
|
|
||||||
|
// Collect stats from server, ignore request content
|
||||||
|
rpc CollectServerStats(StatsRequest) returns (ServerStats);
|
||||||
|
|
||||||
|
// One request followed by one response.
|
||||||
|
// The server returns the client payload as-is.
|
||||||
|
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
|
||||||
|
|
||||||
|
// One request followed by a sequence of responses (streamed download).
|
||||||
|
// The server returns the payload with client desired type and sizes.
|
||||||
|
rpc StreamingOutputCall(StreamingOutputCallRequest)
|
||||||
|
returns (stream StreamingOutputCallResponse);
|
||||||
|
|
||||||
|
// A sequence of requests followed by one response (streamed upload).
|
||||||
|
// The server returns the aggregated size of client payload as the result.
|
||||||
|
rpc StreamingInputCall(stream StreamingInputCallRequest)
|
||||||
|
returns (StreamingInputCallResponse);
|
||||||
|
|
||||||
|
// A sequence of requests with each request served by the server immediately.
|
||||||
|
// As one request could lead to multiple responses, this interface
|
||||||
|
// demonstrates the idea of full duplexing.
|
||||||
|
rpc FullDuplexCall(stream StreamingOutputCallRequest)
|
||||||
|
returns (stream StreamingOutputCallResponse);
|
||||||
|
|
||||||
|
// A sequence of requests followed by a sequence of responses.
|
||||||
|
// The server buffers all the client requests and then serves them in order. A
|
||||||
|
// stream of responses are returned to the client when the server starts with
|
||||||
|
// first request.
|
||||||
|
rpc HalfDuplexCall(stream StreamingOutputCallRequest)
|
||||||
|
returns (stream StreamingOutputCallResponse);
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,8 @@ subprojects {
|
||||||
hpack: 'com.twitter:hpack:0.9.1',
|
hpack: 'com.twitter:hpack:0.9.1',
|
||||||
protobuf_plugin: 'ws.antonov.gradle.plugins:gradle-plugin-protobuf:0.9.1',
|
protobuf_plugin: 'ws.antonov.gradle.plugins:gradle-plugin-protobuf:0.9.1',
|
||||||
okhttp: 'com.squareup.okhttp:okhttp:2.2.0',
|
okhttp: 'com.squareup.okhttp:okhttp:2.2.0',
|
||||||
|
// used to collect benchmark results
|
||||||
|
hdrhistogram: 'org.hdrhistogram:HdrHistogram:2.1.4',
|
||||||
|
|
||||||
// TODO: Unreleased dependencies.
|
// TODO: Unreleased dependencies.
|
||||||
// These must already be installed in the local maven repository.
|
// These must already be installed in the local maven repository.
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ include ":grpc-testing"
|
||||||
include ":grpc-compiler"
|
include ":grpc-compiler"
|
||||||
include ":grpc-integration-testing"
|
include ":grpc-integration-testing"
|
||||||
include ":grpc-all"
|
include ":grpc-all"
|
||||||
|
include ":grpc-benchmarks"
|
||||||
|
|
||||||
project(':grpc-core').projectDir = "$rootDir/core" as File
|
project(':grpc-core').projectDir = "$rootDir/core" as File
|
||||||
project(':grpc-stub').projectDir = "$rootDir/stub" as File
|
project(':grpc-stub').projectDir = "$rootDir/stub" as File
|
||||||
|
|
@ -18,3 +19,4 @@ project(':grpc-testing').projectDir = "$rootDir/testing" as File
|
||||||
project(':grpc-compiler').projectDir = "$rootDir/compiler" as File
|
project(':grpc-compiler').projectDir = "$rootDir/compiler" as File
|
||||||
project(':grpc-integration-testing').projectDir = "$rootDir/integration-testing" as File
|
project(':grpc-integration-testing').projectDir = "$rootDir/integration-testing" as File
|
||||||
project(':grpc-all').projectDir = "$rootDir/all" as File
|
project(':grpc-all').projectDir = "$rootDir/all" as File
|
||||||
|
project(':grpc-benchmarks').projectDir = "$rootDir/benchmarks" as File
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue