package com.ning.pummel.cli; import com.google.common.collect.Lists; import org.apache.commons.math.stat.descriptive.DescriptiveStatistics; import org.skife.cli.Arguments; import org.skife.cli.Command; import org.skife.cli.Option; import com.ning.pummel.Fight; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.List; import java.util.concurrent.Callable; @Command(name = "limit", description = "find the lowest concurrency level at which response times stay below a threshold at a certain percentile") public class Limit implements Callable<Void> { @Option(name = {"-m", "--max"}, title = "max-requests", description = "Maximum number of requests to execute") public int maxRequests = -1; @Option(name = {"-s", "--start"}, description = "initial concurrency level, defaults to 100") public int start = 1; @Option(name = {"-l", "--labels"}, description = "Show column labels") public boolean labels = false; @Option(name = {"-t", "--target"}, description = "target 99th percentile threshold, default is 100") public long target = 100L; @Option(name = {"-p", "--percentile"}, description = "Percentile to try to target, default is 99th percentile") public double percentile = 99.0; @Arguments(title = "url file", description = "input file to pull urls from, otherwise will use stdin") public File urlFile; public Void call() throws Exception { List<String> urls = Lists.newArrayList(); final BufferedReader in; if (urlFile != null) { in = new BufferedReader(new InputStreamReader(new FileInputStream(urlFile))); } else { in = new BufferedReader(new InputStreamReader(System.in)); } for (String line = in.readLine(); line != null; line = in.readLine()) { if (maxRequests >= 0) { if (maxRequests == 0) { break; } else if (maxRequests > 0) { maxRequests--; } } urls.add(line); } if (labels) {System.out.printf("clients\ttp%.1f\tmean\treqs/sec\n", percentile);} int best_concurency = start; int concurrency = start; DescriptiveStatistics result; DescriptiveStatistics best_result = null; double reqs_per_sec; double res = 1; while ((result = new Fight(concurrency, urls).call()).getPercentile(percentile) < target) { res = result.getPercentile(percentile); reqs_per_sec = ((1000 / result.getMean()) * concurrency); System.out.printf("%d\t%.2f\t%.2f\t%.2f\n", concurrency, res, result.getMean(), reqs_per_sec); best_concurency = concurrency; best_result = result; concurrency = concurrency * 2; } reqs_per_sec = ((1000 / result.getMean()) * concurrency); System.out.printf("%d\t%.2f\t%.2f\t%.2f\n", concurrency, result.getPercentile(percentile), result.getMean(), reqs_per_sec); int increment = (int) Math.sqrt((concurrency)); concurrency = concurrency / 2; while ((result = new Fight(concurrency, urls).call()).getPercentile(percentile) < target) { res = result.getPercentile(percentile); reqs_per_sec = ((1000 / result.getMean()) * concurrency); System.out.printf("%d\t%.2f\t%.2f\t%.2f\n", concurrency, res, result.getMean(), reqs_per_sec); best_concurency = concurrency; best_result = result; concurrency += increment; } reqs_per_sec = ((1000 / result.getMean()) * concurrency); System.out.printf("%d\t%.2f\t%.2f\t%.2f\n", concurrency, result.getPercentile(percentile), result.getMean(), reqs_per_sec); increment = (int) Math.sqrt(Math.sqrt(concurrency)); concurrency = concurrency - (2 * increment); while ((result = new Fight(concurrency, urls).call()).getPercentile(percentile) < target) { res = result.getPercentile(percentile); reqs_per_sec = ((1000 / result.getMean()) * concurrency); System.out.printf("%d\t%.2f\t%.2f\t%.2f\n", concurrency, res, result.getMean(), reqs_per_sec); best_concurency = concurrency; best_result = result; concurrency += increment; } reqs_per_sec = ((1000 / result.getMean()) * concurrency); System.out.printf("%d\t%.2f\t%.2f\t%.2f\n", concurrency, result.getPercentile(percentile), result.getMean(), reqs_per_sec); assert best_result != null; reqs_per_sec = ((1000 / best_result.getMean()) * best_concurency); System.out.printf("%d\t%.2f\t%.2f\t%.2f\n", best_concurency, best_result.getPercentile(percentile), best_result.getMean(), reqs_per_sec); return null; } }