1 5 package com.tctest.performance.http.load; 6 7 import java.io.BufferedInputStream ; 8 import java.io.File ; 9 import java.io.FileFilter ; 10 import java.io.FileInputStream ; 11 import java.io.FileNotFoundException ; 12 import java.io.IOException ; 13 import java.io.ObjectInputStream ; 14 import java.net.URL ; 15 import java.text.NumberFormat ; 16 import java.util.Arrays ; 17 import java.util.Iterator ; 18 import java.util.Map ; 19 import java.util.TreeMap ; 20 import java.util.regex.Matcher ; 21 import java.util.regex.Pattern ; 22 import java.util.zip.GZIPInputStream ; 23 24 final class HttpResponseAnalysisReport { 25 26 static final String RESULTS_FILE_PREFIX = "response-statistics"; 27 static final String PAD = " "; 28 29 private HttpResponseAnalysisReport() { 30 } 32 33 private static class UrlStat { 34 private final IntList times = new IntList(); 35 private int errors = 0; 36 private int success = 0; 37 38 void add(ResponseStatistic stat) { 39 times.add(stat.duration()); 40 if (stat.statusCode() == 200) { 41 success++; 42 } else { 43 errors++; 44 } 45 } 46 } 47 48 private static class HostStat { 49 private final Map urlStats = new TreeMap (); 50 51 void add(String urlKey, ResponseStatistic stat) { 52 UrlStat urlStat = (UrlStat) urlStats.get(urlKey); 53 if (urlStat == null) { 54 urlStat = new UrlStat(); 55 urlStats.put(urlKey, urlStat); 56 } 57 58 urlStat.add(stat); 59 } 60 61 } 62 63 private static class StatsIterator implements Iterator { 64 65 private final File [] files; 66 private final Pattern pattern = Pattern.compile("^" + RESULTS_FILE_PREFIX + "\\.(.+)\\.(\\d+)\\.gz$"); 67 private final int[] counts; 68 private int index = 0; 69 private GZIPInputStream in; 70 71 public StatsIterator(File resultsDir) { 72 files = resultsDir.listFiles(new FileFilter () { 73 public boolean accept(File pathname) { 74 return pattern.matcher(pathname.getName()).matches(); 75 } 76 }); 77 78 counts = new int[files.length]; 79 80 for (int i = 0; i < files.length; i++) { 81 File file = files[i]; 82 Matcher m = pattern.matcher(file.getName()); 83 if (!m.matches()) { throw new RuntimeException (file + " doesn't match"); } 84 int count = Integer.parseInt(m.group(2)); 85 System.err.println("Going to read " + count + " stats from host " + m.group(1)); 86 counts[i] = count; 87 } 88 } 89 90 public boolean hasNext() { 91 for (int i = 0; i < counts.length; i++) { 92 if (counts[i] > 0) { return true; } 93 } 94 return false; 95 } 96 97 public Object next() { 98 try { 99 return next0(); 100 } catch (Exception e) { 101 if (e instanceof RuntimeException ) { throw (RuntimeException ) e; } 102 throw new RuntimeException (e); 103 } 104 } 105 106 private Object next0() throws Exception { 107 if (index >= counts.length) { throw new IllegalStateException ("no more data: index = " + index); } 108 109 if (in == null) { 110 in = inputFor(files[index]); 111 } 112 113 if (counts[index] == 0) { 114 index++; 115 in.close(); 116 in = inputFor(files[index]); 117 } 118 119 counts[index]--; 120 return new ObjectInputStream (in).readObject(); 121 } 122 123 public void remove() { 124 throw new UnsupportedOperationException (); 125 } 126 127 public int numClients() { 128 return files.length; 129 } 130 131 private static GZIPInputStream inputFor(File file) throws FileNotFoundException , IOException { 132 return new GZIPInputStream (new BufferedInputStream (new FileInputStream (file))); 133 } 134 } 135 136 public static void printReport(File resultsDir, String testName, int duration) throws IOException { 137 StatsIterator statsIterator = new StatsIterator(resultsDir); 138 139 int count = 0; 140 141 Map hostGroup = new TreeMap (); 142 Map fullUrlGroup = new TreeMap (); 143 144 long minStart = Long.MAX_VALUE; 145 long maxEnd = -1; 146 147 while (statsIterator.hasNext()) { 148 count++; 149 if ((count % 50000) == 0) { 150 System.err.println("Processed " + count + " stats..."); 151 } 152 153 ResponseStatistic stat = (ResponseStatistic) statsIterator.next(); 154 minStart = Math.min(stat.startTime(), minStart); 155 maxEnd = Math.max(stat.endTime(), maxEnd); 156 157 URL url = new URL (stat.url()); 159 String hostKey = url.getHost() + ":" + url.getPort(); 160 String urlKey = url.getPath() + url.getQuery(); 161 162 IntList urlTimes = (IntList) fullUrlGroup.get(urlKey); 164 if (urlTimes == null) { 165 urlTimes = new IntList(); 166 fullUrlGroup.put(urlKey, urlTimes); 167 } 168 urlTimes.add(stat.duration()); 169 170 HostStat hostStat = (HostStat) hostGroup.get(hostKey); 172 if (hostStat == null) { 173 hostStat = new HostStat(); 174 hostGroup.put(hostKey, hostStat); 175 } 176 hostStat.add(urlKey, stat); 177 } 178 179 int realDuration = (int) ((maxEnd - minStart) / 1000); 180 181 printHeader(resultsDir, testName, realDuration, statsIterator.numClients()); 182 out("Throughput Analyze:"); 183 out(repeat('_', "Throughput Analyze:".length())); 184 185 Iterator iter = hostGroup.entrySet().iterator(); 186 while (iter.hasNext()) { 187 Map.Entry entry = (Map.Entry ) iter.next(); 188 String hostKey = (String ) entry.getKey(); 189 HostStat hostStat = (HostStat) entry.getValue(); 190 throughputAnalysis(hostKey, hostStat, realDuration); 191 } 192 nl(); 193 nl(); 194 out("Response Analyze:"); 195 out(repeat('_', "Response Analyze:".length())); 196 responseAnalysis(fullUrlGroup); 197 } 198 199 private static void throughputAnalysis(String key, HostStat hostStat, long duration) { 200 int colWidth = 16; 201 nl(); 202 write("(" + key + ")", (42 + key.length()) - ((key.length() + 2) / 2)); 203 nl(); 204 nl(); 205 write("Ave.", colWidth); 206 write("tps", colWidth); 207 write("total", colWidth); 208 write("success", colWidth); 209 write("error", colWidth); 210 nl(); 211 out(repeat('-', 80)); 212 213 double totalAve = 0; 214 double totalTps = 0; 215 int totalTotal = 0; 216 int totalSuccess = 0; 217 int totalError = 0; 218 219 Iterator iter = hostStat.urlStats.entrySet().iterator(); 220 while (iter.hasNext()) { 221 double ave = 0; 222 double tps = 0; 223 long sum = 0; 224 225 Map.Entry entry = (Map.Entry ) iter.next(); 226 String urlKey = (String ) entry.getKey(); 227 UrlStat urlStat = (UrlStat) entry.getValue(); 228 229 final IntList times = urlStat.times; 230 final int success = urlStat.success; 231 final int error = urlStat.errors; 232 233 out(urlKey); 234 int size = times.size(); 235 236 for (int i = 0; i < size; i++) { 237 sum += times.get(i); 238 } 239 240 double doubleSize = size; 241 242 ave = sum / doubleSize; 243 totalAve += ave; 244 tps = doubleSize / duration; 245 totalTps += tps; 246 totalTotal += doubleSize; 247 totalSuccess += success; 248 totalError += error; 249 writeNum(Math.floor(ave), colWidth); 250 writeNum(tps, colWidth); 251 writeNum(doubleSize, colWidth); 252 writeNum(success, colWidth); 253 writeNum(error, colWidth); 254 nl(); 255 } 256 out(repeat('=', 80)); 257 write("total", 5); 258 writeNum(Math.floor(totalAve), 11); 259 writeNum(totalTps, colWidth); 260 writeNum(totalTotal, colWidth); 261 writeNum(totalSuccess, colWidth); 262 writeNum(totalError, colWidth); 263 nl(); 264 nl(); 265 } 266 267 private static void responseAnalysis(Map urlGroup) { 268 int colWidth = 9; 269 nl(); 270 write("Ave.", 8); 271 write("S.D.", colWidth); 272 write("min.", colWidth); 273 write("50%", colWidth); 274 write("60%", colWidth); 275 write("70%", colWidth); 276 write("80%", colWidth); 277 write("90%", colWidth); 278 write("max.", colWidth); 279 nl(); 280 out(repeat('-', 80)); 281 282 for (Iterator iter = urlGroup.entrySet().iterator(); iter.hasNext(); ) { 283 double ave = 0; 284 double size = 0; 285 double squareSum = 0; 286 long sum = 0; 287 288 Map.Entry entry = (Map.Entry ) iter.next(); 289 String urlKey = (String ) entry.getKey(); 290 IntList values = (IntList) entry.getValue(); 291 out(urlKey); 292 size = values.size(); 293 long[] durationSpread = new long[values.size()]; 294 295 for (int i = 0; i < size; i++) { 296 int duration = values.get(i); 297 sum += duration; 298 squareSum += duration * duration; 299 durationSpread[i] = duration; 300 } 301 302 Arrays.sort(durationSpread); 303 ave = sum / size; 304 writeNum(Math.floor(ave), 8); 305 writeNum(Math.floor(Math.sqrt((squareSum / size) - (ave * ave))), colWidth); 306 writeNum(durationSpread[0], colWidth); 307 writeNum(durationSpread[new Float (durationSpread.length * .5f).intValue() - 1], colWidth); 308 writeNum(durationSpread[new Float (durationSpread.length * .6f).intValue() - 1], colWidth); 309 writeNum(durationSpread[new Float (durationSpread.length * .7f).intValue() - 1], colWidth); 310 writeNum(durationSpread[new Float (durationSpread.length * .8f).intValue() - 1], colWidth); 311 writeNum(durationSpread[new Float (durationSpread.length * .9f).intValue() - 1], colWidth); 312 writeNum(durationSpread[durationSpread.length - 1], colWidth); 313 nl(); 314 } 315 } 316 317 private static void printHeader(File resultsDir, String testName, int realDuration, int loadClients) { 318 TestProperties props = new TestProperties(resultsDir.getParentFile()); 319 String threads = "" + props.getThreadCount(); 320 String [] hosts = props.getHosts(); 321 String stickyRatio = "" + props.getStickyRatio(); 322 323 out("HTTP RESPONSE ANALYSIS REPORT -- " + testName); 324 nl(); 325 write("THREADS:", 74); 326 out("" + (Integer.parseInt(threads) * loadClients), 6); 327 write("HOSTS:", 74); 328 out(Integer.toString(hosts.length), 6); 329 write("STICKY-RATIO:", 74); 330 out(stickyRatio, 6); 331 write("DURATION (real):", 74); 332 out("" + realDuration, 6); 333 write("LOAD CLIENTS:", 74); 334 out("" + loadClients, 6); 335 } 336 337 private static void write(String str, int width) { 338 if (str.length() > width) str = str.substring(0, width); 339 System.out.print(pad(width - str.length()) + str); 340 } 341 342 private static void writeNum(double num, int width) { 343 NumberFormat nf = NumberFormat.getInstance(); 344 nf.setMaximumFractionDigits(2); 345 String str = nf.format(num); 346 System.out.print(pad(width - str.length()) + str); 347 } 348 349 private static void out(String str) { 350 System.out.println(str); 351 } 352 353 private static void out(String str, int width) { 354 System.out.println(pad(width - str.length()) + str); 355 } 356 357 private static String pad(int width) { 358 String pad = ""; 359 for (int i = 0; i < width; i++) { 360 pad += PAD; 361 } 362 return pad; 363 } 364 365 private static String repeat(char chr, int width) { 366 String str = ""; 367 for (int i = 0; i < width; i++) { 368 str += chr; 369 } 370 return str; 371 } 372 373 private static void nl() { 374 System.out.print("\n"); 375 } 376 } 377 | Popular Tags |