// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.feed.perf; import com.yahoo.messagebus.routing.Route; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; /** * @author Simon Thoresen Hult */ class FeederParams { private static final int BUFFER_SIZE = 0x100000; enum DumpFormat {JSON, VESPA} private PrintStream stdErr = System.err; private PrintStream stdOut = System.out; private Route route = Route.parse("default"); private String configId = "client"; private OutputStream dumpStream = null; private DumpFormat dumpFormat = DumpFormat.JSON; private boolean benchmarkMode = false; private int numDispatchThreads = 1; private int maxPending = 0; private double timeout = 180.0; private double windowSizeBackOff = 0.95; private double windowDecrementFactor = 1.2; private double windowResizeRate = 3; private int windowIncrementSize = 20; private int numConnectionsPerTarget = 1; private long numMessagesToSend = Long.MAX_VALUE; private List inputStreams = new ArrayList<>(); FeederParams() { inputStreams.add(System.in); } PrintStream getStdErr() { return stdErr; } FeederParams setStdErr(PrintStream stdErr) { this.stdErr = stdErr; return this; } PrintStream getStdOut() { return stdOut; } FeederParams setStdOut(PrintStream stdOut) { this.stdOut = stdOut; return this; } Route getRoute() { return route; } OutputStream getDumpStream() { return dumpStream; } FeederParams setDumpStream(OutputStream dumpStream) { this.dumpStream = dumpStream; return this; } DumpFormat getDumpFormat() { return dumpFormat; } FeederParams setDumpFormat(DumpFormat dumpFormat) { this.dumpFormat = dumpFormat; return this; } String getConfigId() { return configId; } FeederParams setConfigId(String configId) { this.configId = configId; return this; } public double getWindowSizeBackOff() { return windowSizeBackOff; } public double getWindowDecrementFactor() { return windowDecrementFactor; } public double getWindowResizeRate() { return windowResizeRate; } public double getTimeout() { return timeout; } public int getWindowIncrementSize() { return windowIncrementSize; } int getNumConnectionsPerTarget() { return numConnectionsPerTarget; } long getNumMessagesToSend() { return numMessagesToSend; } boolean isSerialTransferEnabled() { return maxPending == 1; } FeederParams setSerialTransfer() { maxPending = 1; numDispatchThreads = 1; return this; } List getInputStreams() { return inputStreams; } FeederParams setInputStreams(List inputStreams) { this.inputStreams = inputStreams; return this; } int getNumDispatchThreads() { return numDispatchThreads; } int getMaxPending() { return maxPending; } boolean isBenchmarkMode() { return benchmarkMode; } FeederParams parseArgs(String... args) throws ParseException, FileNotFoundException { Options opts = new Options(); opts.addOption("s", "serial", false, "use serial transfer mode, at most 1 pending operation and a single thread"); opts.addOption("n", "numthreads", true, "Number of clients for sending messages. Anything, but 1 will bypass sequencing by document id."); opts.addOption("m", "maxpending", true, "Max number of inflights messages. Default is auto."); opts.addOption("r", "route", true, "Route for sending messages. default is 'default'...."); opts.addOption("b", "mode", true, "Mode for benchmarking."); opts.addOption("o", "output", true, "File to write to. Extensions gives format (.xml, .json, .vespa) json will be produced if no extension."); opts.addOption("c", "numconnections", true, "Number of connections per host."); opts.addOption("t", "timeout", true, "Timeout for a message in seconds. default = " + timeout); opts.addOption("l", "nummessages", true, "Number of messages to send (all is default)."); opts.addOption("wi", "window_incrementsize", true, "Dynamic window increment step size. default = " + windowIncrementSize); opts.addOption("wd", "window_decrementfactor", true, "Dynamic window decrement step size factor. default = " + windowDecrementFactor); opts.addOption("wb", "window_backoffactor", true, "Dynamic window backoff factor. default = " + windowSizeBackOff); opts.addOption("wr", "window_resizerate", true, "Dynamic window resize rate. default = " + windowResizeRate); CommandLine cmd = new DefaultParser().parse(opts, args); if (cmd.hasOption('n')) { numDispatchThreads = Integer.valueOf(cmd.getOptionValue('n').trim()); } if (cmd.hasOption('m')) { maxPending = Integer.valueOf(cmd.getOptionValue('m').trim()); } if (cmd.hasOption('c')) { numConnectionsPerTarget = Integer.valueOf(cmd.getOptionValue('c').trim()); } if (cmd.hasOption("wi")) { windowIncrementSize = Integer.valueOf(cmd.getOptionValue("wi").trim()); } if (cmd.hasOption("wd")) { windowDecrementFactor = Double.valueOf(cmd.getOptionValue("wd").trim()); } if (cmd.hasOption("wb")) { windowSizeBackOff = Double.valueOf(cmd.getOptionValue("wb").trim()); } if (cmd.hasOption("wr")) { windowResizeRate = Double.valueOf(cmd.getOptionValue("wr").trim()); } if (cmd.hasOption('r')) { route = Route.parse(cmd.getOptionValue('r').trim()); } if (cmd.hasOption("t")) { timeout = Double.valueOf(cmd.getOptionValue("t").trim()); } benchmarkMode = cmd.hasOption('b'); if (cmd.hasOption('o')) { String fileName = cmd.getOptionValue('o').trim(); dumpStream = new FileOutputStream(new File(fileName)); if (fileName.endsWith(".vespa")) { dumpFormat = DumpFormat.VESPA; } } if (cmd.hasOption('s')) { setSerialTransfer(); } if (cmd.hasOption('l')) { numMessagesToSend = Long.valueOf(cmd.getOptionValue('l').trim()); } if ( !cmd.getArgList().isEmpty()) { inputStreams.clear(); for (String fileName : cmd.getArgList()) { inputStreams.add(new BufferedInputStream(new FileInputStream(new File(fileName)), BUFFER_SIZE)); } } return this; } }