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    }