1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.perfidix.element;
28
29 import java.lang.annotation.Annotation;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.util.Arrays;
33 import java.util.Hashtable;
34 import java.util.LinkedHashSet;
35 import java.util.Map;
36 import java.util.Set;
37
38 import org.perfidix.AbstractConfig;
39 import org.perfidix.annotation.AfterEachRun;
40 import org.perfidix.annotation.AfterLastRun;
41 import org.perfidix.annotation.BeforeEachRun;
42 import org.perfidix.annotation.BeforeFirstRun;
43 import org.perfidix.annotation.Bench;
44 import org.perfidix.exceptions.PerfidixMethodCheckException;
45 import org.perfidix.exceptions.PerfidixMethodInvocationException;
46 import org.perfidix.meter.AbstractMeter;
47 import org.perfidix.result.BenchmarkResult;
48
49
50
51
52
53
54
55
56
57
58 public final class BenchmarkExecutor {
59
60
61
62
63
64 private static final Map<BenchmarkMethod, BenchmarkExecutor> EXECUTOR =
65 new Hashtable<BenchmarkMethod, BenchmarkExecutor>();
66
67
68 private static final Map<BenchmarkMethod, Integer> RUNS = new Hashtable<BenchmarkMethod, Integer>();
69
70
71 private static final Set<AbstractMeter> METERS_TO_BENCH = new LinkedHashSet<AbstractMeter>();
72
73
74 private static BenchmarkResult BENCHRES;
75
76
77 private static AbstractConfig CONFIG;
78
79
80 private transient boolean beforeFirstRun;
81
82
83
84
85
86 private transient final BenchmarkMethod element;
87
88
89
90
91
92
93
94
95
96 private BenchmarkExecutor(final BenchmarkMethod paramElement) {
97 beforeFirstRun = false;
98 element = paramElement;
99 }
100
101
102
103
104
105
106
107
108
109
110 public static BenchmarkExecutor getExecutor(final BenchmarkElement meth) {
111 if (BENCHRES == null) {
112 throw new IllegalStateException("Call initialize method first!");
113 }
114
115
116 if (!EXECUTOR.containsKey(meth.getMeth())) {
117 EXECUTOR.put(meth.getMeth(), new BenchmarkExecutor(meth.getMeth()));
118 int runsOnAnno = BenchmarkMethod.getNumberOfAnnotatedRuns(meth.getMeth().getMethodToBench());
119 if (runsOnAnno < 0) {
120 runsOnAnno = CONFIG.getRuns();
121 }
122 RUNS.put(meth.getMeth(), runsOnAnno);
123 }
124
125
126 return EXECUTOR.get(meth.getMeth());
127
128 }
129
130
131
132
133
134
135
136
137
138 public static void initialize(final AbstractConfig config, final BenchmarkResult result) {
139 METERS_TO_BENCH.clear();
140 METERS_TO_BENCH.addAll(Arrays.asList(config.getMeters()));
141 EXECUTOR.clear();
142 BENCHRES = result;
143 CONFIG = config;
144
145 }
146
147
148
149
150
151
152
153
154 public void executeBeforeMethods(final Object obj) {
155
156
157 if (!beforeFirstRun) {
158 beforeFirstRun = true;
159
160 Method[] beforeFirst = null;
161 try {
162 beforeFirst = element.findBeforeFirstRun();
163 } catch (final PerfidixMethodCheckException e) {
164 BENCHRES.addException(e);
165 }
166 if (beforeFirst.length != 0) {
167 checkAndExectuteBeforeAfters(obj, BeforeFirstRun.class, beforeFirst);
168 }
169 }
170
171
172 Method[] beforeEach = null;
173 try {
174 beforeEach = element.findBeforeEachRun();
175 } catch (final PerfidixMethodCheckException e) {
176 BENCHRES.addException(e);
177 }
178 if (beforeEach.length != 0) {
179 checkAndExectuteBeforeAfters(obj, BeforeEachRun.class, beforeEach);
180 }
181
182 }
183
184
185
186
187
188
189
190
191
192 public void executeBench(final Object objToExecute) {
193
194 final double[] meterResults = new double[METERS_TO_BENCH.size()];
195
196 final Method meth = element.getMethodToBench();
197
198 int meterIndex1 = 0;
199 int meterIndex2 = 0;
200 for (final AbstractMeter meter : METERS_TO_BENCH) {
201 meterResults[meterIndex1] = meter.getValue();
202 meterIndex1++;
203 }
204
205 final PerfidixMethodInvocationException res = invokeMethod(objToExecute, Bench.class, meth);
206
207 for (final AbstractMeter meter : METERS_TO_BENCH) {
208 meterResults[meterIndex2] = meter.getValue() - meterResults[meterIndex2];
209 meterIndex2++;
210 }
211
212 if (res == null) {
213 meterIndex1 = 0;
214 for (final AbstractMeter meter : METERS_TO_BENCH) {
215 BENCHRES.addData(element.getMethodToBench(), meter, meterResults[meterIndex1]);
216 meterIndex1++;
217 }
218 } else {
219 BENCHRES.addException(res);
220 }
221
222 }
223
224
225
226
227
228
229
230
231 public void executeAfterMethods(final Object obj) {
232 int runs = RUNS.get(element);
233 runs--;
234 RUNS.put(element, runs);
235
236
237 if (RUNS.get(element) == 0) {
238 Method[] afterLast = null;
239 try {
240 afterLast = element.findAfterLastRun();
241 } catch (final PerfidixMethodCheckException e) {
242 BENCHRES.addException(e);
243 }
244 if (afterLast.length != 0) {
245 checkAndExectuteBeforeAfters(obj, AfterLastRun.class, afterLast);
246 }
247
248 }
249
250
251 Method[] afterEach = null;
252 try {
253 afterEach = element.findAfterEachRun();
254 } catch (final PerfidixMethodCheckException e) {
255 BENCHRES.addException(e);
256 }
257 if (afterEach != null) {
258 checkAndExectuteBeforeAfters(obj, AfterEachRun.class, afterEach);
259 }
260
261 }
262
263
264
265
266
267
268
269
270
271
272
273 private void checkAndExectuteBeforeAfters(final Object obj, final Class<? extends Annotation> anno,
274 Method... meths) {
275 final PerfidixMethodCheckException checkExc = checkMethod(obj, anno, meths);
276 if (checkExc == null) {
277 final PerfidixMethodInvocationException invoExc = invokeMethod(obj, anno, meths);
278 if (invoExc != null) {
279 BENCHRES.addException(invoExc);
280 }
281
282 } else {
283 BENCHRES.addException(checkExc);
284 }
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299 public static PerfidixMethodInvocationException invokeMethod(final Object obj,
300 final Class<? extends Annotation> relatedAnno, Method... meths) {
301 final Object[] args = {};
302 for (Method meth : meths) {
303 try {
304 meth.invoke(obj, args);
305 } catch (final IllegalArgumentException e) {
306 return new PerfidixMethodInvocationException(e, meth, relatedAnno);
307 } catch (final IllegalAccessException e) {
308 return new PerfidixMethodInvocationException(e, meth, relatedAnno);
309 } catch (final InvocationTargetException e) {
310 return new PerfidixMethodInvocationException(e.getCause(), meth, relatedAnno);
311 }
312 }
313 return null;
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 public static PerfidixMethodCheckException checkMethod(final Object obj,
330 final Class<? extends Annotation> anno, Method... meths) {
331
332 for (Method meth : meths) {
333
334 boolean classMethodCorr = false;
335 for (final Method methodOfClass : obj.getClass().getDeclaredMethods()) {
336 if (methodOfClass.equals(meth)) {
337 classMethodCorr = true;
338 }
339 }
340
341 if (!classMethodCorr) {
342 return new PerfidixMethodCheckException(new IllegalStateException(new StringBuilder(
343 "Object to execute ").append(obj).append(" is not having a Method named ").append(meth)
344 .append(".").toString()), meth, anno);
345 }
346
347
348 if (!BenchmarkMethod.isReflectedExecutable(meth, anno)) {
349 return new PerfidixMethodCheckException(new IllegalAccessException(new StringBuilder(
350 "Method to execute ").append(meth).append(" is not reflected executable.").toString()),
351 meth, anno);
352 }
353 }
354 return null;
355 }
356
357 }