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 | 5 | private static final Map<BenchmarkMethod, BenchmarkExecutor> EXECUTOR = |
65 | |
new Hashtable<BenchmarkMethod, BenchmarkExecutor>(); |
66 | |
|
67 | |
|
68 | 5 | private static final Map<BenchmarkMethod, Integer> RUNS = new Hashtable<BenchmarkMethod, Integer>(); |
69 | |
|
70 | |
|
71 | 5 | 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 | 110 | private BenchmarkExecutor(final BenchmarkMethod paramElement) { |
97 | 110 | beforeFirstRun = false; |
98 | 110 | element = paramElement; |
99 | 110 | } |
100 | |
|
101 | |
|
102 | |
|
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
|
110 | |
public static BenchmarkExecutor getExecutor(final BenchmarkElement meth) { |
111 | 4000 | if (BENCHRES == null) { |
112 | 0 | throw new IllegalStateException("Call initialize method first!"); |
113 | |
} |
114 | |
|
115 | |
|
116 | 4000 | if (!EXECUTOR.containsKey(meth.getMeth())) { |
117 | 110 | EXECUTOR.put(meth.getMeth(), new BenchmarkExecutor(meth.getMeth())); |
118 | 110 | int runsOnAnno = BenchmarkMethod.getNumberOfAnnotatedRuns(meth.getMeth().getMethodToBench()); |
119 | 110 | if (runsOnAnno < 0) { |
120 | 50 | runsOnAnno = CONFIG.getRuns(); |
121 | |
} |
122 | 110 | RUNS.put(meth.getMeth(), runsOnAnno); |
123 | |
} |
124 | |
|
125 | |
|
126 | 4000 | 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 | 65 | METERS_TO_BENCH.clear(); |
140 | 65 | METERS_TO_BENCH.addAll(Arrays.asList(config.getMeters())); |
141 | 65 | EXECUTOR.clear(); |
142 | 65 | BENCHRES = result; |
143 | 65 | CONFIG = config; |
144 | |
|
145 | 65 | } |
146 | |
|
147 | |
|
148 | |
|
149 | |
|
150 | |
|
151 | |
|
152 | |
|
153 | |
|
154 | |
public void executeBeforeMethods(final Object obj) { |
155 | |
|
156 | |
|
157 | 3935 | if (!beforeFirstRun) { |
158 | 90 | beforeFirstRun = true; |
159 | |
|
160 | 90 | Method[] beforeFirst = null; |
161 | |
try { |
162 | 90 | beforeFirst = element.findBeforeFirstRun(); |
163 | 0 | } catch (final PerfidixMethodCheckException e) { |
164 | 0 | BENCHRES.addException(e); |
165 | 90 | } |
166 | 90 | if (beforeFirst.length != 0) { |
167 | 55 | checkAndExectuteBeforeAfters(obj, BeforeFirstRun.class, beforeFirst); |
168 | |
} |
169 | |
} |
170 | |
|
171 | |
|
172 | 3935 | Method[] beforeEach = null; |
173 | |
try { |
174 | 3935 | beforeEach = element.findBeforeEachRun(); |
175 | 0 | } catch (final PerfidixMethodCheckException e) { |
176 | 0 | BENCHRES.addException(e); |
177 | 3935 | } |
178 | 3935 | if (beforeEach.length != 0) { |
179 | 2385 | checkAndExectuteBeforeAfters(obj, BeforeEachRun.class, beforeEach); |
180 | |
} |
181 | |
|
182 | 3935 | } |
183 | |
|
184 | |
|
185 | |
|
186 | |
|
187 | |
|
188 | |
|
189 | |
|
190 | |
|
191 | |
|
192 | |
public void executeBench(final Object objToExecute) { |
193 | |
|
194 | 3930 | final double[] meterResults = new double[METERS_TO_BENCH.size()]; |
195 | |
|
196 | 3930 | final Method meth = element.getMethodToBench(); |
197 | |
|
198 | 3930 | int meterIndex1 = 0; |
199 | 3930 | int meterIndex2 = 0; |
200 | 3930 | for (final AbstractMeter meter : METERS_TO_BENCH) { |
201 | 6985 | meterResults[meterIndex1] = meter.getValue(); |
202 | 6985 | meterIndex1++; |
203 | 6985 | } |
204 | |
|
205 | 3930 | final PerfidixMethodInvocationException res = invokeMethod(objToExecute, Bench.class, meth); |
206 | |
|
207 | 3930 | for (final AbstractMeter meter : METERS_TO_BENCH) { |
208 | 6985 | meterResults[meterIndex2] = meter.getValue() - meterResults[meterIndex2]; |
209 | 6985 | meterIndex2++; |
210 | 6985 | } |
211 | |
|
212 | 3930 | if (res == null) { |
213 | 3909 | meterIndex1 = 0; |
214 | 3909 | for (final AbstractMeter meter : METERS_TO_BENCH) { |
215 | 6943 | BENCHRES.addData(element.getMethodToBench(), meter, meterResults[meterIndex1]); |
216 | 6943 | meterIndex1++; |
217 | 6943 | } |
218 | |
} else { |
219 | 21 | BENCHRES.addException(res); |
220 | |
} |
221 | |
|
222 | 3930 | } |
223 | |
|
224 | |
|
225 | |
|
226 | |
|
227 | |
|
228 | |
|
229 | |
|
230 | |
|
231 | |
public void executeAfterMethods(final Object obj) { |
232 | 3935 | int runs = RUNS.get(element); |
233 | 3935 | runs--; |
234 | 3935 | RUNS.put(element, runs); |
235 | |
|
236 | |
|
237 | 3935 | if (RUNS.get(element) == 0) { |
238 | 90 | Method[] afterLast = null; |
239 | |
try { |
240 | 90 | afterLast = element.findAfterLastRun(); |
241 | 0 | } catch (final PerfidixMethodCheckException e) { |
242 | 0 | BENCHRES.addException(e); |
243 | 90 | } |
244 | 90 | if (afterLast.length != 0) { |
245 | 55 | checkAndExectuteBeforeAfters(obj, AfterLastRun.class, afterLast); |
246 | |
} |
247 | |
|
248 | |
} |
249 | |
|
250 | |
|
251 | 3935 | Method[] afterEach = null; |
252 | |
try { |
253 | 3935 | afterEach = element.findAfterEachRun(); |
254 | 0 | } catch (final PerfidixMethodCheckException e) { |
255 | 0 | BENCHRES.addException(e); |
256 | 3935 | } |
257 | 3935 | if (afterEach != null) { |
258 | 3935 | checkAndExectuteBeforeAfters(obj, AfterEachRun.class, afterEach); |
259 | |
} |
260 | |
|
261 | 3935 | } |
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 | 6430 | final PerfidixMethodCheckException checkExc = checkMethod(obj, anno, meths); |
276 | 6430 | if (checkExc == null) { |
277 | 6430 | final PerfidixMethodInvocationException invoExc = invokeMethod(obj, anno, meths); |
278 | 6430 | if (invoExc != null) { |
279 | 0 | BENCHRES.addException(invoExc); |
280 | |
} |
281 | |
|
282 | 6430 | } else { |
283 | 0 | BENCHRES.addException(checkExc); |
284 | |
} |
285 | 6430 | } |
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 | 10425 | final Object[] args = {}; |
302 | 17774 | for (Method meth : meths) { |
303 | |
try { |
304 | 7375 | meth.invoke(obj, args); |
305 | 0 | } catch (final IllegalArgumentException e) { |
306 | 0 | return new PerfidixMethodInvocationException(e, meth, relatedAnno); |
307 | 0 | } catch (final IllegalAccessException e) { |
308 | 0 | return new PerfidixMethodInvocationException(e, meth, relatedAnno); |
309 | 26 | } catch (final InvocationTargetException e) { |
310 | 26 | return new PerfidixMethodInvocationException(e.getCause(), meth, relatedAnno); |
311 | 7349 | } |
312 | |
} |
313 | 10399 | 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 | 9950 | for (Method meth : meths) { |
333 | |
|
334 | 3455 | boolean classMethodCorr = false; |
335 | 47975 | for (final Method methodOfClass : obj.getClass().getDeclaredMethods()) { |
336 | 44520 | if (methodOfClass.equals(meth)) { |
337 | 3450 | classMethodCorr = true; |
338 | |
} |
339 | |
} |
340 | |
|
341 | 3455 | if (!classMethodCorr) { |
342 | 5 | 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 | 3450 | if (!BenchmarkMethod.isReflectedExecutable(meth, anno)) { |
349 | 5 | 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 | 6495 | return null; |
355 | |
} |
356 | |
|
357 | |
} |