diff options
-rw-r--r-- | config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java | 94 |
1 files changed, 61 insertions, 33 deletions
diff --git a/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java b/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java index 182c30a0ece..26c5889c579 100644 --- a/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java +++ b/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java @@ -36,7 +36,7 @@ import java.util.concurrent.ThreadLocalRandom; import static com.yahoo.vespa.config.ConfigKey.createFull; /** - * A config client for generating load against a config server or config proxy. + * A client for generating load (config requests) against a config server or config proxy. * <p> * Log messages from a run will have a # first in the line, the end result will not. * @@ -44,13 +44,30 @@ import static com.yahoo.vespa.config.ConfigKey.createFull; */ public class LoadTester { - private static boolean debug = false; private final Transport transport = new Transport("rpc-client"); protected Supervisor supervisor = new Supervisor(transport); private List<ConfigKey<?>> configs = new ArrayList<>(); private Map<ConfigDefinitionKey, Tuple2<String, String[]>> defs = new HashMap<>(); private final CompressionType compressionType = JRTConfigRequestFactory.getCompressionType(); + private final String host; + private final int port; + private final int iterations; + private final int threads; + private final String configFile; + private final String defPath; + private final boolean debug; + + LoadTester(String host, int port, int iterations, int threads, String configFile, String defPath, boolean debug) { + this.host = host; + this.port = port; + this.iterations = iterations; + this.threads = threads; + this.configFile = configFile; + this.defPath = defPath; + this.debug = debug; + } + /** * @param args command-line arguments */ @@ -61,27 +78,29 @@ public class LoadTester { parser.addRequiredBinarySwitch("-p", "port"); parser.addRequiredBinarySwitch("-i", "iterations per thread"); parser.addRequiredBinarySwitch("-t", "threads"); - parser.addLegalBinarySwitch("-l", "configs file, on form name,configid. (To get list: vespa-configproxy-cmd -m cache | cut -d ',' -f1-2)"); + parser.addLegalBinarySwitch("-l", "config file, on form name,configid. (To get list: vespa-configproxy-cmd -m cache | cut -d ',' -f1-2)"); parser.addLegalBinarySwitch("-dd", "dir with def files, must be of form name.def"); parser.parse(); String host = parser.getBinarySwitches().get("-c"); int port = Integer.parseInt(parser.getBinarySwitches().get("-p")); int iterations = Integer.parseInt(parser.getBinarySwitches().get("-i")); int threads = Integer.parseInt(parser.getBinarySwitches().get("-t")); - String configsList = parser.getBinarySwitches().get("-l"); + String configFile = parser.getBinarySwitches().get("-l"); String defPath = parser.getBinarySwitches().get("-dd"); - debug = parser.getUnarySwitches().contains("-d"); - new LoadTester().runLoad(host, port, iterations, threads, configsList, defPath); + boolean debug = parser.getUnarySwitches().contains("-d"); + new LoadTester(host, port, iterations, threads, configFile, defPath, debug) + .runLoad(); } - private void runLoad(String host, int port, int iterations, int threads, - String configsList, String defPath) throws IOException, InterruptedException { - configs = readConfigs(configsList); + private void runLoad() throws IOException, InterruptedException { + configs = readConfigs(configFile); defs = readDefs(defPath); + validateConfigs(configs, defs); + List<LoadThread> threadList = new ArrayList<>(); - long startInNanos = System.nanoTime(); Metrics m = new Metrics(); + long startInNanos = System.nanoTime(); for (int i = 0; i < threads; i++) { LoadThread lt = new LoadThread(iterations, host, port); threadList.add(lt); @@ -92,7 +111,9 @@ public class LoadTester { lt.join(); m.merge(lt.metrics); } - printOutput(startInNanos, threads, iterations, m); + float durationInSeconds = (float) (System.nanoTime() - startInNanos) / 1_000_000_000f; + + printResults(durationInSeconds, threads, iterations, m); } private Map<ConfigDefinitionKey, Tuple2<String, String[]>> readDefs(String defPath) throws IOException { @@ -122,11 +143,10 @@ public class LoadTester { return ret; } - private void printOutput(long startInNanos, long threads, long iterations, Metrics metrics) { - float durSec = (float) (System.nanoTime() - startInNanos) / 1_000_000_000f; + private void printResults(float durationInSeconds, long threads, long iterations, Metrics metrics) { StringBuilder sb = new StringBuilder(); sb.append("#reqs/sec #avglatency #minlatency #maxlatency #failedrequests\n"); - sb.append(((float) (iterations * threads)) / durSec).append(","); + sb.append(((float) (iterations * threads)) / durationInSeconds).append(","); sb.append((metrics.latencyInMillis / threads / iterations)).append(","); sb.append((metrics.minLatency)).append(","); sb.append((metrics.maxLatency)).append(","); @@ -151,6 +171,16 @@ public class LoadTester { return ret; } + private void validateConfigs(List<ConfigKey<?>> configs, Map<ConfigDefinitionKey, Tuple2<String, String[]>> defs) { + for (ConfigKey<?> configKey : configs) { + ConfigDefinitionKey dKey = new ConfigDefinitionKey(configKey); + Tuple2<String, String[]> defContent = defs.get(dKey); + if (defContent == null) + throw new IllegalArgumentException("No matching config definition for " + configKey + + ", known config definitions: " + defs.keySet()); + } + } + private static class Metrics { long latencyInMillis = 0; @@ -189,34 +219,28 @@ public class LoadTester { private class LoadThread extends Thread { private final int iterations; - private final String host; - private final int port; + private final Spec spec; private final Metrics metrics = new Metrics(); LoadThread(int iterations, String host, int port) { this.iterations = iterations; - this.host = host; - this.port = port; + this.spec = new Spec(host, port); } @Override public void run() { - Spec spec = new Spec(host, port); Target target = connect(spec); - + int numberOfConfigs = configs.size(); for (int i = 0; i < iterations; i++) { - ConfigKey<?> reqKey = configs.get(ThreadLocalRandom.current().nextInt(configs.size())); - ConfigDefinitionKey dKey = new ConfigDefinitionKey(reqKey); - Tuple2<String, String[]> defContent = defs.get(dKey); - if (defContent == null && defs.size() > 0) { // Only complain if we actually did run with a def dir - System.out.println("# No def found for " + dKey + ", not sending in request."); - } - ConfigKey<?> configKey = createFull(reqKey.getName(), reqKey.getConfigId(), reqKey.getNamespace(), defContent.first); - JRTClientConfigRequest request = createRequest(configKey, defContent.second); - if (debug) System.out.println("# Requesting: " + reqKey); + ConfigKey<?> reqKey = configs.get(ThreadLocalRandom.current().nextInt(numberOfConfigs)); + JRTClientConfigRequest request = createRequest(reqKey); + if (debug) + System.out.println("# Requesting: " + reqKey); + long start = System.nanoTime(); target.invokeSync(request.getRequest(), 10.0); long durationInMillis = (System.nanoTime() - start) / 1_000_000; + if (request.isError()) { target = handleError(request, spec, target); } else { @@ -225,11 +249,15 @@ public class LoadTester { } } - private JRTClientConfigRequest createRequest(ConfigKey<?> reqKey, String[] defContent) { - if (defContent == null) defContent = new String[0]; + private JRTClientConfigRequest createRequest(ConfigKey<?> reqKey) { + ConfigDefinitionKey dKey = new ConfigDefinitionKey(reqKey); + Tuple2<String, String[]> defContent = defs.get(dKey); + ConfigKey<?> fullKey = createFull(reqKey.getName(), reqKey.getConfigId(), reqKey.getNamespace(), defContent.first); + final long serverTimeout = 1000; - return JRTClientConfigRequestV3.createWithParams(reqKey, DefContent.fromList(Arrays.asList(defContent)), - ConfigUtils.getCanonicalHostName(), "", 0, serverTimeout, Trace.createDummy(), + return JRTClientConfigRequestV3.createWithParams(fullKey, DefContent.fromList(List.of(defContent.second)), + ConfigUtils.getCanonicalHostName(), "", + 0, serverTimeout, Trace.createDummy(), compressionType, Optional.empty()); } |