aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java60
-rw-r--r--vespa-feed-client/src/main/java/ai/vespa/feed/client/BenchmarkingCluster.java11
-rw-r--r--vespa-feed-client/src/main/java/ai/vespa/feed/client/OperationStats.java11
3 files changed, 57 insertions, 25 deletions
diff --git a/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java b/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java
index bb0bf35dbce..b2af7dfb21f 100644
--- a/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java
+++ b/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java
@@ -15,6 +15,7 @@ import java.nio.file.Files;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -24,6 +25,8 @@ import java.util.concurrent.atomic.AtomicReference;
*/
public class CliClient {
+ private static final JsonFactory factory = new JsonFactory().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+
private final PrintStream systemOut;
private final PrintStream systemError;
private final InputStream systemIn;
@@ -59,12 +62,16 @@ public class CliClient {
JsonFeeder feeder = createJsonFeeder(feedClient, cliArgs)) {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<FeedException> fatal = new AtomicReference<>();
+ AtomicLong successes = new AtomicLong();
+ AtomicLong failures = new AtomicLong();
long startNanos = System.nanoTime();
if (cliArgs.showProgress()) {
Thread progressPrinter = new Thread(() -> {
try {
while ( ! latch.await(10, TimeUnit.SECONDS)) {
- synchronized (printMonitor) { printBenchmarkResult(System.nanoTime() - startNanos, feedClient.stats(), systemError);}
+ synchronized (printMonitor) {
+ printBenchmarkResult(System.nanoTime() - startNanos, successes.get(), failures.get(), feedClient.stats(), systemError);
+ }
}
}
catch (InterruptedException | IOException ignored) { } // doesn't happen
@@ -74,14 +81,14 @@ public class CliClient {
}
feeder.feedMany(in, new ResultCallback() {
- @Override public void onNextResult(Result result, FeedException error) { handleResult(result, error, cliArgs); }
+ @Override public void onNextResult(Result result, FeedException error) { handleResult(result, error, successes, failures, cliArgs); }
@Override public void onError(FeedException error) { fatal.set(error); latch.countDown(); }
@Override public void onComplete() { latch.countDown(); }
});
latch.await();
if (cliArgs.benchmarkModeEnabled()) {
- printBenchmarkResult(System.nanoTime() - startNanos, feedClient.stats(), systemOut);
+ printBenchmarkResult(System.nanoTime() - startNanos, successes.get(), failures.get(), feedClient.stats(), systemOut);
}
if (fatal.get() != null) throw fatal.get();
}
@@ -93,8 +100,9 @@ public class CliClient {
}
}
- private void handleResult(Result result, FeedException error, CliArguments args) {
+ private void handleResult(Result result, FeedException error, AtomicLong successes, AtomicLong failures, CliArguments args) {
if (error != null) {
+ failures.incrementAndGet();
if (args.showErrors()) synchronized (printMonitor) {
systemError.println(error.getMessage());
if (error instanceof ResultException) ((ResultException) error).getTrace().ifPresent(systemError::println);
@@ -102,6 +110,7 @@ public class CliClient {
}
}
else {
+ successes.incrementAndGet();
if (args.showSuccesses()) synchronized (printMonitor) {
systemError.println(result.documentId() + ": " + result.type());
result.traceMessage().ifPresent(systemError::println);
@@ -151,24 +160,30 @@ public class CliClient {
@Override public boolean verify(String hostname, SSLSession session) { return true; }
}
- static void printBenchmarkResult(long durationNanos, OperationStats stats, OutputStream systemOut) throws IOException {
- JsonFactory factory = new JsonFactory().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
- long okCount = stats.successes();
- long errorCount = stats.requests() - okCount;
- double throughput = okCount * 1e9 / Math.max(1, durationNanos);
+ static void printBenchmarkResult(long durationNanos, long successes, long failures,
+ OperationStats stats, OutputStream systemOut) throws IOException {
try (JsonGenerator generator = factory.createGenerator(systemOut).useDefaultPrettyPrinter()) {
generator.writeStartObject();
- generator.writeNumberField("feeder.runtime", durationNanos / 1_000_000);
- generator.writeNumberField("feeder.okcount", okCount);
- generator.writeNumberField("feeder.errorcount", errorCount);
- generator.writeNumberField("feeder.throughput", throughput);
- generator.writeNumberField("feeder.minlatency", stats.minLatencyMillis());
- generator.writeNumberField("feeder.avglatency", stats.averageLatencyMillis());
- generator.writeNumberField("feeder.maxlatency", stats.maxLatencyMillis());
- generator.writeNumberField("feeder.bytessent", stats.bytesSent());
- generator.writeNumberField("feeder.bytesreceived", stats.bytesReceived());
-
- generator.writeObjectFieldStart("feeder.responsecodes");
+
+ writeFloatField(generator, "feeder.seconds", durationNanos * 1e-9, 3);
+ generator.writeNumberField("feeder.ok.count", successes);
+ writeFloatField(generator, "feeder.ok.rate", successes * 1e9 / Math.max(1, durationNanos), 3);
+ generator.writeNumberField("feeder.error.count", failures);
+ generator.writeNumberField("feeder.inflight.count", stats.inflight());
+
+ generator.writeNumberField("http.request.count", stats.requests());
+ generator.writeNumberField("http.request.bytes", stats.bytesSent());
+
+ generator.writeNumberField("http.exception.count", stats.exceptions());
+
+ generator.writeNumberField("http.response.count", stats.responses());
+ generator.writeNumberField("http.response.bytes", stats.bytesReceived());
+ generator.writeNumberField("http.response.error.count", stats.responses() - stats.successes());
+ writeFloatField(generator, "http.response.latency.millis.min", stats.minLatencyMillis(), 3);
+ writeFloatField(generator, "http.response.latency.millis.avg", stats.averageLatencyMillis(), 3);
+ writeFloatField(generator, "http.response.latency.millis.max", stats.maxLatencyMillis(), 3);
+
+ generator.writeObjectFieldStart("http.response.code.counts");
for (Map.Entry<Integer, Long> entry : stats.responsesByCode().entrySet())
generator.writeNumberField(Integer.toString(entry.getKey()), entry.getValue());
generator.writeEndObject();
@@ -177,4 +192,9 @@ public class CliClient {
}
}
+ private static void writeFloatField(JsonGenerator generator, String name, double value, int precision) throws IOException {
+ generator.writeFieldName(name);
+ generator.writeNumber(String.format("%." + precision + "f", value));
+ }
+
}
diff --git a/vespa-feed-client/src/main/java/ai/vespa/feed/client/BenchmarkingCluster.java b/vespa-feed-client/src/main/java/ai/vespa/feed/client/BenchmarkingCluster.java
index 840219a6bf1..4a26508cd17 100644
--- a/vespa-feed-client/src/main/java/ai/vespa/feed/client/BenchmarkingCluster.java
+++ b/vespa-feed-client/src/main/java/ai/vespa/feed/client/BenchmarkingCluster.java
@@ -82,13 +82,14 @@ public class BenchmarkingCluster implements Cluster {
if (responsesByCode[code] > 0)
responses.put(code, responsesByCode[code]);
- return new OperationStats(requests.get(),
+ long requests = this.requests.get();
+ return new OperationStats(requests,
responses,
exceptions,
- requests.get() - results,
- this.responses == 0 ? 0 : totalLatencyMillis / this.responses,
- minLatencyMillis,
- maxLatencyMillis,
+ requests - results,
+ this.responses == 0 ? -1 : totalLatencyMillis / this.responses,
+ this.responses == 0 ? -1 : minLatencyMillis,
+ this.responses == 0 ? -1 : maxLatencyMillis,
bytesSent,
bytesReceived);
}
diff --git a/vespa-feed-client/src/main/java/ai/vespa/feed/client/OperationStats.java b/vespa-feed-client/src/main/java/ai/vespa/feed/client/OperationStats.java
index abba0f15880..9740421d810 100644
--- a/vespa-feed-client/src/main/java/ai/vespa/feed/client/OperationStats.java
+++ b/vespa-feed-client/src/main/java/ai/vespa/feed/client/OperationStats.java
@@ -53,46 +53,57 @@ public class OperationStats {
bytesReceived - initial.bytesReceived);
}
+ /** Number of HTTP requests attempted. */
public long requests() {
return requests;
}
+ /** Number of HTTP responses received. */
public long responses() {
return requests - inflight;
}
+ /** Number of 200 OK HTTP responses received. */
public long successes() {
return responsesByCode.getOrDefault(200, 0L);
}
+ /** Number of HTTP responses by status code. */
public Map<Integer, Long> responsesByCode() {
return responsesByCode;
}
+ /** Number of exceptions (instead of responses). */
public long exceptions() {
return exceptions;
}
+ /** Number of attempted requests which haven't yielded a response or exception yet. */
public long inflight() {
return inflight;
}
+ /** Average request-response latency, or -1. */
public long averageLatencyMillis() {
return averageLatencyMillis;
}
+ /** Minimum request-response latency, or -1. */
public long minLatencyMillis() {
return minLatencyMillis;
}
+ /** Maximum request-response latency, or -1. */
public long maxLatencyMillis() {
return maxLatencyMillis;
}
+ /** Number of bytes sent, for HTTP requests with a response. */
public long bytesSent() {
return bytesSent;
}
+ /** Number of bytes received in HTTP responses. */
public long bytesReceived() {
return bytesReceived;
}