diff --git a/simulation/src/main/java/com/palantir/dialogue/core/Benchmark.java b/simulation/src/main/java/com/palantir/dialogue/core/Benchmark.java index 53228d5f6..458b72a01 100644 --- a/simulation/src/main/java/com/palantir/dialogue/core/Benchmark.java +++ b/simulation/src/main/java/com/palantir/dialogue/core/Benchmark.java @@ -142,7 +142,8 @@ public BenchmarkResult run() { @SuppressWarnings("FutureReturnValueIgnored") public ListenableFuture schedule() { - HistogramChannel histogramChannel = new HistogramChannel(simulation, channelUnderTest); + DialogueClientMetrics clientMetrics = DialogueClientMetrics.of(simulation.taggedMetrics()); + InstrumentedChannel channel = new InstrumentedChannel(channelUnderTest, clientMetrics); long[] requestsStarted = {0}; long[] responsesReceived = {0}; @@ -152,6 +153,7 @@ public ListenableFuture schedule() { FutureCallback accumulateStatusCodes = new FutureCallback() { @Override public void onSuccess(Response response) { + response.close(); // just being a good citizen statusCodes.compute(Integer.toString(response.code()), (c, num) -> num == null ? 1 : num + 1); } @@ -166,7 +168,7 @@ public void onFailure(Throwable throwable) { () -> { log.debug( "time={} starting num={} {}", simulation.clock().read(), req.number(), req); - ListenableFuture future = histogramChannel.execute(req.endpoint(), req.request()); + ListenableFuture future = channel.execute(req.endpoint(), req.request()); requestsStarted[0] += 1; Futures.addCallback(future, accumulateStatusCodes, MoreExecutors.directExecutor()); @@ -184,19 +186,30 @@ public void onFailure(Throwable throwable) { TimeUnit.NANOSECONDS); }); - benchmarkFinished.getFuture().addListener(simulation.metrics()::report, MoreExecutors.directExecutor()); + benchmarkFinished.getFuture().addListener(simulation.metricsReporter()::report, MoreExecutors.directExecutor()); return Futures.transform( benchmarkFinished.getFuture(), - v -> ImmutableBenchmarkResult.builder() - .clientHistogram(histogramChannel.getHistogram().getSnapshot()) - .endTime(Duration.ofNanos(simulation.clock().read())) - .statusCodes(statusCodes) - .successPercentage( - Math.round(statusCodes.getOrDefault("200", 0) * 1000d / requestsStarted[0]) / 10d) - .numSent(requestsStarted[0]) - .numReceived(responsesReceived[0]) - .build(), + v -> { + long numGlobalResponses = MetricNames.globalResponses(simulation.taggedMetrics()) + .getCount(); + long leaked = numGlobalResponses + - MetricNames.responseClose(simulation.taggedMetrics()) + .getCount(); + return ImmutableBenchmarkResult.builder() + .clientHistogram(clientMetrics + .response(SimulationUtils.SERVICE_NAME) + .getSnapshot()) + .endTime(Duration.ofNanos(simulation.clock().read())) + .statusCodes(statusCodes) + .successPercentage( + Math.round(statusCodes.getOrDefault("200", 0) * 1000d / requestsStarted[0]) / 10d) + .numSent(requestsStarted[0]) + .numReceived(responsesReceived[0]) + .numGlobalResponses(numGlobalResponses) + .responsesLeaked(leaked) + .build(); + }, MoreExecutors.directExecutor()); } @@ -218,11 +231,20 @@ interface BenchmarkResult { Map statusCodes(); + /** What proportion of responses were 200s. */ double successPercentage(); + /** How many requests did we fire off in the benchmark. */ long numSent(); + /** How many responses were returned to the user. */ long numReceived(); + + /** How many responses were issued in total across all servers. */ + long numGlobalResponses(); + + /** How many responses were never closed. */ + long responsesLeaked(); } /** diff --git a/simulation/src/main/java/com/palantir/dialogue/core/HistogramChannel.java b/simulation/src/main/java/com/palantir/dialogue/core/HistogramChannel.java deleted file mode 100644 index e5e24ddb7..000000000 --- a/simulation/src/main/java/com/palantir/dialogue/core/HistogramChannel.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.palantir.dialogue.core; - -import com.codahale.metrics.Histogram; -import com.codahale.metrics.SlidingTimeWindowArrayReservoir; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; -import com.palantir.dialogue.Channel; -import com.palantir.dialogue.Endpoint; -import com.palantir.dialogue.Request; -import com.palantir.dialogue.Response; -import java.util.concurrent.TimeUnit; - -final class HistogramChannel implements Channel { - private final Simulation simulation; - private final Histogram histogram; - private final Channel channel; - - HistogramChannel(Simulation simulation, Channel channel) { - this.simulation = simulation; - this.channel = channel; - histogram = new Histogram(new SlidingTimeWindowArrayReservoir(1, TimeUnit.DAYS, simulation.codahaleClock())); - } - - /** Unit is nanos. */ - public Histogram getHistogram() { - return histogram; - } - - @Override - public ListenableFuture execute(Endpoint endpoint, Request request) { - long start = simulation.clock().read(); - ListenableFuture future = channel.execute(endpoint, request); - future.addListener(() -> histogram.update(simulation.clock().read() - start), MoreExecutors.directExecutor()); - return future; - } -} diff --git a/simulation/src/main/java/com/palantir/dialogue/core/MetricNames.java b/simulation/src/main/java/com/palantir/dialogue/core/MetricNames.java new file mode 100644 index 000000000..c1061c4c8 --- /dev/null +++ b/simulation/src/main/java/com/palantir/dialogue/core/MetricNames.java @@ -0,0 +1,59 @@ +/* + * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.dialogue.core; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Meter; +import com.palantir.dialogue.Endpoint; +import com.palantir.tritium.metrics.registry.MetricName; +import com.palantir.tritium.metrics.registry.TaggedMetricRegistry; + +final class MetricNames { + /** Counter incremented every time a {@code Response} is closed. */ + static Counter responseClose(TaggedMetricRegistry reg) { + return reg.counter(MetricName.builder().safeName("responseClose").build()); + } + + /** Counter for how many responses are issued across all servers. */ + static Counter globalResponses(TaggedMetricRegistry registry) { + return registry.counter(MetricName.builder().safeName("globalResponses").build()); + } + + /** Counter for how long servers spend processing requests. */ + static Counter globalServerTimeNanos(TaggedMetricRegistry registry) { + return registry.counter( + MetricName.builder().safeName("globalServerTime").build()); + } + + static Counter activeRequests(TaggedMetricRegistry reg, String serverName) { + return reg.counter(MetricName.builder() + .safeName("activeRequests") + .putSafeTags("server", serverName) + .build()); + } + + /** Marked every time a server received a request. */ + static Meter requestMeter(TaggedMetricRegistry reg, String serverName, Endpoint endpoint) { + return reg.meter(MetricName.builder() + .safeName("request") + .putSafeTags("server", serverName) + .putSafeTags("endpoint", endpoint.endpointName()) + .build()); + } + + private MetricNames() {} +} diff --git a/simulation/src/main/java/com/palantir/dialogue/core/Simulation.java b/simulation/src/main/java/com/palantir/dialogue/core/Simulation.java index 20294773d..d0b3d0f54 100644 --- a/simulation/src/main/java/com/palantir/dialogue/core/Simulation.java +++ b/simulation/src/main/java/com/palantir/dialogue/core/Simulation.java @@ -35,10 +35,12 @@ final class Simulation { private final DeterministicScheduler deterministicExecutor = new DeterministicScheduler(); private final ListeningScheduledExecutorService listenableExecutor = MoreExecutors.listeningDecorator(deterministicExecutor); + private final TestCaffeineTicker ticker = new TestCaffeineTicker(); - private final SimulationMetrics metrics = new SimulationMetrics(this); + private final SimulationMetricsReporter metrics = new SimulationMetricsReporter(this); private final CodahaleClock codahaleClock = new CodahaleClock(ticker); private final EventMarkers eventMarkers = new EventMarkers(ticker); + private final TaggedMetrics taggedMetrics = new TaggedMetrics(codahaleClock); Simulation() { Thread.currentThread().setUncaughtExceptionHandler((t, e) -> log.error("Uncaught throwable", e)); @@ -82,7 +84,11 @@ public CodahaleClock codahaleClock() { return codahaleClock; } - public SimulationMetrics metrics() { + public TaggedMetrics taggedMetrics() { + return taggedMetrics; + } + + public SimulationMetricsReporter metricsReporter() { return metrics; } diff --git a/simulation/src/main/java/com/palantir/dialogue/core/SimulationMetrics.java b/simulation/src/main/java/com/palantir/dialogue/core/SimulationMetricsReporter.java similarity index 51% rename from simulation/src/main/java/com/palantir/dialogue/core/SimulationMetrics.java rename to simulation/src/main/java/com/palantir/dialogue/core/SimulationMetricsReporter.java index b2f6fd8e9..c2b54a311 100644 --- a/simulation/src/main/java/com/palantir/dialogue/core/SimulationMetrics.java +++ b/simulation/src/main/java/com/palantir/dialogue/core/SimulationMetricsReporter.java @@ -16,28 +16,19 @@ package com.palantir.dialogue.core; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Metric; +import com.codahale.metrics.Counting; +import com.codahale.metrics.Gauge; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; import com.palantir.logsafe.Preconditions; import com.palantir.logsafe.SafeArg; -import java.io.BufferedWriter; +import com.palantir.tritium.metrics.registry.MetricName; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -50,14 +41,13 @@ import org.slf4j.LoggerFactory; /** - * This is a combination metric registry, reporter, logger and renderer, all hooked up to - * {@link Simulation#clock()}. Capable of reporting PNGs (although this is slow). + * This is a metric reporter, all hooked up to {@link Simulation#clock()}. + * Capable of reporting PNGs (although this is slow). */ -final class SimulationMetrics { - private static final Logger log = LoggerFactory.getLogger(SimulationMetrics.class); +final class SimulationMetricsReporter { + private static final Logger log = LoggerFactory.getLogger(SimulationMetricsReporter.class); private final Simulation simulation; - private Map metrics = new HashMap<>(); // each of these is a named column private final LoadingCache> measurements = @@ -65,7 +55,7 @@ final class SimulationMetrics { private static final String X_AXIS = "time_sec"; - SimulationMetrics(Simulation simulation) { + SimulationMetricsReporter(Simulation simulation) { this.simulation = simulation; } @@ -74,109 +64,32 @@ private int numMeasurements() { return (xAxis != null) ? xAxis.size() : 0; } - public Meter meter(String name) { - if (!metrics.containsKey(name)) { - Meter freshMeter = new Meter(simulation.codahaleClock()); - metrics.put(name, freshMeter); - return freshMeter; - } else { - // have to support 'get existing' because multiple servers inside a composite might be named 'node1' - Metric metric = metrics.get(name); - Preconditions.checkState( - metric instanceof Meter, "Existing metric wasn't a meter", SafeArg.of("name", name)); - return (Meter) metric; - } - } - - public Counter counter(String name) { - if (!metrics.containsKey(name)) { - Counter fresh = new Counter(); - metrics.put(name, fresh); - return fresh; - } else { - Metric metric = metrics.get(name); - Preconditions.checkState( - metric instanceof Counter, "Existing metric wasn't a Counter", SafeArg.of("name", name)); - return (Counter) metric; - } - } - - // @CheckReturnValue - // public Runnable startReporting(Duration interval) { - // metrics = ImmutableMap.copyOf(metrics); // just to make sure nobody tries to create any more after we start! - // AtomicBoolean keepRunning = new AtomicBoolean(true); - // reportInfinitely(keepRunning, interval); - // return () -> keepRunning.set(false); - // } - // - // @SuppressWarnings("FutureReturnValueIgnored") - // private void reportInfinitely(AtomicBoolean keepRunning, Duration interval) { - // report(); - // - // if (keepRunning.get()) { - // simulation.schedule( - // () -> { - // reportInfinitely(keepRunning, interval); - // return null; - // }, - // interval.toNanos(), - // TimeUnit.NANOSECONDS); - // } - // } - public void report() { - long nanos = simulation.clock().read(); - double seconds = TimeUnit.MILLISECONDS.convert(nanos, TimeUnit.NANOSECONDS) / 1000d; + simulation.taggedMetrics().forEachMetric((metricName, metric) -> { + String name = asString(metricName); - metrics.forEach((name, metric) -> { - if (metric instanceof Meter) { - measurements.get(name + ".1m").add(((Meter) metric).getOneMinuteRate()); - measurements.get(name + ".count").add((double) ((Meter) metric).getCount()); - } else if (metric instanceof Counter) { - measurements.get(name + ".count").add((double) ((Counter) metric).getCount()); - } else { - log.error("Unknown metric type {} {}", name, metric); + if (metric instanceof Counting) { // includes meters too! + measurements.get(name + ".count").add((double) ((Counting) metric).getCount()); + return; } - }); - - measurements.get(X_AXIS).add(seconds); - - // Set differentSizes = - // measurements.asMap().values().stream().map(List::size).collect(Collectors.toSet()); - // if (differentSizes.size() > 1) { - // String info = measurements.asMap().entrySet().stream() - // .map(e -> e.getKey() + ":" + e.getValue().size()) - // .collect(Collectors.joining(" ")); - // System.out.println(info); - // } - } - public void dumpCsv(Path file) { - ConcurrentMap> map = measurements.asMap(); - List xAxis = map.get(X_AXIS); - List columns = ImmutableList.copyOf(Sets.difference(map.keySet(), ImmutableSet.of(X_AXIS))); + if (metric instanceof Gauge) { + Object value = ((Gauge) metric).getValue(); + Preconditions.checkState( + value instanceof Number, + "Gauges must produce numbers", + SafeArg.of("metric", metricName), + SafeArg.of("value", value)); + measurements.get(name + ".count").add(((Number) value).doubleValue()); + return; + } - try (BufferedWriter writer = Files.newBufferedWriter( - file, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + log.error("Unknown metric type {} {}", metricName, metric); + }); - writer.write(X_AXIS); - for (String column : columns) { - writer.write(','); - writer.write(column); - } - writer.newLine(); - - for (int i = 0; i < xAxis.size(); i++) { - writer.write(Double.toString(xAxis.get(i))); - for (String column : columns) { - writer.write(','); - writer.write(Double.toString(map.get(column).get(i))); - } - writer.newLine(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } + long nanos = simulation.clock().read(); + double seconds = TimeUnit.MILLISECONDS.convert(nanos, TimeUnit.NANOSECONDS) / 1000d; + measurements.get(X_AXIS).add(seconds); } public XYChart chart(Pattern metricNameRegex) { @@ -226,6 +139,11 @@ public XYChart chart(Pattern metricNameRegex) { return chart; } + private static String asString(MetricName metricName) { + return metricName.safeTags().values().stream().map(v -> '[' + v + "] ").collect(Collectors.joining()) + + metricName.safeName(); + } + public static void png(String file, XYChart... charts) throws IOException { int rows = charts.length; int cols = 1; diff --git a/simulation/src/main/java/com/palantir/dialogue/core/SimulationServer.java b/simulation/src/main/java/com/palantir/dialogue/core/SimulationServer.java index da5661b7f..1bccc3b2c 100644 --- a/simulation/src/main/java/com/palantir/dialogue/core/SimulationServer.java +++ b/simulation/src/main/java/com/palantir/dialogue/core/SimulationServer.java @@ -46,17 +46,22 @@ final class SimulationServer implements Channel { private static final Logger log = LoggerFactory.getLogger(SimulationServer.class); private final Simulation simulation; - private final String metricName; - private final Counter globalActiveRequests; private final ImmutableList handlers; - private long cumulativeServerTimeNanos = 0; + + private final String serverName; + private final Counter activeRequests; + private final Counter globalResponses; + private final Counter globalServerTimeNanos; private SimulationServer(Builder builder) { - this.metricName = Preconditions.checkNotNull(builder.metricName, "metricName"); + this.serverName = Preconditions.checkNotNull(builder.serverName, "serverName"); this.simulation = Preconditions.checkNotNull(builder.simulation, "simulation"); - this.globalActiveRequests = simulation.metrics().counter(String.format("[%s] activeRequests", metricName)); Preconditions.checkState(!builder.handlers.isEmpty(), "Handlers can't be empty"); this.handlers = ImmutableList.copyOf(builder.handlers); + + this.activeRequests = MetricNames.activeRequests(simulation.taggedMetrics(), serverName); + this.globalResponses = MetricNames.globalResponses(simulation.taggedMetrics()); + this.globalServerTimeNanos = MetricNames.globalServerTimeNanos(simulation.taggedMetrics()); } public static Builder builder() { @@ -65,12 +70,11 @@ public static Builder builder() { @Override public ListenableFuture execute(Endpoint endpoint, Request request) { - Meter perEndpointRequests = - simulation.metrics().meter(String.format("[%s] [%s] request", metricName, endpoint.endpointName())); + Meter perEndpointRequests = MetricNames.requestMeter(simulation.taggedMetrics(), serverName, endpoint); - globalActiveRequests.inc(); + activeRequests.inc(); perEndpointRequests.mark(); - simulation.metrics().report(); + simulation.metricsReporter().report(); for (ServerHandler handler : handlers) { long beforeNanos = simulation.clock().read(); @@ -82,8 +86,9 @@ public ListenableFuture execute(Endpoint endpoint, Request request) { ListenableFuture resp = maybeResp.get(); resp.addListener( () -> { - globalActiveRequests.dec(); - cumulativeServerTimeNanos += simulation.clock().read() - beforeNanos; + globalResponses.inc(); + activeRequests.dec(); + globalServerTimeNanos.inc(simulation.clock().read() - beforeNanos); }, MoreExecutors.directExecutor()); Futures.addCallback( @@ -94,7 +99,7 @@ public void onSuccess(Response result) { log.debug( "time={} server={} status={} id={}", Duration.ofNanos(simulation.clock().read()), - metricName, + serverName, result.code(), request != null ? request.headerParams().get(Benchmark.REQUEST_ID_HEADER) : null); } @@ -108,27 +113,22 @@ public void onFailure(Throwable _throwable) {} } log.error("No handler available for request {}", request); - globalActiveRequests.dec(); + activeRequests.dec(); return Futures.immediateFailedFuture(new SafeRuntimeException("No handler")); } @Override public String toString() { - return metricName; - } - - // note this is misleading for the black_hole case, because it only increases when a task _returns_ - public Duration getCumulativeServerTime() { - return Duration.ofNanos(cumulativeServerTimeNanos); + return serverName; } public static class Builder { - private String metricName; + private String serverName; private Simulation simulation; private ImmutableList handlers = ImmutableList.of(); - Builder metricName(String value) { - metricName = value; + Builder serverName(String value) { + serverName = value; return this; } @@ -199,7 +199,13 @@ public Optional> maybeExecute( Duration responseTime = responseTimeFunction.getResponseTime(server); return Optional.of(server.simulation.schedule( - () -> responseFunction.apply(server), responseTime.toNanos(), TimeUnit.NANOSECONDS)); + () -> { + Response response = responseFunction.apply(server); + return SimulationUtils.wrapWithCloseInstrumentation( + response, server.simulation.taggedMetrics()); + }, + responseTime.toNanos(), + TimeUnit.NANOSECONDS)); } @Override @@ -226,17 +232,13 @@ public interface HandlerBuilder0 { HandlerBuilder1 response(Function func); - default HandlerBuilder1 response(Response resp) { - return response(unused -> resp); - } - default HandlerBuilder1 response(int status) { - return response(SimulationUtils.response(status, "1.0.0")); + return response(server -> SimulationUtils.response(status, "1.0.0")); } default HandlerBuilder1 respond200UntilCapacity(int errorStatus, int capacity) { return response(server -> { - if (server.globalActiveRequests.getCount() > capacity) { + if (server.activeRequests.getCount() > capacity) { return SimulationUtils.response(errorStatus, "1.0.0"); } else { return SimulationUtils.response(200, "1.0.0"); @@ -261,7 +263,7 @@ default ServerHandler responseTime(Duration duration) { default ServerHandler linearResponseTime(Duration bestCase, int capacity) { return responseTime(server -> { long expected = bestCase.toNanos(); - long inflight = server.globalActiveRequests.getCount(); + long inflight = server.activeRequests.getCount(); if (inflight > capacity) { return Duration.ofNanos(5 * expected); // above stated 'capacity', server dies a brutal death diff --git a/simulation/src/main/java/com/palantir/dialogue/core/SimulationUtils.java b/simulation/src/main/java/com/palantir/dialogue/core/SimulationUtils.java index 973d7e9b8..50a69a948 100644 --- a/simulation/src/main/java/com/palantir/dialogue/core/SimulationUtils.java +++ b/simulation/src/main/java/com/palantir/dialogue/core/SimulationUtils.java @@ -22,6 +22,7 @@ import com.palantir.dialogue.HttpMethod; import com.palantir.dialogue.Response; import com.palantir.dialogue.UrlBuilder; +import com.palantir.tritium.metrics.registry.TaggedMetricRegistry; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.List; @@ -54,6 +55,32 @@ public void close() {} }; } + public static Response wrapWithCloseInstrumentation(Response delegate, TaggedMetricRegistry registry) { + return new Response() { + @Override + public InputStream body() { + return delegate.body(); + } + + @Override + public int code() { + return delegate.code(); + } + + @Override + public Map> headers() { + return delegate.headers(); + } + + @Override + public void close() { + MetricNames.responseClose(registry).inc(); + } + }; + } + + static final String SERVICE_NAME = "svc"; + public static Endpoint endpoint(String name) { return new Endpoint() { @Override @@ -66,7 +93,7 @@ public HttpMethod httpMethod() { @Override public String serviceName() { - return "service"; + return SERVICE_NAME; } @Override diff --git a/simulation/src/main/java/com/palantir/dialogue/core/TaggedMetrics.java b/simulation/src/main/java/com/palantir/dialogue/core/TaggedMetrics.java new file mode 100644 index 000000000..3d7d60072 --- /dev/null +++ b/simulation/src/main/java/com/palantir/dialogue/core/TaggedMetrics.java @@ -0,0 +1,58 @@ +/* + * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.dialogue.core; + +import com.codahale.metrics.Clock; +import com.codahale.metrics.Counter; +import com.codahale.metrics.Meter; +import com.codahale.metrics.SlidingTimeWindowArrayReservoir; +import com.codahale.metrics.Timer; +import com.palantir.tritium.metrics.registry.AbstractTaggedMetricRegistry; +import com.palantir.tritium.metrics.registry.MetricName; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public final class TaggedMetrics extends AbstractTaggedMetricRegistry { + private final Clock clock; + + public TaggedMetrics(Clock clock) { + super(() -> new SlidingTimeWindowArrayReservoir(1, TimeUnit.DAYS, clock)); + this.clock = clock; + } + + @Override + protected Supplier meterSupplier() { + return () -> new Meter(clock); + } + + @Override + protected Supplier timerSupplier() { + return () -> new Timer(createReservoir(), clock); + } + + /** Helper method to create an untagged metric. */ + public Meter meter(String name) { + return meter(MetricName.builder().safeName(name).build()); + } + + /** Helper method to create an untagged metric. */ + public Counter counter(String name) { + return counter(MetricName.builder().safeName(name).build()); + } + + // TODO(dfox): disable methods involving MetricSets somehow, as they don't use our clock +} diff --git a/simulation/src/test/java/com/palantir/dialogue/core/SimulationTest.java b/simulation/src/test/java/com/palantir/dialogue/core/SimulationTest.java index ae3f515a8..f9747b2f2 100644 --- a/simulation/src/test/java/com/palantir/dialogue/core/SimulationTest.java +++ b/simulation/src/test/java/com/palantir/dialogue/core/SimulationTest.java @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -103,17 +104,17 @@ public void simplest_possible_case() { // real servers don't scale like this - see later tests servers = servers( SimulationServer.builder() - .metricName("fast") + .serverName("fast") .simulation(simulation) .handler(h -> h.response(200).responseTime(Duration.ofMillis(600))) .build(), SimulationServer.builder() - .metricName("medium") + .serverName("medium") .simulation(simulation) .handler(h -> h.response(200).responseTime(Duration.ofMillis(800))) .build(), SimulationServer.builder() - .metricName("slightly_slow") + .serverName("slightly_slow") .simulation(simulation) .handler(h -> h.response(200).responseTime(Duration.ofMillis(1000))) .build()); @@ -133,19 +134,19 @@ public void slowdown_and_error_thresholds() { int slowdownThreshold = 30; servers = servers( SimulationServer.builder() - .metricName("fast") + .serverName("fast") .simulation(simulation) .handler(h -> h.respond200UntilCapacity(500, errorThreshold) .linearResponseTime(Duration.ofMillis(600), slowdownThreshold)) .build(), SimulationServer.builder() - .metricName("medium") + .serverName("medium") .simulation(simulation) .handler(h -> h.respond200UntilCapacity(500, errorThreshold) .linearResponseTime(Duration.ofMillis(800), slowdownThreshold)) .build(), SimulationServer.builder() - .metricName("slightly_slow") + .serverName("slightly_slow") .simulation(simulation) .handler(h -> h.respond200UntilCapacity(500, errorThreshold) .linearResponseTime(Duration.ofMillis(1000), slowdownThreshold)) @@ -165,12 +166,12 @@ public void slow_503s_then_revert() { int capacity = 60; servers = servers( SimulationServer.builder() - .metricName("fast") + .serverName("fast") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(60), capacity)) .build(), SimulationServer.builder() - .metricName("slow_failures_then_revert") + .serverName("slow_failures_then_revert") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(60), capacity)) .until(Duration.ofSeconds(3), "slow 503s") @@ -193,12 +194,12 @@ public void fast_500s_then_revert() { int capacity = 60; servers = servers( SimulationServer.builder() - .metricName("fast") + .serverName("fast") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(60), capacity)) .build(), SimulationServer.builder() - .metricName("fast_500s_then_revert") + .serverName("fast_500s_then_revert") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(60), capacity)) .until(Duration.ofSeconds(3), "fast 500s") @@ -221,12 +222,12 @@ public void drastic_slowdown() { int capacity = 60; servers = servers( SimulationServer.builder() - .metricName("fast") + .serverName("fast") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(60), capacity)) .build(), SimulationServer.builder() - .metricName("fast_then_slow_then_fast") + .serverName("fast_then_slow_then_fast") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(60), capacity)) .until(Duration.ofSeconds(3), "slow 200s") @@ -248,14 +249,14 @@ public void drastic_slowdown() { public void all_nodes_500() { servers = servers( SimulationServer.builder() - .metricName("node1") + .serverName("node1") .simulation(simulation) .handler(h -> h.response(500).responseTime(Duration.ofMillis(600))) .until(Duration.ofSeconds(10), "revert badness") .handler(h -> h.response(200).responseTime(Duration.ofMillis(600))) .build(), SimulationServer.builder() - .metricName("node2") + .serverName("node2") .simulation(simulation) .handler(h -> h.response(500).responseTime(Duration.ofMillis(600))) .until(Duration.ofSeconds(10), "revert badness") @@ -277,12 +278,12 @@ public void all_nodes_500() { public void black_hole() { servers = servers( SimulationServer.builder() - .metricName("node1") + .serverName("node1") .simulation(simulation) .handler(h -> h.response(200).responseTime(Duration.ofMillis(600))) .build(), SimulationServer.builder() - .metricName("node2_black_hole") + .serverName("node2_black_hole") .simulation(simulation) .handler(h -> h.response(200).responseTime(Duration.ofMillis(600))) .until(Duration.ofSeconds(3), "black hole") @@ -306,7 +307,7 @@ public void one_endpoint_dies_on_each_server() { servers = servers( SimulationServer.builder() - .metricName("server_where_e1_breaks") + .serverName("server_where_e1_breaks") .simulation(simulation) .handler(endpoint1, h -> h.response(200).responseTime(Duration.ofMillis(600))) .handler(endpoint2, h -> h.response(200).responseTime(Duration.ofMillis(600))) @@ -315,7 +316,7 @@ public void one_endpoint_dies_on_each_server() { .handler(endpoint2, h -> h.response(200).responseTime(Duration.ofMillis(600))) .build(), SimulationServer.builder() - .metricName("server_where_e2_breaks") + .serverName("server_where_e2_breaks") .simulation(simulation) .handler(endpoint1, h -> h.response(200).responseTime(Duration.ofMillis(600))) .handler(endpoint2, h -> h.response(200).responseTime(Duration.ofMillis(600))) @@ -342,21 +343,21 @@ public void live_reloading() { beginAt( Duration.ZERO, SimulationServer.builder() - .metricName("always_on") + .serverName("always_on") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(600), capacity)) .build()), beginAt( Duration.ZERO, SimulationServer.builder() - .metricName("always_broken") + .serverName("always_broken") .simulation(simulation) .handler(h -> h.response(500).linearResponseTime(Duration.ofMillis(600), capacity)) .build()), beginAt( Duration.ofSeconds(5), SimulationServer.builder() - .metricName("added_halfway") + .serverName("added_halfway") .simulation(simulation) .handler(h -> h.response(200).linearResponseTime(Duration.ofMillis(600), capacity)) .build())); @@ -401,20 +402,20 @@ private Supplier> beginAt(Duration beginTime, Simulat @After public void after() throws IOException { - Duration serverCpu = Duration.ofNanos(servers.get().stream() // live-reloading breaks this :( - .mapToLong(s -> s.getCumulativeServerTime().toNanos()) - .sum()); + Duration serverCpu = Duration.ofNanos( + MetricNames.globalServerTimeNanos(simulation.taggedMetrics()).getCount()); long clientMeanNanos = (long) result.clientHistogram().getMean(); - double clientMeanMillis = TimeUnit.MICROSECONDS.convert(clientMeanNanos, TimeUnit.NANOSECONDS) / 1000d; + double clientMeanMillis = TimeUnit.MILLISECONDS.convert(clientMeanNanos, TimeUnit.NANOSECONDS); // intentionally using tabs so that opening report.txt with 'cat' aligns columns nicely String longSummary = String.format( - "success=%s%%\tclient_mean=%-15s\tserver_cpu=%-15s\treceived=%s/%s\tcodes=%s", + "success=%s%%\tclient_mean=%-15s\tserver_cpu=%-15s\tclient_received=%s/%s\tserver_resps=%s\tcodes=%s", result.successPercentage(), - Duration.ofNanos(clientMeanNanos), + Duration.of(clientMeanNanos, ChronoUnit.NANOS), serverCpu, result.numReceived(), result.numSent(), + result.numGlobalResponses(), result.statusCodes()); Path txt = Paths.get("src/test/resources/" + testName.getMethodName() + ".txt"); @@ -428,24 +429,26 @@ public void after() throws IOException { .describedAs("Run tests locally to update checked-in file: %s", txt) .isEqualTo(longSummary); assertThat(Paths.get(pngPath)).exists(); - return; - } - - if (txtChanged || !Files.exists(Paths.get(pngPath))) { + } else if (txtChanged || !Files.exists(Paths.get(pngPath))) { // only re-generate PNGs if the txt file changed (as they're slow af) Stopwatch sw = Stopwatch.createStarted(); Files.write(txt, longSummary.getBytes(StandardCharsets.UTF_8)); - XYChart activeRequests = simulation.metrics().chart(Pattern.compile("active")); + XYChart activeRequests = simulation.metricsReporter().chart(Pattern.compile("active")); activeRequests.setTitle(String.format( "%s success=%.0f%% client_mean=%.1f ms server_cpu=%s", strategy, result.successPercentage(), clientMeanMillis, serverCpu)); - XYChart serverRequestCount = simulation.metrics().chart(Pattern.compile("request.*count")); - // XYChart clientStuff = simulation.metrics().chart(Pattern.compile("(refusals|starts).count")); - SimulationMetrics.png(pngPath, activeRequests, serverRequestCount); + SimulationMetricsReporter.png( + pngPath, activeRequests, simulation.metricsReporter().chart(Pattern.compile("request.*count")) + // simulation.metrics().chart(Pattern.compile("(responseClose|globalResponses)")) + ); log.info("Generated {} ({} ms)", pngPath, sw.elapsed(TimeUnit.MILLISECONDS)); } + + assertThat(result.responsesLeaked()) + .describedAs("There should be no unclosed responses") + .isZero(); } @AfterClass diff --git a/simulation/src/test/java/com/palantir/dialogue/core/Strategy.java b/simulation/src/test/java/com/palantir/dialogue/core/Strategy.java index c9022d8dc..42cd718bd 100644 --- a/simulation/src/test/java/com/palantir/dialogue/core/Strategy.java +++ b/simulation/src/test/java/com/palantir/dialogue/core/Strategy.java @@ -23,7 +23,6 @@ import com.palantir.dialogue.Endpoint; import com.palantir.dialogue.Request; import com.palantir.dialogue.Response; -import com.palantir.tritium.metrics.registry.DefaultTaggedMetricRegistry; import java.util.List; import java.util.Optional; import java.util.function.BiFunction; @@ -55,8 +54,8 @@ private static Channel concurrencyLimiter(Simulation sim, Supplier ConcurrencyLimitedChannel.createLimiter(sim.clock()))) .collect(Collectors.toList()); LimitedChannel limited1 = new RoundRobinChannel(limitedChannels1); - limited1 = instrumentClient(limited1, sim.metrics()); // just for debugging - Channel channel = new QueuedChannel(limited1, DispatcherMetrics.of(new DefaultTaggedMetricRegistry())); + limited1 = instrumentClient(limited1, sim.taggedMetrics()); // just for debugging + Channel channel = new QueuedChannel(limited1, DispatcherMetrics.of(sim.taggedMetrics())); return new RetryingChannel(channel); }); } @@ -66,13 +65,14 @@ private static Channel roundRobin(Simulation sim, Supplier limitedChannels = channels.stream().map(Strategy::noOpLimitedChannel).collect(Collectors.toList()); LimitedChannel limited = new RoundRobinChannel(limitedChannels); - limited = instrumentClient(limited, sim.metrics()); // will always be zero due to the noOpLimitedChannel - Channel channel = new QueuedChannel(limited, DispatcherMetrics.of(new DefaultTaggedMetricRegistry())); + limited = + instrumentClient(limited, sim.taggedMetrics()); // will always be zero due to the noOpLimitedChannel + Channel channel = new QueuedChannel(limited, DispatcherMetrics.of(sim.taggedMetrics())); return new RetryingChannel(channel); }); } - private static LimitedChannel instrumentClient(LimitedChannel delegate, SimulationMetrics metrics) { + private static LimitedChannel instrumentClient(LimitedChannel delegate, TaggedMetrics metrics) { Meter starts = metrics.meter("test_client.starts"); Counter metric = metrics.counter("test_client.refusals"); return new LimitedChannel() { diff --git a/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].png index b8968530e..3113fdbe9 100644 --- a/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68dc5387af352d2f5253099dd08c3c582b3ca2d771e80a9c5c80449aaed52ecb -size 99033 +oid sha256:e54131078c639b1dda767c85804f041d564ac5383700ed71b681fe5fc015634f +size 99081 diff --git a/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].txt index 904a41041..b954222f5 100644 --- a/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/all_nodes_500[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=50.0% client_mean=PT0.6S server_cpu=PT2M received=200/200 codes={200=100, 500=100} \ No newline at end of file +success=50.0% client_mean=PT0.6S server_cpu=PT2M client_received=200/200 server_resps=200 codes={200=100, 500=100} \ No newline at end of file diff --git a/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].png b/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].png index 87ab99989..c4f9bcd7b 100644 --- a/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].png +++ b/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4cfc5435c55e9aa856f2f00b1aa644ea5ea4fda839f7a07d7a24429dae611e15 -size 98402 +oid sha256:ce5300cfd78cca8d0346a5fc5d4cea241c2bc27eb04cd3aaed8ee3163d56b60e +size 98449 diff --git a/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].txt b/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].txt index 904a41041..b954222f5 100644 --- a/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/all_nodes_500[ROUND_ROBIN].txt @@ -1 +1 @@ -success=50.0% client_mean=PT0.6S server_cpu=PT2M received=200/200 codes={200=100, 500=100} \ No newline at end of file +success=50.0% client_mean=PT0.6S server_cpu=PT2M client_received=200/200 server_resps=200 codes={200=100, 500=100} \ No newline at end of file diff --git a/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].png index 467cce4ea..84db6a634 100644 --- a/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc5ab96859759fa0a9187b34d922e18cae3c7314a4f45f743687b5fa1b27799b -size 87383 +oid sha256:a332af55dce97d8cc845f7a6291616595a547cc350bc52471e86197a18a7886f +size 87447 diff --git a/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].txt index ab490d3f0..dfb6ec6b6 100644 --- a/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/black_hole[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=90.0% client_mean=PT0.6S server_cpu=PT1M48S received=180/200 codes={200=180} \ No newline at end of file +success=90.0% client_mean=PT0.6S server_cpu=PT1M48S client_received=180/200 server_resps=180 codes={200=180} \ No newline at end of file diff --git a/simulation/src/test/resources/black_hole[ROUND_ROBIN].png b/simulation/src/test/resources/black_hole[ROUND_ROBIN].png index 9e3918136..a96db2114 100644 --- a/simulation/src/test/resources/black_hole[ROUND_ROBIN].png +++ b/simulation/src/test/resources/black_hole[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71281c1858647123856da136bdc48499bb2fc6097d011dc481bec712625d4a12 -size 84686 +oid sha256:d1aaf348dca344414eaffcb3fdc2e1d24eb982464a9d9be894dbb421fbe37a82 +size 84765 diff --git a/simulation/src/test/resources/black_hole[ROUND_ROBIN].txt b/simulation/src/test/resources/black_hole[ROUND_ROBIN].txt index 75f764339..77df1ba4e 100644 --- a/simulation/src/test/resources/black_hole[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/black_hole[ROUND_ROBIN].txt @@ -1 +1 @@ -success=65.0% client_mean=PT0.6S server_cpu=PT1M18S received=130/200 codes={200=130} \ No newline at end of file +success=65.0% client_mean=PT0.6S server_cpu=PT1M18S client_received=130/200 server_resps=130 codes={200=130} \ No newline at end of file diff --git a/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].png index ba1ba7bbb..f5e408c8b 100644 --- a/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af7bde8f916b52cb39fdccd251611ae793b6f62e954bfa21c4a8c38c1c258dac -size 92473 +oid sha256:59a1c274da5dfa4fc4384ddcbb237d475aa767bacaa391de483fd29a740988ff +size 92430 diff --git a/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].txt index 755cb4fa4..52d5b5d63 100644 --- a/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/drastic_slowdown[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=100.0% client_mean=PT0.131675583S server_cpu=PT8M46.702333319S received=4000/4000 codes={200=4000} \ No newline at end of file +success=100.0% client_mean=PT0.131675583S server_cpu=PT8M46.702333319S client_received=4000/4000 server_resps=4000 codes={200=4000} \ No newline at end of file diff --git a/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].png b/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].png index 3a2d98fcc..c616d1c32 100644 --- a/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].png +++ b/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aad22a0683eb9bf2e5a5856eb0108e51a31bb3e3229d6e0e8aa6fad4f9e6777f -size 89971 +oid sha256:289d424bc94ceb5bdd7f4ea8368ec39c00eb100afb6b9e879bde14d28a73e9fd +size 89893 diff --git a/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].txt b/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].txt index 5e045c66a..6f7ee3018 100644 --- a/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/drastic_slowdown[ROUND_ROBIN].txt @@ -1 +1 @@ -success=100.0% client_mean=PT8.340639499S server_cpu=PT9H16M2.557999978S received=4000/4000 codes={200=4000} \ No newline at end of file +success=100.0% client_mean=PT8.340639499S server_cpu=PT9H16M2.557999978S client_received=4000/4000 server_resps=4000 codes={200=4000} \ No newline at end of file diff --git a/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].png index 2774f1416..3917988dd 100644 --- a/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5a335e1b6868a06bfe3550c077988fad5e7aca46fbe5c5f854b2140f50c6bc1e -size 80931 +oid sha256:95b61286b8da213f046840fa9d19a74f5b0358b3caa023d483a7cff65f7b902f +size 80948 diff --git a/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].txt index eebb1a6a7..6ecb07372 100644 --- a/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/fast_500s_then_revert[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S received=3750/3750 codes={200=2875, 500=875} \ No newline at end of file +success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S client_received=3750/3750 server_resps=3750 codes={200=2875, 500=875} \ No newline at end of file diff --git a/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].png b/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].png index 3fa7fab2e..832cd5d90 100644 --- a/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].png +++ b/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae2c12d4faf72bb6c881d3cdfa312dd7b79c534f924248a97c8d3f347974c076 -size 80384 +oid sha256:68954c4f06e9e8258af42029f22045e801c157643b7de77c3e6205e9c4e3bb81 +size 80401 diff --git a/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].txt b/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].txt index eebb1a6a7..6ecb07372 100644 --- a/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/fast_500s_then_revert[ROUND_ROBIN].txt @@ -1 +1 @@ -success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S received=3750/3750 codes={200=2875, 500=875} \ No newline at end of file +success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S client_received=3750/3750 server_resps=3750 codes={200=2875, 500=875} \ No newline at end of file diff --git a/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].png index 7c90ae171..5d46e0322 100644 --- a/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e58363c0396a0482969f57ee044b0a5c9899cb7e384a7e816c02190d90018f7 -size 130098 +oid sha256:c0603aea0b59e45b62a72f97d100dc8e60398e37986bc03be0bf55bf93eee54b +size 130123 diff --git a/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].txt index 9bcad841c..8faf2b58a 100644 --- a/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/live_reloading[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S received=400/400 codes={200=233, 500=167} \ No newline at end of file +success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S client_received=400/400 server_resps=400 codes={200=233, 500=167} \ No newline at end of file diff --git a/simulation/src/test/resources/live_reloading[ROUND_ROBIN].png b/simulation/src/test/resources/live_reloading[ROUND_ROBIN].png index fb41b6f2e..cbc4b7025 100644 --- a/simulation/src/test/resources/live_reloading[ROUND_ROBIN].png +++ b/simulation/src/test/resources/live_reloading[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2cdab85f8ae1a462336e26a59d9a2417773e33f14955f694d39d0a2e807b2e2 -size 129604 +oid sha256:ebe589a1f0a9aa2a0d9b1ca27bafac8fae2db23f521f466390c666528c35d4ff +size 129638 diff --git a/simulation/src/test/resources/live_reloading[ROUND_ROBIN].txt b/simulation/src/test/resources/live_reloading[ROUND_ROBIN].txt index 9bcad841c..8faf2b58a 100644 --- a/simulation/src/test/resources/live_reloading[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/live_reloading[ROUND_ROBIN].txt @@ -1 +1 @@ -success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S received=400/400 codes={200=233, 500=167} \ No newline at end of file +success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S client_received=400/400 server_resps=400 codes={200=233, 500=167} \ No newline at end of file diff --git a/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].png index ddb881e78..fc4d6f545 100644 --- a/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68c5858b434c83e2c3a0f8b86f07d868d681ee517d43cfcc6287a36da9cc0ddb -size 135422 +oid sha256:daa54dc0063cf32bc1d135e9747d06dca1c7fadea2730ae0d9215c248663b2c0 +size 135506 diff --git a/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].txt index eb682e056..3a4566ae7 100644 --- a/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=67.6% client_mean=PT0.6S server_cpu=PT5M6S received=510/510 codes={200=345, 500=165} \ No newline at end of file +success=67.6% client_mean=PT0.6S server_cpu=PT5M6S client_received=510/510 server_resps=510 codes={200=345, 500=165} \ No newline at end of file diff --git a/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].png b/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].png index 496e0893d..00725f102 100644 --- a/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].png +++ b/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:932c5f552c89583fbd76c8662a3714cee596695fed0d2fb50c63f401f2a7bee6 -size 134850 +oid sha256:8b2b17c3292d903bf786a64452807461795ee6c106eca63c252ea5a1848506fb +size 134938 diff --git a/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].txt b/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].txt index eb682e056..3a4566ae7 100644 --- a/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/one_endpoint_dies_on_each_server[ROUND_ROBIN].txt @@ -1 +1 @@ -success=67.6% client_mean=PT0.6S server_cpu=PT5M6S received=510/510 codes={200=345, 500=165} \ No newline at end of file +success=67.6% client_mean=PT0.6S server_cpu=PT5M6S client_received=510/510 server_resps=510 codes={200=345, 500=165} \ No newline at end of file diff --git a/simulation/src/test/resources/report.md b/simulation/src/test/resources/report.md index ab2c231ba..4e049ad71 100644 --- a/simulation/src/test/resources/report.md +++ b/simulation/src/test/resources/report.md @@ -1,24 +1,24 @@ # Report ``` - all_nodes_500[CONCURRENCY_LIMITER].txt: success=50.0% client_mean=PT0.6S server_cpu=PT2M received=200/200 codes={200=100, 500=100} - all_nodes_500[ROUND_ROBIN].txt: success=50.0% client_mean=PT0.6S server_cpu=PT2M received=200/200 codes={200=100, 500=100} - black_hole[CONCURRENCY_LIMITER].txt: success=90.0% client_mean=PT0.6S server_cpu=PT1M48S received=180/200 codes={200=180} - black_hole[ROUND_ROBIN].txt: success=65.0% client_mean=PT0.6S server_cpu=PT1M18S received=130/200 codes={200=130} - drastic_slowdown[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT0.131675583S server_cpu=PT8M46.702333319S received=4000/4000 codes={200=4000} - drastic_slowdown[ROUND_ROBIN].txt: success=100.0% client_mean=PT8.340639499S server_cpu=PT9H16M2.557999978S received=4000/4000 codes={200=4000} - fast_500s_then_revert[CONCURRENCY_LIMITER].txt: success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S received=3750/3750 codes={200=2875, 500=875} - fast_500s_then_revert[ROUND_ROBIN].txt: success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S received=3750/3750 codes={200=2875, 500=875} - live_reloading[CONCURRENCY_LIMITER].txt: success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S received=400/400 codes={200=233, 500=167} - live_reloading[ROUND_ROBIN].txt: success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S received=400/400 codes={200=233, 500=167} - one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].txt: success=67.6% client_mean=PT0.6S server_cpu=PT5M6S received=510/510 codes={200=345, 500=165} - one_endpoint_dies_on_each_server[ROUND_ROBIN].txt: success=67.6% client_mean=PT0.6S server_cpu=PT5M6S received=510/510 codes={200=345, 500=165} - simplest_possible_case[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S received=1000/1000 codes={200=1000} - simplest_possible_case[ROUND_ROBIN].txt: success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S received=1000/1000 codes={200=1000} - slow_503s_then_revert[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT0.129949111S server_cpu=PT6M29.847333275S received=3000/3000 codes={200=3000} - slow_503s_then_revert[ROUND_ROBIN].txt: success=100.0% client_mean=PT1.408771222S server_cpu=PT1H10M26.313666644S received=3000/3000 codes={200=3000} - slowdown_and_error_thresholds[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT1.977419999S server_cpu=PT31M8.473333135S received=1000/1000 codes={200=1000} - slowdown_and_error_thresholds[ROUND_ROBIN].txt: success=77.1% client_mean=PT2.231446666S server_cpu=PT37M11.446666464S received=1000/1000 codes={200=771, 500=229} + all_nodes_500[CONCURRENCY_LIMITER].txt: success=50.0% client_mean=PT0.6S server_cpu=PT2M client_received=200/200 server_resps=200 codes={200=100, 500=100} + all_nodes_500[ROUND_ROBIN].txt: success=50.0% client_mean=PT0.6S server_cpu=PT2M client_received=200/200 server_resps=200 codes={200=100, 500=100} + black_hole[CONCURRENCY_LIMITER].txt: success=90.0% client_mean=PT0.6S server_cpu=PT1M48S client_received=180/200 server_resps=180 codes={200=180} + black_hole[ROUND_ROBIN].txt: success=65.0% client_mean=PT0.6S server_cpu=PT1M18S client_received=130/200 server_resps=130 codes={200=130} + drastic_slowdown[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT0.131675583S server_cpu=PT8M46.702333319S client_received=4000/4000 server_resps=4000 codes={200=4000} + drastic_slowdown[ROUND_ROBIN].txt: success=100.0% client_mean=PT8.340639499S server_cpu=PT9H16M2.557999978S client_received=4000/4000 server_resps=4000 codes={200=4000} + fast_500s_then_revert[CONCURRENCY_LIMITER].txt: success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S client_received=3750/3750 server_resps=3750 codes={200=2875, 500=875} + fast_500s_then_revert[ROUND_ROBIN].txt: success=76.7% client_mean=PT0.055281733S server_cpu=PT3M27.306499709S client_received=3750/3750 server_resps=3750 codes={200=2875, 500=875} + live_reloading[CONCURRENCY_LIMITER].txt: success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S client_received=400/400 server_resps=400 codes={200=233, 500=167} + live_reloading[ROUND_ROBIN].txt: success=58.3% client_mean=PT0.7228S server_cpu=PT4M49.12S client_received=400/400 server_resps=400 codes={200=233, 500=167} + one_endpoint_dies_on_each_server[CONCURRENCY_LIMITER].txt: success=67.6% client_mean=PT0.6S server_cpu=PT5M6S client_received=510/510 server_resps=510 codes={200=345, 500=165} + one_endpoint_dies_on_each_server[ROUND_ROBIN].txt: success=67.6% client_mean=PT0.6S server_cpu=PT5M6S client_received=510/510 server_resps=510 codes={200=345, 500=165} + simplest_possible_case[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S client_received=1000/1000 server_resps=1000 codes={200=1000} + simplest_possible_case[ROUND_ROBIN].txt: success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S client_received=1000/1000 server_resps=1000 codes={200=1000} + slow_503s_then_revert[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT0.129949111S server_cpu=PT6M29.847333275S client_received=3000/3000 server_resps=3130 codes={200=3000} + slow_503s_then_revert[ROUND_ROBIN].txt: success=100.0% client_mean=PT1.408771222S server_cpu=PT1H10M26.313666644S client_received=3000/3000 server_resps=3809 codes={200=3000} + slowdown_and_error_thresholds[CONCURRENCY_LIMITER].txt: success=100.0% client_mean=PT1.977419999S server_cpu=PT31M8.473333135S client_received=1000/1000 server_resps=1000 codes={200=1000} + slowdown_and_error_thresholds[ROUND_ROBIN].txt: success=77.1% client_mean=PT2.231446666S server_cpu=PT37M11.446666464S client_received=1000/1000 server_resps=1000 codes={200=771, 500=229} ``` diff --git a/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].png index e5819cf34..842677f5e 100644 --- a/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e58150714156206021ee47bb1ae1b383c056243b796ecad770183e353a18efe -size 111612 +oid sha256:6c037dc2aed3bfd180e4f97a6d8cfa80760828f9b70176d8791cb06b3b5c1f2f +size 111561 diff --git a/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].txt index 1ec3c6a47..3dc7d982a 100644 --- a/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/simplest_possible_case[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S received=1000/1000 codes={200=1000} \ No newline at end of file +success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S client_received=1000/1000 server_resps=1000 codes={200=1000} \ No newline at end of file diff --git a/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].png b/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].png index efa1cc117..eea991473 100644 --- a/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].png +++ b/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0bfd66cf8d7211aa48d6773988a63c71a10d31a228a6b696a012387dd1c45f8c -size 111083 +oid sha256:401183280dc88092e13596c3d90d18889a710d12075e368872109a8fff88ea3f +size 111025 diff --git a/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].txt b/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].txt index 1ec3c6a47..3dc7d982a 100644 --- a/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/simplest_possible_case[ROUND_ROBIN].txt @@ -1 +1 @@ -success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S received=1000/1000 codes={200=1000} \ No newline at end of file +success=100.0% client_mean=PT0.7998S server_cpu=PT13M19.8S client_received=1000/1000 server_resps=1000 codes={200=1000} \ No newline at end of file diff --git a/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].png index 67fed09a8..2fa11d972 100644 --- a/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea5a60e5c549a993cd6927d036d04d4c10bdeb39f8d98f66301673ffa1a24c9d -size 94865 +oid sha256:1be426894e79e54cd828df724bfbaaf981a3f2119bb94db6b5d878fb78cc15dd +size 94815 diff --git a/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].txt index 21947144b..ccacc3464 100644 --- a/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/slow_503s_then_revert[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=100.0% client_mean=PT0.129949111S server_cpu=PT6M29.847333275S received=3000/3000 codes={200=3000} \ No newline at end of file +success=100.0% client_mean=PT0.129949111S server_cpu=PT6M29.847333275S client_received=3000/3000 server_resps=3130 codes={200=3000} \ No newline at end of file diff --git a/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].png b/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].png index 7ce283efb..6db99ccab 100644 --- a/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].png +++ b/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9f3db44713c4215cca1f7b573be68aa2074eb990581bd55bbbb05485505f7aa -size 87163 +oid sha256:7c2c39ff6832b9c87700c6e3f277219834b4e2f967d14f5bc912e0a882a7280a +size 87158 diff --git a/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].txt b/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].txt index 82de04ecd..09840cb59 100644 --- a/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/slow_503s_then_revert[ROUND_ROBIN].txt @@ -1 +1 @@ -success=100.0% client_mean=PT1.408771222S server_cpu=PT1H10M26.313666644S received=3000/3000 codes={200=3000} \ No newline at end of file +success=100.0% client_mean=PT1.408771222S server_cpu=PT1H10M26.313666644S client_received=3000/3000 server_resps=3809 codes={200=3000} \ No newline at end of file diff --git a/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].png b/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].png index 6158fe4d2..c6cac6094 100644 --- a/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].png +++ b/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e5f0a066a7e39a87d1bec49d39ffe7c52dc9ab0bfa1ad642d86a31196e8b5f9 -size 148757 +oid sha256:4321f1293e26c8a5fd88c5238be72e65900892c6ed04399aa080d8c8bbb25d62 +size 148785 diff --git a/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].txt b/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].txt index 234cc2c2f..0b1abc998 100644 --- a/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].txt +++ b/simulation/src/test/resources/slowdown_and_error_thresholds[CONCURRENCY_LIMITER].txt @@ -1 +1 @@ -success=100.0% client_mean=PT1.977419999S server_cpu=PT31M8.473333135S received=1000/1000 codes={200=1000} \ No newline at end of file +success=100.0% client_mean=PT1.977419999S server_cpu=PT31M8.473333135S client_received=1000/1000 server_resps=1000 codes={200=1000} \ No newline at end of file diff --git a/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].png b/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].png index 21413f00d..79c79ea02 100644 --- a/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].png +++ b/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68073490ca3f7b3d3923bad49e781f2db90dd6156b7482cce80f7f5d92c0ace7 -size 113559 +oid sha256:74506b045bfa2b89059d86a40f5fe41f28e01335e6d7e2769c763f3b37f3e052 +size 113569 diff --git a/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].txt b/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].txt index f009c1276..e33c48eb1 100644 --- a/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].txt +++ b/simulation/src/test/resources/slowdown_and_error_thresholds[ROUND_ROBIN].txt @@ -1 +1 @@ -success=77.1% client_mean=PT2.231446666S server_cpu=PT37M11.446666464S received=1000/1000 codes={200=771, 500=229} \ No newline at end of file +success=77.1% client_mean=PT2.231446666S server_cpu=PT37M11.446666464S client_received=1000/1000 server_resps=1000 codes={200=771, 500=229} \ No newline at end of file