001 package jigcell.compare.tests;
002
003 import java.awt.EventQueue;
004 import java.util.List;
005 import jigcell.compare.IDataGenerator;
006 import jigcell.compare.IEditableDataElement;
007 import jigcell.compare.IReadableDataSource;
008 import jigcell.compare.ITypeChecker;
009 import jigcell.compare.data.EditableDataGenerator;
010 import jigcell.compare.data.PackedDoubleDataElement;
011 import jigcell.compare.data.PackedTreeDataElement;
012 import jigcell.compare.impl.Compare;
013 import jigcell.compare.impl.ProxyBuilder;
014 import jigcell.compare.ui.CompareFrontEnd;
015 import jigcell.compare.ui.IDataEditorTab;
016
017 /**
018 * Supports running performance tests in the Comparator. A benchmark is a state machine which supports timing how long a state takes to run. To
019 * run a benchmark, start a thread using the benchmark runnable. This puts the benchmark into state 0 which is run off of the event thread,
020 * and calls the runOffEventThread method. All other states are run on the event thread in the runOnEventThread method. Change to a new state
021 * by calling the runState method. To change to a new state and time how long it takes to run, call the timeRunState method.
022 *
023 * <p>
024 * This code is licensed under the DARPA BioCOMP Open Source License. See LICENSE for more details.
025 * </p>
026 *
027 * @author Nicholas Allen
028 */
029
030 public abstract class Benchmark {
031
032 /**
033 * Comparator to abuse
034 */
035
036 protected Compare compare;
037
038 /**
039 * Runnable instance to start benchmarking
040 */
041
042 protected final Runnable benchmarkRunnable = ProxyBuilder.proxyRunnable (this, "startBenchmark");
043
044 /**
045 * Current state of the tester
046 */
047
048 private int state;
049
050 /**
051 * Current run execution time in seconds.
052 */
053
054 protected static double currentTime () {
055 return System.currentTimeMillis () / 1000.0;
056 }
057
058 /**
059 * Attempts to bring the VM to a controlled state.
060 */
061
062 protected static void reset () {
063 System.gc ();
064 try {
065 Thread.sleep (50);
066 } catch (Exception e) {
067 Compare.throwUncheckedException (e);
068 }
069 System.gc ();
070 }
071
072 /**
073 * Creates a new performance tester.
074 *
075 * @param compare Comparator to abuse
076 */
077
078 protected Benchmark (Compare compare) {
079 this.compare = compare;
080 }
081
082 /**
083 * Creates a data generator that represents a benchmark result.
084 *
085 * @param name Generator name
086 * @param description Generator description
087 * @param type Generator type
088 * @param results Timing results
089 */
090
091 protected IDataGenerator createBenchmarkReport (String name, String description, String type, List results) {
092 IEditableDataElement element = new PackedTreeDataElement ();
093 EditableDataGenerator generator = new EditableDataGenerator (element);
094 generator.setName (name);
095 generator.setComment (description);
096 generator.setAttribute (ITypeChecker.ATTRIBUTE_TYPE, type);
097 for (int i = 0, l = results.size (); i < l; i++) {
098 double result [] = (double []) results.get (i);
099 IEditableDataElement _element = new PackedDoubleDataElement ();
100 element.setValue (i + 1, _element);
101 for (int _i = 0, _l = result.length; _i < _l; _i++)
102 _element.setValue (_i + 1, result [_i]);
103 }
104 return generator;
105 }
106
107 /**
108 * Loads data in a view.
109 *
110 * @param view View
111 * @param source Data source
112 */
113
114 protected void loadInView (IDataEditorTab view, IReadableDataSource source) {
115 if (compare instanceof CompareFrontEnd)
116 ((CompareFrontEnd) compare).selectTab (view);
117 view.loadDirect (source);
118 }
119
120 /**
121 * Performs the tester computations that do not interact with the interface. This method will be called at the start of the test.
122 */
123
124 protected abstract void runOffEventThread () throws Exception;
125
126 /**
127 * Performs an operation that interacts with the interface. After the operation completes, the thread needs to notify the benchmark.
128 *
129 * @param state Indicates which interface operation is next
130 */
131
132 protected abstract void runOnEventThread (int state) throws Exception;
133
134 /**
135 * Starts an operation that will interact with the interface. This method will invoke runOnEventThread with the same argument.
136 *
137 * @param state Some state flag
138 */
139
140 protected final void runState (int state) throws Exception {
141 assert state > 0;
142 this.state = state;
143 EventQueue.invokeAndWait (benchmarkRunnable);
144 }
145
146 /**
147 * Executes an operation that interacts with the interface and returns how long it took to complete.
148 *
149 * @param state State flag
150 */
151
152 protected double timeRunState (int state) throws Exception {
153 assert state > 0;
154 double startTime = currentTime ();
155 this.state = state;
156 EventQueue.invokeLater (benchmarkRunnable);
157 synchronized (this) {
158 wait ();
159 }
160 return currentTime () - startTime - 0.05;
161 }
162
163 /**
164 * Starts running the benchmark.
165 */
166
167 private void startBenchmark () {
168 try {
169 if (state == 0)
170 runOffEventThread ();
171 else {
172 try {
173 Thread.sleep (50);
174 } catch (InterruptedException e) {
175 throw new RuntimeException ("Unable to pause benchmark for synchronization.");
176 }
177 runOnEventThread (state);
178 }
179 } catch (Exception e) {
180 Compare.throwUncheckedException (e);
181 }
182 }
183 }