001 package jp.osdl.jbento2.analyzer;
002
003 import java.io.BufferedReader;
004 import java.io.BufferedWriter;
005 import java.io.FileWriter;
006 import java.io.IOException;
007 import java.io.InputStream;
008 import java.text.DecimalFormat;
009 import java.text.Format;
010 import java.text.ParseException;
011 import java.text.SimpleDateFormat;
012 import java.util.ArrayList;
013 import java.util.Date;
014 import java.util.HashMap;
015 import java.util.Iterator;
016 import java.util.LinkedList;
017 import java.util.List;
018 import java.util.Map;
019 import java.util.Properties;
020
021 import jp.osdl.jbento2.StateDateFormatter;
022
023 public class SarAnalyzer extends Analyzer {
024
025 private int skipLine = 2;
026
027 private char delimiter = ' ';
028
029 private SarResultBuilder srb = null;
030
031 private String skipTime;
032
033 private String termTime;
034
035 private StateDateFormatter formatter = new StateDateFormatter("HH:mm:ss",
036 StateDateFormatter.DATE);
037
038 private Date startTime = null;
039
040 private Date beginTime = null;
041
042 private Date endTime = null;
043
044 private SimpleDateFormat sformatter = new SimpleDateFormat("HH:mm:ss");
045
046 private Date previous = null;
047
048 private long newDateDelta = 6 * 3600 * 1000; // 6 hour
049
050 private Properties props = null;
051
052 private void setUpTimes(String str) {
053 if (skipTime != null || termTime != null) {
054 try {
055 startTime = formatter.nextDate(str);
056 if (skipTime != null) {
057 long second = Long.parseLong(skipTime);
058 beginTime = new Date(startTime.getTime() + second * 1000);
059 }
060 } catch (ParseException e) {
061 throw new IllegalArgumentException(e.getMessage());
062 }
063 if (termTime != null) {
064 long second = Long.parseLong(termTime);
065 if (beginTime != null) {
066 endTime = new Date(beginTime.getTime() + second * 1000);
067 } else {
068 endTime = new Date(startTime.getTime() + second * 1000);
069 }
070 }
071 }
072 }
073
074 public void analyze() throws Exception {
075
076 setup();
077
078 BufferedReader reader = null;
079
080 try {
081 reader = new BufferedReader(createReader());
082 for (int i = 0; i < skipLine; i++) {
083 reader.readLine();
084 }
085
086 String line = reader.readLine();
087 String[] data = parseLine(line);
088 setUpTimes(data[0]);
089 srb.firstRow(data);
090
091 while (true) {
092 line = reader.readLine();
093 if (line == null) {
094 break;
095 } else if (line.length() == 0) {
096 continue;
097 }
098 data = parseLine(line);
099
100 if (data[0].equals("Average:")) {
101 continue;
102 }
103
104 Date dataTime = null;
105 try {
106 dataTime = formatter.nextDate(data[0]);
107 } catch (ParseException e) {
108 // System.err.println(getSrc() + " parse error : " + data[0]);
109 // skip illegal data
110 continue;
111 }
112
113 if (beginTime != null) {
114 if (beginTime.compareTo(dataTime) > 0) {
115 continue;
116 } else {
117 beginTime = null;
118 }
119 }
120
121 if (endTime != null) {
122 if (endTime.compareTo(dataTime) < 0) {
123 break;
124 }
125 }
126
127 if (checkValidDate(data[0])) {
128 srb.addRow(data);
129 }
130 }
131
132 srb.end();
133 } finally {
134 reader.close();
135 }
136 }
137
138 private boolean checkValidDate(String dateStr) {
139 try {
140 boolean result = false;
141 Date now = sformatter.parse(dateStr);
142 if (previous == null) {
143 result = true;
144 } else {
145 long delta = now.getTime() - previous.getTime();
146 if (delta >= 0 || delta < -newDateDelta) {
147 // 21600000 msec means back over 6 hours, so it is maybe changing date
148 result = true;
149 }
150 }
151 if (result) {
152 previous = now;
153 }
154 return result;
155 } catch (ParseException e) {
156 return false;
157 }
158 }
159
160 public void average() throws Exception {
161
162 avgSetup();
163
164 BufferedReader reader = null;
165
166 try {
167 reader = new BufferedReader(createReader());
168 // for (int i = 0; i < skipLine; i++) {
169 // reader.readLine();
170 // }
171 String line = reader.readLine();
172
173 setDelimiter(',');
174 String[] data = parseLine(line);
175 //setUpTimes(data[0]);
176 srb.firstRow(data);
177
178 while (true) {
179 line = reader.readLine();
180 if (line == null) {
181 break;
182 } else if (line.length() == 0) {
183 continue;
184 }
185 data = parseLine(line);
186
187 if (data[0].equals("Average:")) {
188 break;
189 }
190
191 if (beginTime != null) {
192 if (beginTime.compareTo(formatter.nextDate(data[0])) > 0) {
193 continue;
194 } else {
195 beginTime = null;
196 }
197 }
198
199 if (endTime != null) {
200 if (endTime.compareTo(formatter.nextDate(data[0])) < 0) {
201 break;
202 }
203 }
204 srb.addRow(data);
205 }
206
207 srb.end();
208 } finally {
209 reader.close();
210 }
211 }
212
213 public void setup() throws AnalyzerException {
214
215 initProperties();
216
217 if (getParser() == null) {
218 throw new AnalyzerException("parser " + getParser() + " is invalid");
219 }
220
221 srb = getSarResultBuilder(getParser(), getDest());
222
223 if (srb == null) {
224 throw new AnalyzerException("parser " + getParser() + " is invalid");
225 }
226 }
227
228 public void avgSetup() throws AnalyzerException {
229 String[] average = { "cvs" };
230
231 if (getParser() == null) {
232 throw new AnalyzerException("parser " + getParser() + " is invalid");
233 }
234
235 for (int i = 0; i < average.length; i++) {
236 if (average[i].equals(getParser())) {
237 srb = new AverageSarResultBuilder(getDest());
238 break;
239 }
240 }
241 srb = new AverageSarResultBuilder(getDest());
242
243 if (srb == null) {
244 throw new AnalyzerException("parser " + getParser() + " is invalid");
245 }
246 }
247
248 protected String[] parseLine(String str) {
249 ArrayList list = new ArrayList();
250 char[] chars = str.toCharArray();
251 StringBuffer buffer = new StringBuffer();
252
253 for (int i = 0; i < chars.length; i++) {
254 if (chars[i] == delimiter) {
255 if (buffer.length() != 0) {
256 list.add(buffer.toString());
257 buffer = new StringBuffer();
258 }
259 } else if (chars[i] != delimiter) {
260 buffer.append(chars[i]);
261 }
262 }
263
264 if (buffer.length() != 0) {
265 list.add(buffer.toString());
266 }
267
268 return (String[]) list.toArray(new String[list.size()]);
269 }
270
271 public void setSkipTime(String skipTime) {
272 this.skipTime = skipTime;
273 }
274
275 public void setTermTime(String termTime) {
276 this.termTime = termTime;
277 }
278
279 private interface SarResultBuilder {
280 public void firstRow(String[] data);
281
282 public void addRow(String[] data);
283
284 public void end();
285 }
286
287 private class SimpleSarResultBuilder implements SarResultBuilder {
288 protected String destName = null;
289
290 TextTable tt = null;
291
292 int colNum;
293 double colValue[];
294 int counter = 0;
295 String headerNameForCheck;
296
297 public SimpleSarResultBuilder(String dest) {
298 if (dest.equals("result")) {
299 destName = getSrc().substring(0, getSrc().lastIndexOf('.'))
300 + ".csv";
301 } else {
302 destName = dest;
303 }
304 }
305
306 public void firstRow(String[] data) {
307 colNum = data.length;
308 tt = new TextTable(colNum, TextTable.ALIGN_RIGHT, ",");
309 data[0] = "time";
310 tt.addRow(data);
311 headerNameForCheck = data[1];
312 }
313
314 public void addRow(String[] data) {
315 if (data.length != colNum) {
316 return;
317 }
318
319 // skip header line
320 if (data[1].equals(headerNameForCheck)) {
321 return;
322 }
323
324 tt.addRow(data);
325
326 }
327
328 public void end() {
329
330 BufferedWriter writer = null;
331 try {
332 writer = new BufferedWriter(new FileWriter(destName));
333 writer.write(tt.toString());
334 writer.flush();
335 } catch (IOException e) {
336 e.printStackTrace(System.err);
337 } finally {
338 try {
339 writer.close();
340 } catch (IOException e) {
341 // nothing to do
342 }
343 }
344 }
345 }
346
347 private class MultiSarResultBuilder implements SarResultBuilder {
348 protected String destName = null;
349
350 Map map = new HashMap();
351
352 String columnName = null;
353
354 int colIndex;
355
356 int colNum;
357
358 String[] firstData;
359
360 public MultiSarResultBuilder(String dest) {
361 if (dest.equals("result")) {
362 destName = getSrc().substring(0, getSrc().lastIndexOf('.'));
363 } else {
364 destName = dest.substring(0, dest.lastIndexOf('.'));
365 }
366 }
367
368 public void setColumnName(String columnName) {
369 this.columnName = columnName;
370 }
371
372 public void firstRow(String[] data) {
373 colNum = data.length;
374 for (colIndex = 0; colIndex < colNum; colIndex++) {
375 if (data[colIndex].equals(columnName)) {
376 break;
377 }
378 }
379 if (colIndex == colNum) {
380 throw new AnalyzerException(columnName + " is not found.");
381 }
382
383 firstData = new String[colNum - 1];
384 for (int i = 0, j = 0; i < colNum; i++) {
385 if (i != colIndex) {
386 firstData[j] = data[i];
387 j++;
388 }
389 }
390 firstData[0] = "time";
391 }
392
393 public void addRow(String[] data) {
394 // skip deficient data
395 if (data.length != colNum) {
396 return;
397 }
398
399 // skip header line
400 if (data[colIndex].equals(columnName)) {
401 return;
402 }
403
404 String[] added = new String[colNum - 1];
405 for (int i = 0, j = 0; i < colNum; i++) {
406 if (i != colIndex) {
407 added[j] = data[i];
408 j++;
409 }
410 }
411
412 TextTable tt = (TextTable) map.get(data[colIndex]);
413 if (tt == null) {
414 tt = new TextTable(colNum - 1, TextTable.ALIGN_RIGHT, ",");
415 tt.addRow(firstData);
416 map.put(data[colIndex], tt);
417 }
418 tt.addRow(added);
419
420
421 }
422
423 public void end() {
424 Iterator ite = map.keySet().iterator();
425 while (ite.hasNext()) {
426 String key = (String) ite.next();
427 TextTable tt = (TextTable) map.get(key);
428 String fileName = destName + "." + key + ".csv";
429 BufferedWriter writer = null;
430 try {
431 writer = new BufferedWriter(new FileWriter(fileName));
432 writer.write(tt.toString());
433 writer.flush();
434 } catch (IOException e) {
435 e.printStackTrace(System.err);
436 } finally {
437 try {
438 writer.close();
439 } catch (IOException e) {
440 // nothing to do
441 }
442 }
443 }
444 }
445 }
446
447 private class CPUSarResultBuilder extends MultiSarResultBuilder {
448
449 private static final int LAST_INDEX = 5;
450
451 TextTable tt = null;
452
453 String currentTime = null;
454
455 List list = null;
456
457 List header = null;
458
459 Map cpuValue = new HashMap();
460
461 boolean parseHeader = true;
462
463 int colNum = 0;
464
465 Format formatter = null;
466
467 public CPUSarResultBuilder(String dest) {
468 super(dest);
469 currentTime = "";
470 list = new LinkedList();
471 header = new LinkedList();
472 header.add("time");
473 formatter = new DecimalFormat("##0.00");
474 }
475
476 public void firstRow(String[] data) {
477 super.firstRow(data);
478 }
479
480 public void addRow(String[] data) {
481 super.addRow(data);
482
483 // skip header line
484 if (data[colIndex].equals(columnName)) {
485 return;
486 }
487
488 if (!currentTime.equals(data[0])) {
489 // when the time is changed
490 if (currentTime.length() != 0) {
491
492 // when the first change, initialize TextTable
493 if (tt == null) {
494 colNum = header.size();
495 tt = new TextTable(colNum, TextTable.ALIGN_RIGHT, ",");
496 tt.addRow((String[]) header
497 .toArray(new String[colNum]));
498 parseHeader = false;
499
500 }
501
502 tt.addRow(createAddedData());
503
504 cpuValue.clear();
505 }
506 currentTime = data[0];
507 }
508
509 if (parseHeader) {
510 header.add(data[1]);
511 }
512
513 double d = 0;
514 for (int i = 2; i <= LAST_INDEX; i++) {
515 double val = Double.parseDouble(data[i]);
516 d += val;
517 }
518 cpuValue.put(data[1], formatter.format(new Double(d)));
519 }
520
521 private String[] createAddedData() {
522 String[] values = new String[colNum];
523 values[0] = currentTime;
524 for (int i = 1; i < colNum; i++) {
525 values[i] = (String) cpuValue.get(header.get(i));
526 }
527 return values;
528 }
529
530 public void end() {
531 super.end();
532
533 if (cpuValue.size() == colNum - 1) {
534 tt.addRow(createAddedData());
535 }
536 String fileName = destName + ".sum.csv";
537 BufferedWriter writer = null;
538
539 if (tt == null) {
540 System.out.println(fileName + " has no data.");
541 return;
542 }
543
544 try {
545 writer = new BufferedWriter(new FileWriter(fileName));
546 writer.write(tt.toString());
547 writer.flush();
548 } catch (IOException e) {
549 e.printStackTrace(System.err);
550 } finally {
551 try {
552 writer.close();
553 } catch (IOException e) {
554 // nothing to do
555 }
556 }
557 }
558
559 }
560
561 private class AverageSarResultBuilder implements SarResultBuilder {
562 protected String destName = null;
563
564 TextTable tt = null;
565
566 int colNum;
567 double colValue[];
568 int counter = 0;
569 Format formatter = null;
570
571 public AverageSarResultBuilder(String dest) {
572 if (dest.equals("result")) {
573 destName = getSrc().substring(0, getSrc().lastIndexOf('.'));
574 } else {
575 destName = dest.substring(0, dest.lastIndexOf('.'));
576 }
577 formatter = new DecimalFormat("##0.00");
578 }
579
580 public void firstRow(String[] data) {
581 colNum = data.length;
582
583 tt = new TextTable(colNum, TextTable.ALIGN_RIGHT, ",");
584 data[0] = "";
585 tt.addRow(data);
586
587 for (int i = 1;i < colNum;i++) {
588 colValue = new double[colNum];
589 }
590
591 }
592
593 public void addRow(String[] data) {
594
595 if (data.length != colNum) {
596 return;
597 }
598
599 for (int i = 1;i < colNum;i++) {
600 double val = Double.parseDouble(data[i]);
601 colValue[i] += val;
602 }
603 counter++;
604
605 }
606
607 private String[] createAverageData() {
608 String[] values = new String[colNum];
609 values[0] = "average";
610 for (int i = 1; i < colNum;i++) {
611 values[i] = formatter.format(new Double(colValue[i] / counter));
612 }
613 return values;
614 }
615
616 public void end() {
617
618 tt.addRow(createAverageData());
619
620 String fileName = destName + ".average.csv";
621 BufferedWriter writer_avg = null;
622
623 if(tt == null) {
624 System.out.println(fileName + "has no data.");
625 return;
626 }
627
628 try {
629 writer_avg = new BufferedWriter(new FileWriter(fileName));
630 writer_avg.write(tt.toString());
631 writer_avg.flush();
632 } catch (IOException e) {
633 e.printStackTrace(System.err);
634 } finally {
635 try {
636 writer_avg.close();
637 } catch (IOException e) {
638 //nothing todo
639 }
640 }
641 // System.out.println(fileName + " is generated.");
642 }
643 }
644
645 /*
646 * Add kbrealmemused and kbrealswpused column
647 * kbrealmemused = kbmemused - kbbuffers - kbcached
648 * kbrealswpused = kbswpused - kbswpcad
649 */
650 private class MemorySarResultBuilder extends SimpleSarResultBuilder {
651
652 int indexKbmemused = 0;
653 int indexKbbuffers = 0;
654 int indexKbcached = 0;
655 int indexKbswpused = 0;
656 int indexKbswpcad = 0;
657 String headerNameForCheck;
658
659 public MemorySarResultBuilder(String dest) {
660 super(dest);
661 }
662
663 public void firstRow(String[] data) {
664 String[] addedData = new String[data.length + 2];
665 colNum = data.length + 2;
666 tt = new TextTable(colNum, TextTable.ALIGN_RIGHT, ",");
667 addedData[0] = "time";
668 for (int i = 1; i < data.length; i++) {
669 addedData[i] = data[i];
670 if ("kbmemused".equals(data[i])) {
671 indexKbmemused = i;
672 } else if ("kbbuffers".equals(data[i])) {
673 indexKbbuffers = i;
674 } else if ("kbcached".equals(data[i])) {
675 indexKbcached = i;
676 } else if ("kbswpused".equals(data[i])) {
677 indexKbswpused = i;
678 } else if ("kbswpcad".equals(data[i])) {
679 indexKbswpcad = i;
680 }
681 }
682 addedData[colNum - 2] = "kbrealmemused";
683 addedData[colNum - 1] = "kbrealswpused";
684 tt.addRow(addedData);
685 headerNameForCheck = data[1];
686 }
687
688 public void addRow(String[] data) {
689 if (data.length != colNum - 2) {
690 return;
691 }
692
693 // skip header line
694 if (data[1].equals(headerNameForCheck)) {
695 return;
696 }
697
698 String[] addedData = new String[colNum];
699 for (int i = 0; i < data.length; i++) {
700 addedData[i] = data[i];
701 }
702 addedData[colNum - 2] = Long.toString(Long
703 .parseLong(data[indexKbmemused])
704 - Long.parseLong(data[indexKbbuffers])
705 - Long.parseLong(data[indexKbcached]));
706 if (indexKbswpcad != 0) {
707 addedData[colNum - 1] = Long.toString(
708 Long.parseLong(data[indexKbswpused])
709 - Long.parseLong(data[indexKbswpcad]));
710 } else {
711 addedData[colNum - 1] = data[indexKbswpused];
712 }
713 tt.addRow(addedData);
714 }
715
716 public void end() {
717
718 BufferedWriter writer = null;
719 try {
720 writer = new BufferedWriter(new FileWriter(destName));
721 writer.write(tt.toString());
722 writer.flush();
723 } catch (IOException e) {
724 e.printStackTrace(System.err);
725 } finally {
726 try {
727 writer.close();
728 } catch (IOException e) {
729 // nothing to do
730 }
731 }
732 }
733 }
734
735 public char getDelimiter() {
736 return delimiter;
737 }
738
739 public void setDelimiter(char delimiter) {
740 this.delimiter = delimiter;
741 }
742
743 private void initProperties() throws AnalyzerException {
744 Properties p = new Properties();
745 InputStream in = null;
746 try {
747 in = getClass().getResourceAsStream("jbento-sar.properties");
748 p.load(in);
749 } catch (IOException e) {
750 e.printStackTrace(System.err);
751 throw new AnalyzerException(e.getMessage());
752 } finally {
753 if (in != null) {
754 try {
755 in.close();
756 } catch (IOException ignore) {
757 }
758 }
759 }
760 this.props = p;
761 }
762
763 private SarResultBuilder getSarResultBuilder(String parser, String dest) {
764 SarResultBuilder result = null;
765 String builderName = props.getProperty("builder." + parser);
766 if (builderName == null) {
767 throw new AnalyzerException("parser " + " is invalid");
768 }
769 if (builderName.equals("simple")) {
770 result = new SimpleSarResultBuilder(dest);
771 } else if (builderName.equals("multi")) {
772 result = new MultiSarResultBuilder(dest);
773 } else if (builderName.equals("cpu")) {
774 result = new CPUSarResultBuilder(dest);
775 } else if (builderName.equals("memory")) {
776 result = new MemorySarResultBuilder(dest);
777 }
778
779 if (result instanceof MultiSarResultBuilder) {
780 String columnName = props.getProperty("mcolumn." + parser);
781 ((MultiSarResultBuilder) result).setColumnName(columnName);
782 }
783
784 return result;
785 }
786
787 public long getNewDateDelta() {
788 return newDateDelta;
789 }
790
791 public void setNewDateDelta(long newDateDelta) {
792 this.newDateDelta = newDateDelta;
793 }
794 }