1 | package test.stress; |
---|
2 | |
---|
3 | import java.io.BufferedReader; |
---|
4 | import java.io.File; |
---|
5 | import java.io.FileInputStream; |
---|
6 | import java.io.FileOutputStream; |
---|
7 | import java.io.IOException; |
---|
8 | import java.io.InputStreamReader; |
---|
9 | import java.lang.management.MemoryMXBean; |
---|
10 | import java.util.ArrayList; |
---|
11 | import java.util.Collections; |
---|
12 | import java.util.List; |
---|
13 | import java.util.Properties; |
---|
14 | import java.awt.Toolkit; |
---|
15 | |
---|
16 | import org.apache.commons.logging.Log; |
---|
17 | import org.apache.commons.logging.LogFactory; |
---|
18 | |
---|
19 | import simulator.GridSchedulingSimulator; |
---|
20 | |
---|
21 | /** |
---|
22 | * Class responsible for performin memory and time analysis of experiments |
---|
23 | * execution. |
---|
24 | * |
---|
25 | * @author Jarek Szymczak |
---|
26 | * @version $Id$ |
---|
27 | */ |
---|
28 | public class MemoryAndTimeAnalyzer { |
---|
29 | |
---|
30 | /** The class logger. */ |
---|
31 | private static final Log LOGGER = |
---|
32 | LogFactory.getLog(MemoryAndTimeAnalyzer.class); |
---|
33 | |
---|
34 | /** The properties. */ |
---|
35 | private static Properties properties = new Properties(); |
---|
36 | |
---|
37 | /** |
---|
38 | * Variables determinig what type of memories should be meassured and should |
---|
39 | * it be performed in detailed or simple way. |
---|
40 | */ |
---|
41 | private static boolean heap, nonHeap, jvm, heapDet, nonHeapDet, jvmDet; |
---|
42 | |
---|
43 | /** |
---|
44 | * Determines if the time is meassured precisly (it's not disturb with |
---|
45 | * memory meassuring). |
---|
46 | */ |
---|
47 | private static boolean timePrec; |
---|
48 | |
---|
49 | /** Memory details output stream. */ |
---|
50 | private static FileOutputStream outDetails; |
---|
51 | |
---|
52 | /** The current number of iterations - used for progress calculation. */ |
---|
53 | private static int currentNumberOfIterations; |
---|
54 | |
---|
55 | /** The total number of iterations - used for progress calculation. */ |
---|
56 | private static int totalNumberOfIterations; |
---|
57 | |
---|
58 | /** Number of repeats of each experiments. */ |
---|
59 | private static int repeats; |
---|
60 | |
---|
61 | /** |
---|
62 | * It stores information about amount of system memory in a certain machine |
---|
63 | * (in megabytes). |
---|
64 | */ |
---|
65 | private static int memoryInMB; |
---|
66 | |
---|
67 | /** The interval between memory checks (in miliseconds). */ |
---|
68 | private static int interval; |
---|
69 | |
---|
70 | /** |
---|
71 | * The object used for gathering the information about heap and non-heap |
---|
72 | * memory. |
---|
73 | */ |
---|
74 | private static MemoryMXBean memoryMXBean = |
---|
75 | java.lang.management.ManagementFactory.getMemoryMXBean(); |
---|
76 | |
---|
77 | /** |
---|
78 | * The GSSIM object which is analyzed with certain experiment (for each |
---|
79 | * experiment new object is created, and the old one is dereferenced and |
---|
80 | * deleted (probably). |
---|
81 | */ |
---|
82 | private static GridSchedulingSimulator gssim = |
---|
83 | new GridSchedulingSimulator(); |
---|
84 | |
---|
85 | /** |
---|
86 | * Variables helpful during time and memory consumption analysis (they're |
---|
87 | * not local to simplify working with the thread responsible for memory |
---|
88 | * analysis and to write the details to outDetails output stream. |
---|
89 | */ |
---|
90 | private static long timestart, hmemstart, hmemmax, nmemmax, jvmmemmax, |
---|
91 | timend; |
---|
92 | |
---|
93 | /** |
---|
94 | * Performs memory and time analysis of a single file. |
---|
95 | * |
---|
96 | * @param filename |
---|
97 | * experiment file path |
---|
98 | * @param iteration |
---|
99 | * iteration number |
---|
100 | * @return array with results: time, heap memory, non-heap memory and JVM |
---|
101 | * memory |
---|
102 | * @throws InterruptedException |
---|
103 | * the interrupted exception when thread was interrupted during |
---|
104 | * sleep |
---|
105 | */ |
---|
106 | private static double[] singleTask(String filename, int iteration) |
---|
107 | throws InterruptedException { |
---|
108 | double[] result = new double[4]; |
---|
109 | |
---|
110 | Thread t = new Thread() { |
---|
111 | public void run() { |
---|
112 | long htemp, ntemp, jvmtemp; |
---|
113 | hmemmax = hmemstart; |
---|
114 | nmemmax = 0; |
---|
115 | jvmmemmax = 0; |
---|
116 | try { |
---|
117 | while (!interrupted()) { |
---|
118 | |
---|
119 | sleep(interval); |
---|
120 | |
---|
121 | htemp = |
---|
122 | heap ? memoryMXBean.getHeapMemoryUsage() |
---|
123 | .getUsed() : 0; |
---|
124 | ntemp = |
---|
125 | nonHeap ? memoryMXBean.getNonHeapMemoryUsage() |
---|
126 | .getUsed() : 0; |
---|
127 | jvmtemp = jvm ? getJVMMemory() : 0; |
---|
128 | |
---|
129 | if (htemp > hmemmax) |
---|
130 | hmemmax = htemp; |
---|
131 | if (ntemp > nmemmax) |
---|
132 | nmemmax = ntemp; |
---|
133 | if (htemp > jvmmemmax) |
---|
134 | jvmmemmax = jvmtemp; |
---|
135 | |
---|
136 | if (heapDet) |
---|
137 | outDetails.write(String.format("%.3f\t", |
---|
138 | (hmemmax - hmemstart) / (1024.0 * 1024.0)) |
---|
139 | .getBytes("UTF-8")); |
---|
140 | |
---|
141 | if (nonHeapDet) |
---|
142 | outDetails.write(String.format("%.3f\t", |
---|
143 | nmemmax / (1024.0 * 1024.0)).getBytes( |
---|
144 | "UTF-8")); |
---|
145 | |
---|
146 | if (jvmDet) |
---|
147 | outDetails.write(String.format("%.3f\t", |
---|
148 | jvmmemmax / (1024.0 * 1024.0)).getBytes( |
---|
149 | "UTF-8")); |
---|
150 | |
---|
151 | if (heapDet || nonHeapDet || jvmDet) |
---|
152 | outDetails.write("\n".getBytes("UTF-8")); |
---|
153 | } |
---|
154 | } catch (InterruptedException e) { |
---|
155 | return; |
---|
156 | } catch (IOException e) { |
---|
157 | // if this happens it's very bad,,, but it's totally |
---|
158 | // unexpected - only if there's a problem with closing |
---|
159 | // stream from ps process |
---|
160 | throw new RuntimeException(e); |
---|
161 | } |
---|
162 | } |
---|
163 | }; |
---|
164 | |
---|
165 | try { |
---|
166 | if (heapDet || nonHeapDet || jvmDet) |
---|
167 | outDetails.write(("\n\n" + filename + " (iteration: " |
---|
168 | + Integer.toString(iteration) + ") \n\n") |
---|
169 | .getBytes("UTF-8")); |
---|
170 | if (heapDet) |
---|
171 | outDetails.write("Hmem\t".getBytes("UTF-8")); |
---|
172 | if (nonHeapDet) |
---|
173 | outDetails.write("Nmem\t".getBytes("UTF-8")); |
---|
174 | if (jvmDet) |
---|
175 | outDetails.write("JVMmem\t".getBytes("UTF-8")); |
---|
176 | if (heapDet || nonHeapDet || jvmDet) |
---|
177 | outDetails.write("\n".getBytes("UTF-8")); |
---|
178 | } catch (IOException e) { |
---|
179 | // if this happens it's very bad,,, but it's totally unexpected |
---|
180 | throw new RuntimeException(e); |
---|
181 | } |
---|
182 | |
---|
183 | LOGGER.info("Current progress in number of experiments performed: " |
---|
184 | + Integer.toString(currentNumberOfIterations) |
---|
185 | + " / " |
---|
186 | + Integer.toString(totalNumberOfIterations) |
---|
187 | + " (" |
---|
188 | + Integer.toString((currentNumberOfIterations) * 100 |
---|
189 | / totalNumberOfIterations) + "%)"); |
---|
190 | |
---|
191 | currentNumberOfIterations++; |
---|
192 | |
---|
193 | gssim = null; |
---|
194 | |
---|
195 | for (int i = 0; i < 5; i++) { |
---|
196 | Thread.sleep(600); |
---|
197 | System.gc(); |
---|
198 | } |
---|
199 | |
---|
200 | hmemstart = memoryMXBean.getHeapMemoryUsage().getUsed(); |
---|
201 | gssim = new GridSchedulingSimulator(); |
---|
202 | |
---|
203 | if (heap || nonHeap || jvm) |
---|
204 | t.start(); |
---|
205 | |
---|
206 | timestart = System.currentTimeMillis(); |
---|
207 | gssim.run(new String[] { filename }); |
---|
208 | timend = System.currentTimeMillis(); |
---|
209 | |
---|
210 | if (heap || nonHeap || jvm) { |
---|
211 | t.interrupt(); |
---|
212 | t.join(); |
---|
213 | |
---|
214 | if (timePrec) { |
---|
215 | gssim = null; |
---|
216 | for (int i = 0; i < 5; i++) |
---|
217 | System.gc(); |
---|
218 | gssim = new GridSchedulingSimulator(); |
---|
219 | |
---|
220 | timestart = System.currentTimeMillis(); |
---|
221 | gssim.run(new String[] { filename }); |
---|
222 | timend = System.currentTimeMillis(); |
---|
223 | } |
---|
224 | } |
---|
225 | |
---|
226 | result[0] = (timend - timestart) / 1000.0; |
---|
227 | result[1] = (hmemmax - hmemstart) / (1024.0 * 1024.0); |
---|
228 | result[2] = nmemmax / (1024.0 * 1024.0); |
---|
229 | result[3] = jvmmemmax / (1024.0 * 1024.0); |
---|
230 | |
---|
231 | return result; |
---|
232 | } |
---|
233 | |
---|
234 | /** |
---|
235 | * Repeats task number specified in variable "repeats" times |
---|
236 | * |
---|
237 | * @param filename |
---|
238 | * experiment filename |
---|
239 | * @return the formatted line with results (content depends on |
---|
240 | * configuration) |
---|
241 | * @throws InterruptedException |
---|
242 | * thrown when thread is interrupted during sleep |
---|
243 | */ |
---|
244 | private static String repeatTask(String filename) |
---|
245 | throws InterruptedException { |
---|
246 | |
---|
247 | double[] temp; |
---|
248 | |
---|
249 | double tavg = 0; |
---|
250 | double tstdev = 0; |
---|
251 | double hmavg = 0; |
---|
252 | double hmstdev = 0; |
---|
253 | double nmstdev = 0; |
---|
254 | double nmavg = 0; |
---|
255 | double jvmmavg = 0; |
---|
256 | double jvmmstdev = 0; |
---|
257 | |
---|
258 | for (int i = 0; i < repeats; i++) { |
---|
259 | temp = singleTask(filename, i); |
---|
260 | tavg += temp[0]; |
---|
261 | tstdev += temp[0] * temp[0]; |
---|
262 | hmavg += temp[1]; |
---|
263 | hmstdev += temp[1] * temp[1]; |
---|
264 | nmavg += temp[2]; |
---|
265 | nmstdev += temp[2] * temp[2]; |
---|
266 | jvmmavg += temp[3]; |
---|
267 | jvmmstdev += temp[3] * temp[3]; |
---|
268 | } |
---|
269 | |
---|
270 | tavg /= repeats; |
---|
271 | tstdev /= repeats; |
---|
272 | hmavg /= repeats; |
---|
273 | hmstdev /= repeats; |
---|
274 | nmavg /= repeats; |
---|
275 | nmstdev /= repeats; |
---|
276 | jvmmavg /= repeats; |
---|
277 | jvmmstdev /= repeats; |
---|
278 | |
---|
279 | tstdev = Math.sqrt(tstdev - tavg * tavg); |
---|
280 | hmstdev = Math.sqrt(hmstdev - hmavg * hmavg); |
---|
281 | nmstdev = Math.sqrt(nmstdev - nmavg * nmavg); |
---|
282 | jvmmstdev = Math.sqrt(jvmmstdev - jvmmavg * jvmmavg); |
---|
283 | |
---|
284 | StringBuilder result = |
---|
285 | new StringBuilder(String.format("%.3f\t%.3f\t", tavg, tstdev)); |
---|
286 | |
---|
287 | if (heap) |
---|
288 | result.append(String.format("%.3f\t%.3f\t", hmavg, hmstdev)); |
---|
289 | if (nonHeap) |
---|
290 | result.append(String.format("%.3f\t%.3f\t", nmavg, nmstdev)); |
---|
291 | if (jvm) |
---|
292 | result.append(String.format("%.3f\t%.3f\t", jvmmavg, jvmmstdev)); |
---|
293 | |
---|
294 | return result.toString(); |
---|
295 | } |
---|
296 | |
---|
297 | /** |
---|
298 | * Gets the JVM memory. It works only under linux and only if the process |
---|
299 | * name begins with "java" (so, for instance, it doesn't work when the |
---|
300 | * application is run under Eclipse SDK). It depends on {@link #memoryInMB} |
---|
301 | * variable |
---|
302 | * |
---|
303 | * @return amount of memory used by JVM process (in bytes) |
---|
304 | * @throws IOException |
---|
305 | * Signals that an I/O exception has occurred. |
---|
306 | */ |
---|
307 | public static Long getJVMMemory() throws IOException { |
---|
308 | BufferedReader reader = null; |
---|
309 | try { |
---|
310 | Process proc = |
---|
311 | Runtime |
---|
312 | .getRuntime() |
---|
313 | .exec( |
---|
314 | new String[] { "bash", "-c", |
---|
315 | "ps u --width=5 | grep java | tr -s ' ' | cut -d ' ' -f 4" }); |
---|
316 | reader = |
---|
317 | new BufferedReader(new InputStreamReader(proc |
---|
318 | .getInputStream())); |
---|
319 | |
---|
320 | String line; |
---|
321 | if (null != (line = reader.readLine())) { |
---|
322 | return Math.round(Double.parseDouble(line) / 100.0 * memoryInMB |
---|
323 | * 1024.0 * 1024.0); |
---|
324 | } |
---|
325 | return null; |
---|
326 | } catch (IOException e) { |
---|
327 | System.out.println(e.getMessage()); |
---|
328 | return null; |
---|
329 | } finally { |
---|
330 | if (reader != null) |
---|
331 | reader.close(); |
---|
332 | } |
---|
333 | |
---|
334 | } |
---|
335 | |
---|
336 | /** |
---|
337 | * The main method. It reads the properties of analysis from file |
---|
338 | * "properties/performance.properties" - this path is relative so it's |
---|
339 | * important from which folder the application is run. Meaning of each |
---|
340 | * property is described in the .properties file, please do not change it's |
---|
341 | * content other than parameters' values |
---|
342 | * |
---|
343 | * @param args |
---|
344 | * the arguments of main methods are relative paths to |
---|
345 | * .properties files with experiments or directories containing |
---|
346 | * these files (it's not recursive) |
---|
347 | * @throws IOException |
---|
348 | * Signals that an I/O exception has occurred. |
---|
349 | * @throws InterruptedException |
---|
350 | * fall-through exception which is not possible to occur |
---|
351 | */ |
---|
352 | public static void main(String[] args) throws IOException, |
---|
353 | InterruptedException { |
---|
354 | |
---|
355 | LOGGER.info("Reading the properties"); |
---|
356 | |
---|
357 | properties.load(new FileInputStream(new File( |
---|
358 | "properties/performance.properties"))); |
---|
359 | |
---|
360 | int noOfBeeps = |
---|
361 | Integer.parseInt(properties.getProperty("NO_OF_BEEPS", "0")); |
---|
362 | |
---|
363 | interval = Integer.parseInt(properties.getProperty("INTERVAL")); |
---|
364 | repeats = Integer.parseInt(properties.getProperty("REPEATS")); |
---|
365 | memoryInMB = Integer.parseInt(properties.getProperty("MEMORY_IN_MB")); |
---|
366 | |
---|
367 | heap = |
---|
368 | "simple".equals(properties.getProperty("HEAP_MEMORY")) |
---|
369 | || "details".equals(properties |
---|
370 | .getProperty("HEAP_MEMORY")); |
---|
371 | heapDet = "details".equals(properties.getProperty("HEAP_MEMORY")); |
---|
372 | nonHeap = |
---|
373 | "simple".equals(properties.getProperty("NON_HEAP_MEMORY")) |
---|
374 | || "details".equals(properties |
---|
375 | .getProperty("NON_HEAP_MEMORY")); |
---|
376 | nonHeapDet = |
---|
377 | "details".equals(properties.getProperty("NON_HEAP_MEMORY")); |
---|
378 | jvm = |
---|
379 | "simple".equals(properties.getProperty("JVM_MEMORY")) |
---|
380 | || "details".equals(properties |
---|
381 | .getProperty("JVM_MEMORY")); |
---|
382 | jvmDet = "details".equals(properties.getProperty("JVM_MEMORY")); |
---|
383 | |
---|
384 | timePrec = (!jvm && !heap && !nonHeap); |
---|
385 | |
---|
386 | if ("precisly".equals(properties.getProperty("TIME_MEASURING"))) |
---|
387 | timePrec = true; |
---|
388 | |
---|
389 | LOGGER.info("Preparing file list to perform experiment"); |
---|
390 | |
---|
391 | List<String> records = new ArrayList<String>(); |
---|
392 | |
---|
393 | File temp; |
---|
394 | |
---|
395 | if (args.length < 1) |
---|
396 | return; |
---|
397 | |
---|
398 | for (int i = 0; i < args.length; i++) { |
---|
399 | if ((new File(args[i])).exists()) |
---|
400 | if (args[i].endsWith(".properties")) |
---|
401 | records.add(args[i]); |
---|
402 | else { |
---|
403 | temp = new File(args[i]); |
---|
404 | String[] files = temp.list(); |
---|
405 | if (files != null) { |
---|
406 | for (String file : files) { |
---|
407 | if ((new File(args[i] + "/" + file).exists() && file |
---|
408 | .endsWith(".properties"))) |
---|
409 | records.add(args[i] + "/" + file); |
---|
410 | } |
---|
411 | } |
---|
412 | } |
---|
413 | } |
---|
414 | |
---|
415 | totalNumberOfIterations = repeats * records.size(); |
---|
416 | |
---|
417 | if (records.size() == 0) |
---|
418 | return; |
---|
419 | |
---|
420 | int counter = 0; |
---|
421 | File file = null; |
---|
422 | File fileDetails = null; |
---|
423 | |
---|
424 | do { |
---|
425 | counter++; |
---|
426 | file = |
---|
427 | new File("performance_result_" + Integer.toString(counter) |
---|
428 | + ".txt"); |
---|
429 | fileDetails = |
---|
430 | new File("performance_result_" + Integer.toString(counter) |
---|
431 | + "_details.txt"); |
---|
432 | } while (file.exists() || fileDetails.exists()); |
---|
433 | |
---|
434 | FileOutputStream out = new FileOutputStream(file); |
---|
435 | |
---|
436 | if (heapDet || nonHeapDet || jvmDet) |
---|
437 | outDetails = new FileOutputStream(fileDetails); |
---|
438 | |
---|
439 | StringBuilder header = new StringBuilder("Measuring time precisly: "); |
---|
440 | |
---|
441 | if (timePrec) |
---|
442 | header.append("yes\n"); |
---|
443 | else |
---|
444 | header.append("no\n"); |
---|
445 | |
---|
446 | header.append(String.format("Number of repets: %d\n", repeats)); |
---|
447 | header.append(String.format( |
---|
448 | "Interval between memory checking: %d ms\n", interval)); |
---|
449 | header.append(String.format("System memory: %d MB\n\n", memoryInMB)); |
---|
450 | |
---|
451 | header.append("Name\tTavg\tTstdev\t"); |
---|
452 | |
---|
453 | if (heap) |
---|
454 | header.append("HMavg\tHMstdev\t"); |
---|
455 | if (nonHeap) |
---|
456 | header.append("NMavg\tNMstdev\t"); |
---|
457 | if (jvm) |
---|
458 | header.append("JVMMavg\tJVMMstdev\t"); |
---|
459 | header.append('\n'); |
---|
460 | |
---|
461 | LOGGER.info("Measuring of performance begun"); |
---|
462 | |
---|
463 | try { |
---|
464 | |
---|
465 | out.write(header.toString().getBytes("UTF-8")); |
---|
466 | if (heapDet || nonHeapDet || jvmDet) |
---|
467 | outDetails |
---|
468 | .write(("Detailed analysis of memory usage with interval: " |
---|
469 | + interval + "ms\n\n").getBytes("UTF-8")); |
---|
470 | Collections.sort(records); |
---|
471 | for (String record : records) { |
---|
472 | out.write((record + "\t" + repeatTask(record) + "\n") |
---|
473 | .getBytes("UTF-8")); |
---|
474 | } |
---|
475 | } finally { |
---|
476 | if (out != null) |
---|
477 | out.close(); |
---|
478 | if (outDetails != null) |
---|
479 | outDetails.close(); |
---|
480 | } |
---|
481 | |
---|
482 | LOGGER.info("Measuring of performance ended succesfully"); |
---|
483 | |
---|
484 | for (int i = 0; i < noOfBeeps; i++) { |
---|
485 | Toolkit.getDefaultToolkit().beep(); |
---|
486 | Thread.sleep(1000); |
---|
487 | } |
---|
488 | } |
---|
489 | |
---|
490 | } |
---|