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 }