/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.logging.log4j.core.async.perftest; import java.io.BufferedReader; import java.io.InputStreamReader; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * Utility class that can read the "Ranking" output of the PerfTestDriver and * format it for pasting into Excel. */ class PerfTestResultFormatter { static final String LF = System.lineSeparator(); static final NumberFormat NUM = new DecimalFormat("#,##0"); static class Stats { long throughput; double avgLatency; double latency99Pct; double latency99_99Pct; Stats(final String throughput, final String avg, final String lat99, final String lat99_99) throws ParseException { this.throughput = NUM.parse(throughput.trim()).longValue(); this.avgLatency = Double.parseDouble(avg.trim()); this.latency99Pct = Double.parseDouble(lat99.trim()); this.latency99_99Pct = Double.parseDouble(lat99_99.trim()); } } private final Map<String, Map<String, Stats>> results = new TreeMap<>(); public PerfTestResultFormatter() { } public String format(final String text) throws ParseException { results.clear(); final String[] lines = text.split("[\\r\\n]+"); for (final String line : lines) { process(line); } return latencyTable() + LF + throughputTable(); } private String latencyTable() { final StringBuilder sb = new StringBuilder(4 * 1024); final Set<String> subKeys = results.values().iterator().next().keySet(); final char[] tabs = new char[subKeys.size()]; Arrays.fill(tabs, '\t'); final String sep = new String(tabs); sb.append("\tAverage latency").append(sep).append("99% less than").append(sep).append("99.99% less than"); sb.append(LF); for (int i = 0; i < 3; i++) { for (final String subKey : subKeys) { sb.append('\t').append(subKey); } } sb.append(LF); for (final String key : results.keySet()) { sb.append(key); for (int i = 0; i < 3; i++) { final Map<String, Stats> sub = results.get(key); for (final String subKey : sub.keySet()) { final Stats stats = sub.get(subKey); switch (i) { case 0: sb.append('\t').append((long) stats.avgLatency); break; case 1: sb.append('\t').append((long) stats.latency99Pct); break; case 2: sb.append('\t').append((long) stats.latency99_99Pct); break; } } } sb.append(LF); } return sb.toString(); } private String throughputTable() { final StringBuilder sb = new StringBuilder(4 * 1024); final Set<String> subKeys = results.values().iterator().next().keySet(); sb.append("\tThroughput per thread (msg/sec)"); sb.append(LF); for (final String subKey : subKeys) { sb.append('\t').append(subKey); } sb.append(LF); for (final String key : results.keySet()) { sb.append(key); final Map<String, Stats> sub = results.get(key); for (final String subKey : sub.keySet()) { final Stats stats = sub.get(subKey); sb.append('\t').append(stats.throughput); } sb.append(LF); } return sb.toString(); } private void process(final String line) throws ParseException { final String key = line.substring(line.indexOf('.') + 1, line.indexOf('(')); final String sub = line.substring(line.indexOf('(') + 1, line.indexOf(')')); final String throughput = line.substring(line.indexOf("throughput: ") + "throughput: ".length(), line.indexOf(" ops")); final String avg = line.substring(line.indexOf("avg=") + "avg=".length(), line.indexOf(" 99%")); final String pct99 = line.substring( line.indexOf("99% < ") + "99% < ".length(), line.indexOf(" 99.99%")); final String pct99_99 = line.substring(line.indexOf("99.99% < ") + "99.99% < ".length(), line.lastIndexOf('(') - 1); final Stats stats = new Stats(throughput, avg, pct99, pct99_99); Map<String, Stats> map = results.get(key.trim()); if (map == null) { map = new TreeMap<>(sort()); results.put(key.trim(), map); } String subKey = sub.trim(); if ("single thread".equals(subKey)) { subKey = "1 thread"; } map.put(subKey, stats); } private Comparator<String> sort() { return new Comparator<String>() { List<String> expected = Arrays.asList("1 thread", "2 threads", "4 threads", "8 threads", "16 threads", "32 threads", "64 threads"); @Override public int compare(final String o1, final String o2) { final int i1 = expected.indexOf(o1); final int i2 = expected.indexOf(o2); if (i1 < 0 || i2 < 0) { return o1.compareTo(o2); } return i1 - i2; } }; } public static void main(final String[] args) throws Exception { final PerfTestResultFormatter fmt = new PerfTestResultFormatter(); final BufferedReader reader = new BufferedReader(new InputStreamReader( System.in)); String line; while ((line = reader.readLine()) != null) { fmt.process(line); } System.out.println(fmt.latencyTable()); System.out.println(); System.out.println(fmt.throughputTable()); } }