]> review.fuel-infra Code Review - packages/trusty/mysql-wsrep-5.6.git/blob
ad3211b0e39db52ea2faf7df74b9c0aa15ba3c66
[packages/trusty/mysql-wsrep-5.6.git] /
1 /*
2    Copyright 2010 Sun Microsystems, Inc.
3    All rights reserved. Use is subject to license terms.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; version 2 of the License.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
17 */
18
19 package com.mysql.clusterj.jpatest;
20
21 import java.util.Properties;
22 import java.util.List;
23 import java.util.Set;
24 import java.util.HashSet;
25 import java.util.ArrayList;
26 import java.util.Date;
27 import java.text.SimpleDateFormat;
28
29 import java.io.FileInputStream;
30 import java.io.FileWriter;
31 import java.io.IOException;
32 import java.io.PrintWriter;
33 import java.io.InputStream;
34
35
36 /**
37  * This class is part of the CRUND benchmark that measures standard database operations 
38  * over a series of transactions on an increasing data set.
39  * <p>
40  * The abstract database operations are variations of: Create,
41  * Read, Update, Navigate, and Delete -- hence, the benchmark's name: CRUND.
42  * <p>
43  * The actual operations are defined by subclasses to allow measuring the
44  * operation performance across different datastore implementations.
45  *
46  * @see <a href="http://www.urbandictionary.com/define.php?term=crund">Urban Dictionary: crund</a>
47  * <ol>
48  * <li> used to debase people who torture others with their illogical
49  * attempts to make people laugh;
50  * <li> reference to cracking obsolete jokes;
51  * <li> a dance form;
52  * <li> to hit hard or smash.
53  * </ol>
54  */
55 abstract public class Driver {
56
57     /**
58      *  The stream to write messages to.
59      */
60     static protected final PrintWriter out = new PrintWriter(System.out, true);
61
62     /**
63      *  The stream to write error messages to.
64      */
65     static protected final PrintWriter err = new PrintWriter(System.err, true);
66
67     /**
68      *  Shortcut to the end-of-line character sequence.
69      */
70     static protected final String endl = System.getProperty("line.separator");
71
72     /**
73      *  Shortcut to the Runtime.
74      */
75     static private final Runtime rt = Runtime.getRuntime();
76
77     // command-line arguments
78     static private final List<String> propFileNames = new ArrayList<String>();
79     static private String logFileName
80         = ("log_"
81            + new SimpleDateFormat("yyyyMMdd_HHMMss").format(new Date())
82            + ".txt");
83
84     // the data output writer
85     private PrintWriter log;
86
87     // benchmark settings
88     protected final Properties props = new Properties();
89     protected String descr = "";
90     protected boolean logRealTime = false;
91     protected boolean logMemUsage = false;
92     protected boolean includeFullGC = false;
93     protected boolean logSumOfOps = false;
94     protected boolean renewOperations = false;
95     protected boolean renewConnection = false;
96     protected boolean allowExtendedPC = false;
97     protected int aStart = (1 << 8), aEnd = (1 << 12), aIncr = (1 << 2);
98     protected int bStart = (1 << 8), bEnd = (1 << 12), bIncr = (1 << 2);
99     protected int maxStringLength = 100;
100     protected int warmupRuns = 0;
101     protected int hotRuns = 0;
102     protected final Set<String> exclude = new HashSet<String>();
103
104     // ----------------------------------------------------------------------
105
106     /**
107      * A database operation to be benchmarked.
108      */
109     protected abstract class Op {
110         final protected String name;
111
112         public Op(String name) {
113             this.name = name;
114         }
115
116         public String getName() {
117             return name;
118         }
119
120         public abstract void run(int countA, int countB) throws Exception;
121     };
122
123     /**
124      * The list of database operations to be benchmarked.
125      * While the list instance is final, its content is managed by methods
126      * initOperations() and closeOperations() as defined by subclasses.
127      */
128     protected final List<Op> ops = new ArrayList<Op>();
129
130     // buffers collecting the header and data lines written to log
131     boolean logHeader;
132     private StringBuilder header;
133     private StringBuilder rtimes;
134     private StringBuilder musage;
135
136     // benchmark data fields
137     private long t0 = 0, t1 = 0, ta = 0;
138     private long m0 = 0, m1 = 0, ma = 0;
139
140     // benchmark methods to be defined by subclasses
141     abstract protected void initConnection() throws Exception;
142     abstract protected void closeConnection() throws Exception;
143     abstract protected void initOperations() throws Exception;
144     abstract protected void closeOperations() throws Exception;
145     abstract protected void clearPersistenceContext() throws Exception;
146     abstract protected void clearData() throws Exception;
147     abstract protected void beginTransaction() throws Exception;
148     abstract protected void commitTransaction() throws Exception;
149     abstract protected void rollbackTransaction() throws Exception;
150
151     /**
152      * Reports an error if a condition is not met.
153      *
154      * An invariant method to ensure the consistent application
155      * of verifying read results.
156      */
157     static protected final void verify(boolean cond) {
158         //assert (cond);
159         if (!cond)
160             throw new RuntimeException("wrong data; verification failed");
161     }
162
163     /**
164      * Loads a dynamically linked system library and reports any failures.
165      */
166     static protected void loadSystemLibrary(String name) {
167         out.print("loading libary ...");
168         out.flush();
169         try {
170             System.loadLibrary(name);
171         } catch (UnsatisfiedLinkError e) {
172             String path;
173             try {
174                 path = System.getProperty("java.library.path");
175             } catch (Exception ex) {
176                 path = "<exception caught: " + ex.getMessage() + ">";
177             }
178             err.println("NdbBase: failed loading library '"
179                         + name + "'; java.library.path='" + path + "'");
180             throw e;
181         } catch (SecurityException e) {
182             err.println("NdbBase: failed loading library '"
183                         + name + "'; caught exception: " + e);
184             throw e;
185         }
186         out.println("          [" + name + "]");
187     }
188
189     // ----------------------------------------------------------------------
190
191     /**
192      * Runs the entire benchmark.
193      */
194     public void run() {
195         try {
196             init();
197
198             // warmup runs
199             for (int i = 0; i < warmupRuns; i++)
200                 runTests();
201
202             // truncate log file, reset log buffers
203             out.println();
204             out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
205             out.println("start logging results ...");
206             out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
207             out.println();
208             header = new StringBuilder();
209             rtimes = new StringBuilder();
210             musage = new StringBuilder();
211             closeLogFile();
212             openLogFile();
213
214             // hot runs
215             for (int i = 0; i < hotRuns; i++)
216                 runTests();
217
218             // write log buffers
219             if (logRealTime) {
220                 log.println(descr + ", rtime[ms]"
221                             + header.toString() + endl
222                             + rtimes.toString() + endl + endl + endl);
223             }
224             if (logMemUsage) {
225                 log.println(descr + ", net musage[KiB]"
226                             + header.toString() + endl
227                             + musage.toString() + endl + endl + endl);
228             }
229
230             close();
231         } catch (Exception ex) {
232             // end the program regardless of threads
233             out.println("caught " + ex);
234             ex.printStackTrace();
235             System.exit(2); // return an error code
236         }
237     }
238
239     /**
240      * Initializes the benchmark's resources.
241      */
242     protected void init() throws Exception {
243         loadProperties();
244         initProperties();
245         printProperties();
246         openLogFile();
247
248         // init log buffers
249         logHeader = true;
250         header = new StringBuilder();
251         rtimes = new StringBuilder();
252         musage = new StringBuilder();
253     }
254
255     /**
256      * Releases the benchmark's resources.
257      */
258     protected void close() throws Exception {
259         // close log buffers
260         header = null;
261         rtimes = null;
262         musage = null;
263
264         closeLogFile();
265     }
266
267     /**
268      * Loads the benchmark's properties from properties files.
269      * Keys might appear multiple times in the same or different files.
270      * If there are duplicate keys, the last key definition overrides any
271      * previous value for the same key in the same or different file.
272      */
273     private void loadProperties() throws IOException {
274         if (propFileNames.size() == 0) {
275             propFileNames.add("crund.properties");
276         }
277         
278         out.println();
279         for (String fn : propFileNames) {
280             out.println("reading properties file:    " + fn);
281             InputStream is = null;
282             try {
283                 is = new FileInputStream(fn);
284                 props.load(is);
285             } catch (Exception e) {
286                 out.println("error reading file.");
287             } finally {
288                 if (is != null)
289                     is.close();
290             }
291         }
292     }
293
294     /**
295      * Retrieves a property's value and parses it as a boolean.
296      */
297     protected boolean parseBoolean(String k) {
298         return Boolean.parseBoolean(props.getProperty(k));
299     }
300     
301     /**
302      * Retrieves a property's value and parses it as a signed decimal integer.
303      * @throws NumberFormatException with a descriptive error message
304      */
305     protected int parseInt(String k, int vdefault) {
306         final String v = props.getProperty(k);
307         try {
308             return (v == null ? vdefault : Integer.parseInt(v));
309         } catch (NumberFormatException e) {
310             final NumberFormatException nfe = new NumberFormatException(
311                 "invalid value of benchmark property ('" + k + "', '"
312                 + v + "').");
313             nfe.initCause(e);
314             throw nfe;
315         }
316     }
317     
318     /**
319      * Initializes the benchmark properties.
320      */
321     protected void initProperties() {
322         // initialize boolean/numeric properties
323         logRealTime = parseBoolean("logRealTime");
324         logMemUsage = parseBoolean("logMemUsage");
325         includeFullGC = parseBoolean("includeFullGC");
326         logSumOfOps = parseBoolean("logSumOfOps");
327         renewOperations = parseBoolean("renewOperations");
328         renewConnection = parseBoolean("renewConnection");
329         allowExtendedPC = parseBoolean("allowExtendedPC");
330         aStart = parseInt("aStart", 1 << 8);
331         aEnd = parseInt("aEnd", 1 << 12);
332         aIncr = parseInt("aIncr", 1 << 2);
333         bStart = parseInt("bStart", 1 << 8);
334         bEnd = parseInt("bEnd", 1 << 12);
335         bIncr = parseInt("bIncr", 1 << 2);
336         maxStringLength = parseInt("maxStringLength", 100);
337         warmupRuns = parseInt("warmupRuns", 0);
338         hotRuns = parseInt("hotRuns", 1);
339
340         // initialize exclude set
341         final String[] e = props.getProperty("exclude", "").split(",");
342         for (int i = 0; i < e.length; i++) {
343             exclude.add(e[i]);
344         }
345     }
346
347     /**
348      * Prints the benchmark's properties.
349      */
350     protected void printProperties() {
351         //props.list(out);
352         out.println();
353         out.println("main settings:");
354         out.println("logRealTime:                " + logRealTime);
355         out.println("logMemUsage:                " + logMemUsage);
356         out.println("includeFullGC:              " + includeFullGC);
357         out.println("logSumOfOps:                " + logSumOfOps);
358         out.println("renewOperations:            " + renewOperations);
359         out.println("renewConnection:            " + renewConnection);
360         out.println("allowExtendedPC:            " + allowExtendedPC);
361         out.println("aStart:                     " + aStart);
362         out.println("aEnd:                       " + aEnd);
363         out.println("aIncr:                      " + aIncr);
364         out.println("bStart:                     " + bStart);
365         out.println("bEnd:                       " + bEnd);
366         out.println("bIncr:                      " + bIncr);
367         out.println("maxStringLength:            " + maxStringLength);
368         out.println("warmupRuns:                 " + warmupRuns);
369         out.println("hotRuns:                    " + hotRuns);
370         out.println("exclude:                    " + exclude);
371     }
372
373     /**
374      * Opens the benchmark's data log file.
375      */
376     private void openLogFile() throws IOException {
377         out.println();
378         out.println("writing results to file:    " + logFileName);
379         log = new PrintWriter(new FileWriter(logFileName, false));
380     }
381
382     /**
383      * Closes the benchmark's data log file.
384      */
385     private void closeLogFile() throws IOException {
386         out.print("closing files ...    ");
387         out.flush();
388         if (log != null) {
389             log.close();
390             log = null;
391         }
392         out.println("       [ok]");
393     }
394
395     // ----------------------------------------------------------------------
396
397     /**
398      * Runs a series of benchmark operations on scaled-up data.
399      */
400     protected void runTests() throws Exception {
401         initConnection();
402         initOperations();
403
404         for (int i = aStart; i <= aEnd; i *= aIncr) {
405             //for (int j = bBeg; j <= bEnd; j *= bIncr)
406             for (int j = (i > bStart ? i : bStart); j <= bEnd; j *= bIncr) {
407                 try {
408                     runOperations(i, j);
409                 } catch (Exception ex) {
410                     // already in rollback for database/orm exceptions
411                     //rollbackTransaction();
412                     throw ex;
413                 }
414             }
415         }
416
417         out.println();
418         out.println("------------------------------------------------------------");
419         out.println();
420
421         clearData();
422         closeOperations();
423         closeConnection();
424     }
425
426     /**
427      * Runs a series of benchmark operations.
428      */
429     protected void runOperations(int countA, int countB) throws Exception {
430         out.println();
431         out.println("------------------------------------------------------------");
432         out.println("countA = " + countA + ", countB = " + countB);
433         out.println();
434
435         // log buffers
436         if (logRealTime) {
437             rtimes.append("A=" + countA + ", B=" + countB);
438             ta = 0;
439         }
440         if (logMemUsage) {
441             musage.append("A=" + countA + ", B=" + countB);
442             ma = 0;
443         }
444         
445         // pre-run cleanup
446         if (renewConnection) {
447             closeOperations();
448             closeConnection();
449             initConnection();
450             initOperations();
451         } else if (renewOperations) {
452             closeOperations();
453             initOperations();
454         }
455         clearData();
456
457         // run operations
458         for (Op op : ops) {
459             // pre-tx cleanup
460             if (!allowExtendedPC) {
461                 // effectively prevent caching beyond Tx scope by clearing
462                 // any data/result caches before the next transaction
463                 clearPersistenceContext();
464             }
465             runOp(op, countA, countB);
466         }
467         if (logHeader) {
468             if (logSumOfOps)
469                 header.append("\ttotal");
470         }
471
472         // log buffers
473         logHeader = false;
474         if (logRealTime) {
475             if (logSumOfOps) {
476                 rtimes.append("\t" + ta);
477                 out.println();
478                 out.println("total");
479                 out.println("tx real time      = " + ta + "\tms [begin..commit]");
480             }
481             rtimes.append(endl);
482         }
483         if (logMemUsage) {
484             if (logSumOfOps) {
485                 musage.append("\t" + ma);
486                 out.println();
487                 out.println("total");
488                 out.println("net mem usage     = " + (ma >= 0 ? "+" : "") + ma
489                             + "\tKiB");
490             }
491             musage.append(endl);
492         }               
493     }
494
495     /**
496      * Runs a benchmark operation.
497      */
498     protected void runOp(Op op, int countA, int countB) throws Exception {
499         final String name = op.getName();
500         if (!exclude.contains(name)) {
501             begin(name);
502             op.run(countA, countB);
503             commit(name);
504         }
505     }
506
507     /**
508      * Begins a benchmarked transaction.
509      */
510     protected void begin(String name) throws Exception {
511         out.println();
512         out.println(name);
513
514         // attempt max GC, before tx
515         gc();
516
517         if (logMemUsage) {
518             m0 = rt.totalMemory() - rt.freeMemory();
519         }
520
521         if (logRealTime) {
522             //t0 = System.currentTimeMillis();
523             t0 = System.nanoTime() / 1000000;
524         }
525
526         beginTransaction();
527     }
528
529     /**
530      * Closes a benchmarked transaction.
531      */
532     protected void commit(String name) throws Exception {
533         commitTransaction();
534
535         // attempt one full GC, before timing tx end
536         if (includeFullGC) {
537             rt.gc();
538         }
539
540         if (logRealTime) {
541             //t1 = System.currentTimeMillis();
542             t1 = System.nanoTime() / 1000000;
543             final long t = t1 - t0;
544             out.println("tx real time      = " + t + "\tms [begin..commit]");
545             //rtimes.append("\t" + (Math.round(t / 100.0) / 10.0));
546             rtimes.append("\t" + t);
547             ta += t;
548         }
549
550         if (logMemUsage) {
551             // attempt max GC, after tx
552             gc();
553             m1 = rt.totalMemory() - rt.freeMemory();
554             final long m0K = (m0 / 1024);
555             final long m1K = (m1 / 1024);
556             final long mK = m1K - m0K;
557             out.println("net mem usage     = " + (mK >= 0 ? "+" : "") + mK
558                         + "\tKiB [" + m0K + "K->" + m1K + "K]");
559 /*
560             out.println("allocated memory  = "
561                         + m1 + "\tK after commit");
562             out.println("total memory      = "
563                         + (rt.totalMemory() / 1024) + "\tK after commit");
564             out.println("max memory        = "
565                         + (rt.maxMemory() / 1024) + "\tK after commit");
566 */
567             musage.append("\t" + mK);
568             ma += mK;
569         }
570
571         if (logHeader)
572             header.append("\t" + name);
573     }
574
575     /**
576      * Attempts to run the JVM's Garbage Collector.
577      */
578     static private void gc() {
579         // empirically determined limit after which no further
580         // reduction in memory usage has been observed
581         //final int nFullGCs = 5;
582         final int nFullGCs = 10;
583         for (int i = 0; i < nFullGCs; i++) {
584             //out.print("gc: ");
585             long oldfree;
586             long newfree = rt.freeMemory();
587             do {
588                 oldfree = newfree;
589                 rt.runFinalization();
590                 rt.gc();
591                 newfree = rt.freeMemory();
592                 //out.print('.');
593             } while (newfree > oldfree);
594             //out.println();
595         }
596     }
597
598     // ----------------------------------------------------------------------
599
600     /**
601      * Prints a command-line usage message and exits.
602      */
603     static private void exitUsage() {
604         out.println("usage: [options]");
605         out.println("    [-p <file name>]...    a properties file name");
606         out.println("    [-l <file name>]       log file name for data output");
607         out.println("    [-h|--help]            print usage message and exit");
608         out.println();
609         System.exit(1); // return an error code
610     }
611
612     /**
613      * Parses the benchmark's command-line arguments.
614      */
615     static public void parseArguments(String[] args) {
616         for (int i = 0; i < args.length; i++) {
617             final String arg = args[i];
618             if (arg.equals("-p")) {
619                 if (i >= args.length) {
620                     exitUsage();
621                 }
622                 propFileNames.add(args[++i]);
623             } else if (arg.equals("-l")) {
624                 if (i >= args.length) {
625                     exitUsage();
626                 }
627                 logFileName = args[++i];
628             } else if (arg.equals("-h") || arg.equals("--help")) {
629                 exitUsage();
630             } else {
631                 out.println("unknown option: " + arg);
632                 exitUsage();
633             }
634         }
635     }
636
637     /** Clears the propFileNames from a previous run
638      *
639      */
640     public static void clearPropFileNames() {
641         propFileNames.clear();
642     }
643
644 }