MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ResultProcessor.java
1 /* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
3  *
4  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; version 2 of
9  * the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  */
21 
22 package com.mysql.cluster.crund;
23 
24 import java.util.Properties;
25 import java.util.List;
26 import java.util.ArrayList;
27 import java.text.ParseException;
28 import java.text.DecimalFormat;
29 
30 import java.io.FileInputStream;
31 import java.io.FileReader;
32 import java.io.BufferedReader;
33 import java.io.IOException;
34 import java.io.PrintWriter;
35 import java.io.InputStream;
36 
37 
41 public class ResultProcessor {
42 
46  public interface ResultReporter {
47 
57  void report(String tag,
58  int nRuns,
59  int nTxOps,
60  String[] op,
61  double[] avg,
62  double[] sdev,
63  double[] rsdev);
64  }
65 
69  static public class SimpleResultReporter implements ResultReporter {
70  static protected final DecimalFormat df = new DecimalFormat("#.##");
71 
75  public void report(String tag,
76  int nRuns,
77  int nTxOps,
78  String[] op,
79  double[] avg,
80  double[] sdev,
81  double[] rsdev) {
82  out.println();
83  out.println("tag = " + tag);
84  out.println("nRuns = " + nRuns);
85  out.println("nTxOps = " + nTxOps);
86  out.println();
87 
88  // ops with large deviations
89  final double thres = 10.0;
90  final List<String> problematic = new ArrayList<String>();
91 
92  for (int i = 0; i < op.length; i++) {
93  out.println("op = " + op[i]);
94  out.println("avg = " + df.format(avg[i]));
95  out.println("sdev = " + df.format(sdev[i]));
96  out.println("rsdev = " + df.format(rsdev[i]) + "%");
97  out.println();
98 
99  if (rsdev[i] > thres) {
100  problematic.add(df.format(rsdev[i]) + "%\t" + op[i]);
101  }
102  }
103 
104  if (problematic.size() > 1) {
105  out.println("operations with large deviations:");
106  for (String p : problematic) {
107  out.println(" " + p);
108  }
109  }
110  }
111  }
112 
113  // console
114  static protected final PrintWriter out = new PrintWriter(System.out, true);
115  static protected final PrintWriter err = new PrintWriter(System.err, true);
116 
117  // shortcuts
118  static protected final String endl = System.getProperty("line.separator");
119 
120  // result processor command-line arguments
121  static private final List<String> propFileNames = new ArrayList<String>();
122  static private final List<String> ilogFileNames = new ArrayList<String>();
123 
124  // result processor settings
125  protected final Properties props = new Properties();
126  protected int nWarmupRuns;
127 
128  // result processor resources
129  protected ResultReporter reporter;
130  protected String[] header;
131  protected int nTxOps;
132  protected int nRuns;
133  protected double[] ravg;
134  protected double[] rdev;
135 
136  // ----------------------------------------------------------------------
137  // result processor usage
138  // ----------------------------------------------------------------------
139 
143  static protected void exitUsage() {
144  out.println("usage: [options] <log file>...");
145  out.println(" [-p <file name>]... a properties file name");
146  out.println(" [-h|--help] print usage message and exit");
147  out.println();
148  System.exit(1); // return an error code
149  }
150 
154  static public void parseArguments(String[] args) {
155  for (int i = 0; i < args.length; i++) {
156  final String arg = args[i];
157  if (arg.equals("-p")) {
158  if (i >= args.length) {
159  exitUsage();
160  }
161  propFileNames.add(args[++i]);
162  } else if (arg.equals("-h") || arg.equals("--help")) {
163  exitUsage();
164  } else if (arg.startsWith("-")) {
165  out.println("unknown option: " + arg);
166  exitUsage();
167  } else {
168  ilogFileNames.add(args[i]);
169  }
170  }
171 
172  if (propFileNames.size() == 0) {
173  propFileNames.add("crundResult.properties");
174  }
175 
176  if (ilogFileNames.size() == 0) {
177  out.println("missing input files");
178  exitUsage();
179  }
180  }
181 
182  // ----------------------------------------------------------------------
183 
187  public ResultProcessor() {}
188 
192  public void run() {
193  try {
194  init();
195 
196  for (String fn : ilogFileNames) {
197  out.println();
198  out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
199  out.println("reading log file: " + fn);
200  out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
201 
202  BufferedReader ilog = null;
203  try {
204  ilog = new BufferedReader(new FileReader(fn));
205  process(ilog);
206  } finally {
207  if (ilog != null)
208  ilog.close();
209  }
210  }
211 
212  close();
213  } catch (Exception ex) {
214  // end the program regardless of threads
215  out.println("caught " + ex);
216  ex.printStackTrace();
217  System.exit(2); // return an error code
218  }
219  }
220 
221  // processes the log file
222  protected void process(BufferedReader ilog)
223  throws IOException, ParseException {
224 
225  int lineNo = 1;
226  String line;
227  int nIgnored = nWarmupRuns;
228  while (true) {
229  line = ilog.readLine();
230  if (line == null) {
231  return; // eof
232  }
233  lineNo++;
234  //out.println(line);
235 
236  // skip comments
237  if (line.startsWith("#")) {
238  continue;
239  }
240 
241  // parse empty line
242  if (line.equals("")) {
243  if (header != null) {
244  report();
245  }
246 
247  header = null;
248  ravg = null;
249  rdev = null;
250  continue;
251  }
252 
253  // parse header line
254  if (header == null) {
255  header = line.split("\\t");
256  assert (header.length > 0);
257 
258  nRuns = 0;
259  nTxOps = 0;
260  ravg = new double[header.length];
261  rdev = new double[header.length];
262  continue;
263  }
264 
265  // parse value line
266  final String[] values = line.split("\\t");
267  if (values.length != header.length) {
268  String msg = ("line # " + lineNo
269  + ": wrong number of tokens; "
270  + "expected: " + header.length
271  + ", found: " + values.length);
272  throw new ParseException(msg, 0);
273  }
274  nRuns++;
275 
276  // parse nTxOps
277  int n;
278  try {
279  n = Integer.valueOf(values[0]);
280  } catch (NumberFormatException e) {
281  String msg = ("line # " + lineNo
282  + ": " + e);
283  throw new ParseException(msg, 0);
284  }
285  if (nRuns == 1) {
286  nTxOps = n;
287  } else if (nTxOps != n) {
288  String msg = ("line # " + lineNo
289  + ": unexpected nTxOps; "
290  + "expected: " + nTxOps
291  + ", found: " + n);
292  throw new ParseException(msg, 0);
293  }
294 
295  // skip warmup runs
296  if (nRuns <= nIgnored) {
297  nRuns--;
298  nIgnored--;
299  continue;
300  }
301 
302  // parse values
303  for (int i = 1; i < values.length; i++) {
304  long l;
305  try {
306  l = Long.valueOf(values[i]);
307  } catch (NumberFormatException e) {
308  String msg = ("line # " + lineNo
309  + ": " + e);
310  throw new ParseException(msg, i);
311  }
312 
313  // compute running averages and squared deviations
314  final double v = l;
315  final double oavg = ravg[i];
316  final double navg = oavg + (v - oavg) / nRuns;
317  final double odev = rdev[i];
318  final double ndev = odev + (v - oavg) * (v - navg);
319  ravg[i] = navg;
320  rdev[i] = ndev;
321  }
322  }
323  }
324 
325  protected void report() {
326  // result data
327  final int nops = header.length - 1;
328  final String[] op = new String[nops];
329  final double[] avg = new double[nops];
330  final double[] sdev = new double[nops];
331  final double[] rsdev = new double[nops];
332 
333  // compute results
334  for (int i = 1; i <= nops; i++) {
335  op[i-1] = header[i];
336  avg[i-1] = ravg[i];
337  sdev[i-1] = Math.sqrt(rdev[i] / nRuns);
338  rsdev[i-1] = (sdev[i-1] * 100.0) / avg[i-1];
339  }
340  final String tag = header[0];
341 
342  reporter.report(tag, nRuns, nTxOps, op, avg, sdev, rsdev);
343  }
344 
345  // ----------------------------------------------------------------------
346  // result processor intializers/finalizers
347  // ----------------------------------------------------------------------
348 
349  // initializes the result processor's resources.
350  protected void init() throws Exception {
351  loadProperties();
352  initProperties();
353  printProperties();
354  reporter = new SimpleResultReporter();
355  }
356 
357  // releases the result processor's resources.
358  protected void close() throws Exception {
359  reporter = null;
360  props.clear();
361  }
362 
363  // loads the result processor's properties from properties files
364  private void loadProperties() throws IOException {
365  out.println();
366  for (String fn : propFileNames) {
367  out.println("reading properties file: " + fn);
368  InputStream is = null;
369  try {
370  is = new FileInputStream(fn);
371  props.load(is);
372  } finally {
373  if (is != null)
374  is.close();
375  }
376  }
377  }
378 
379  // retrieves a property's value and parses it as a boolean
380  protected boolean parseBoolean(String k, boolean vdefault) {
381  final String v = props.getProperty(k);
382  return (v == null ? vdefault : Boolean.parseBoolean(v));
383  }
384 
385  // retrieves a property's value and parses it as a signed decimal integer
386  protected int parseInt(String k, int vdefault) {
387  final String v = props.getProperty(k);
388  try {
389  return (v == null ? vdefault : Integer.parseInt(v));
390  } catch (NumberFormatException e) {
391  final NumberFormatException nfe = new NumberFormatException(
392  "invalid value of property ('" + k + "', '"
393  + v + "').");
394  nfe.initCause(e);
395  throw nfe;
396  }
397  }
398 
399  // initializes the result processor properties
400  protected void initProperties() {
401  //props.list(out);
402  out.print("setting properties ...");
403  out.flush();
404 
405  final StringBuilder msg = new StringBuilder();
406  final String eol = System.getProperty("line.separator");
407 
408  nWarmupRuns = parseInt("nWarmupRuns", 0);
409  if (nWarmupRuns < 0) {
410  msg.append("[ignored] nWarmupRuns: " + nWarmupRuns + eol);
411  nWarmupRuns = 0;
412  }
413 
414  if (msg.length() == 0) {
415  out.println(" [ok]");
416  } else {
417  out.println();
418  out.print(msg.toString());
419  }
420  }
421 
422  // prints the result processor's properties
423  protected void printProperties() {
424  out.println();
425  out.println("result processor settings ...");
426  out.println("nWarmupRuns: " + nWarmupRuns);
427  }
428 
429  // ----------------------------------------------------------------------
430 
431  static public void main(String[] args) {
432  System.out.println("ResultProcessor.main()");
433  parseArguments(args);
434  new ResultProcessor().run();
435  System.out.println();
436  System.out.println("ResultProcessor.main(): done.");
437  }
438 }