001    package jp.osdl.jbento2.analyzer;
002    
003    import java.io.IOException;
004    import java.io.Reader;
005    import java.util.regex.Matcher;
006    import java.util.regex.Pattern;
007    
008    public class GCParserImpl implements GCParser {
009    
010        private static final String ELEMENT_FIRST = "[";
011    
012        private static final String ELEMENT_END = "]";
013    
014        Pattern numberPattern = Pattern.compile("\\d*\\.\\d*");
015    
016        Pattern transitionHeapPattern = Pattern.compile("(\\d*)K->(\\d*)K");
017    
018        Pattern numberHeapPattern = Pattern.compile("(\\d*)K");
019    
020        Pattern cmsPattern = Pattern.compile("CMS-concurrent-.*");
021    
022        Pattern cmsIllegalPattern = Pattern.compile("CMS(\\d*):");
023    
024        long currentPermMax = 0;
025    
026        long currentPermSize = 0;
027    
028        public GCList parse(Reader reader) throws IOException {
029            GCList gcList = new GCList();
030            GCTokenizer gct = new GCTokenizer(reader);
031            String token;
032    
033            while ((token = gct.getToken()) != null) {
034                try {
035                    Matcher matcher = numberPattern.matcher(token);
036                    if (!matcher.matches()) {
037                        gct.skipLine();
038                        continue;
039                    }
040                    double startTime = Double.parseDouble(token);
041    
042                    token = gct.getToken();
043                    if (!":".equals(token)) {
044                        gct.skipLine();
045                        continue;
046                    }
047                    token = gct.getToken();
048                    if (!ELEMENT_FIRST.equals(token)) {
049                        gct.skipLine();
050                        continue;
051                    }
052    
053                    token = gct.getToken();
054                    GCSample sample = getGCSample(token, gct);
055                    if (sample != null) {
056                        sample.setStartTime((long) (startTime * 1000));
057                        sample.calculate();
058                        gcList.add(sample);
059                    }
060                } catch (Exception ex) {
061                    System.out.println("error at " + gct.getLineNumber()
062                            + " gc analyzing");
063                    ex.printStackTrace();
064                    continue;
065                }
066            }
067            return gcList;
068        }
069    
070        public GCSample getGCSample(String keyToken, GCTokenizer gct)
071                throws IOException {
072            GCSample sample = null;
073            if ("GC".equals(keyToken)) {
074                sample = new GCSample();
075                sample.setType(GCSample.TYPE_GC);
076            } else if ("Full".equals(keyToken)) {
077                keyToken = gct.getToken();
078                if ("GC".equals(keyToken)) {
079                    sample = new GCSample();
080                    sample.setType(GCSample.TYPE_FULL_GC);
081                }
082            } else {
083                Matcher matcher = cmsPattern.matcher(keyToken);
084                if (matcher.matches()) {
085                    gct.skipLine();
086                    return null;
087                }
088                gct.skipLine();
089                throw new IllegalStateException("keyToken '" + keyToken
090                        + "' is invalid.");
091            }
092    
093            while (true) {
094                String token = gct.getToken();
095                if (ELEMENT_FIRST.equals(token)) {
096                    token = gct.getToken();
097                    if ("DefNew".equals(token) || "ParNew".equals(token)
098                            || "PSYoungGen".equals(token)) {
099                        GCTransition newGC = getNewGC(token, gct);
100                        sample.setNewGC(newGC);
101                        continue;
102                    } else if ("Tenured".equals(token)) {
103                        GCTransition tenuredGC = getTenuredGC(token, gct);
104                        sample.setTenuredGC(tenuredGC);
105                        continue;
106                    } else if (token.startsWith("CMS")) {
107                        processCMS(token, gct, sample);
108                        continue;
109                    } else if ("Perm".equals(token)) {
110                        GCTransition permGC = getPermGC("Perm", gct);
111                        sample.setPermGC(permGC);
112                        continue;
113                    } else if ("1".equals(token) || "YG".equals(token)) {
114                        gct.skipLine();
115                        return null;
116                    }
117                    gct.skipLine();
118                    throw new IllegalStateException("token '" + token
119                            + "' is invalid.");
120                } else if (ELEMENT_END.equals(token)) {
121                    break;
122                } else if (":".equals(token)) {
123                    continue;
124                } else {
125                    if (checkAndSetProcessingTime(token, gct, sample)) {
126                        continue;
127                    }
128                    if (checkAndSetTransitionHeap(token, gct, sample)) {
129                        continue;
130                    }
131                    gct.skipLine();
132                    throw new IllegalStateException("token '" + token
133                            + "' is invalid.");
134                }
135            }
136            if (sample.getPermGC().getAfterSize() == -1) {
137                sample.getPermGC().setBeforeSize(currentPermSize);
138                sample.getPermGC().setAfterSize(currentPermSize);
139                sample.getPermGC().setMaxSize(currentPermMax);
140            } else {
141                currentPermSize = sample.getPermGC().getAfterSize();
142                currentPermMax = sample.getPermGC().getMaxSize();
143            }
144            return sample;
145        }
146    
147        public void processCMS(String keyToken, GCTokenizer gct, GCSample sample)
148                throws IOException {
149            String token = gct.getToken();
150            if (":".equals(token)) {
151                GCTransition tenuredGC = getTenuredGC("CMS", gct);
152                sample.setTenuredGC(tenuredGC);
153            } else if ("(".equals(token)) {
154                gct.skipTo(')');
155                GCTransition tenuredGC = getTenuredGC("CMS", gct);
156                sample.setTenuredGC(tenuredGC);
157            } else if ("Perm".equals(token)) {
158                GCTransition permGC = getPermGC("CMS", gct);
159                sample.setPermGC(permGC);
160            } else {
161                gct.skipLine();
162                throw new IllegalStateException("token '" + token + "' is invalid.");
163            }
164        }
165    
166        public GCTransition getNewGC(String keyToken, GCTokenizer gct)
167                throws IOException {
168            GCTransition result = new GCTransition();
169            String token = keyToken;
170    
171            while (true) {
172                if ("DefNew".equals(token) || "ParNew".equals(token)
173                        || "PSYoungGen".equals(token)) {
174                    token = gct.getToken();
175                    continue;
176                }
177                if (ELEMENT_END.equals(token)) {
178                    break;
179                }
180                if (ELEMENT_FIRST.equals(token)) {
181                    gct.skipTo(']');
182                    token = gct.getToken();
183                    continue;
184                }
185                if (":".equals(token)) {
186                    token = gct.getToken();
187                    continue;
188                }
189                if ("(".equals(token)) {
190                    gct.skipTo(')');
191                    token = gct.getToken();
192                    continue;
193                }
194                if (checkAndSetTransitionHeap(token, gct, result)) {
195                    token = gct.getToken();
196                    continue;
197                }
198                if (checkAndSetProcessingTime(token, gct, result)) {
199                    token = gct.getToken();
200                    continue;
201                }
202                gct.skipLine();
203                throw new IllegalStateException("token '" + token + "' is invalid.");
204            }
205            return result;
206        }
207    
208        public GCTransition getTenuredGC(String keyToken, GCTokenizer gct)
209                throws IOException {
210            GCTransition result = new GCTransition();
211    
212            String token = keyToken;
213            while (true) {
214                if ("Tenured".equals(token) || "CMS".equals(token)) {
215                    token = gct.getToken();
216                    continue;
217                }
218                if (ELEMENT_END.equals(token)) {
219                    break;
220                }
221                if (ELEMENT_FIRST.equals(token)) {
222                    gct.skipTo(']');
223                    token = gct.getToken();
224                    continue;
225                }
226                if (":".equals(token)) {
227                    token = gct.getToken();
228                    continue;
229                }
230                if ("(".equals(token)) {
231                    gct.skipTo(')');
232                    token = gct.getToken();
233                    continue;
234                }
235                if (checkAndSetTransitionHeap(token, gct, result)) {
236                    token = gct.getToken();
237                    continue;
238                }
239                if (checkAndSetProcessingTime(token, gct, result)) {
240                    token = gct.getToken();
241                    continue;
242                }
243                gct.skipLine();
244                throw new IllegalStateException("token '" + token + "' is invalid.");
245            }
246            return result;
247        }
248    
249        public GCTransition getPermGC(String keyToken, GCTokenizer gct)
250                throws IOException {
251            GCTransition result = new GCTransition();
252            while (true) {
253                String token = gct.getToken();
254                if (ELEMENT_END.equals(token)) {
255                    break;
256                }
257                if (ELEMENT_FIRST.equals(token)) {
258                    gct.skipTo(']');
259                }
260                if (":".equals(token)) {
261                    continue;
262                }
263                if (checkAndSetTransitionHeap(token, gct, result)) {
264                    continue;
265                }
266                if (checkAndSetProcessingTime(token, gct, result)) {
267                    continue;
268                }
269                gct.skipLine();
270                throw new IllegalStateException("token '" + token + "' is invalid.");
271            }
272            return result;
273        }
274    
275        public boolean checkAndSetTransitionHeap(String token, GCTokenizer gct,
276                GCTransition transition) throws IOException {
277            Matcher matcher = transitionHeapPattern.matcher(token);
278            if (matcher.matches()) {
279                long before = Long.parseLong(matcher.group(1));
280                long after = Long.parseLong(matcher.group(2));
281                transition.setBeforeSize(before);
282                transition.setAfterSize(after);
283    
284                gct.getToken(); // "("
285                matcher = numberHeapPattern.matcher(gct.getToken());
286                if (matcher.matches()) {
287                    long max = Long.parseLong(matcher.group(1));
288                    transition.setMaxSize(max);
289                }
290                gct.getToken(); // ")"
291                return true;
292            }
293            return false;
294        }
295    
296        public boolean checkAndSetProcessingTime(String token, GCTokenizer gct,
297                GCTransition transition) throws IOException {
298            Matcher matcher = numberPattern.matcher(token);
299            if (matcher.matches()) {
300                String nextToken = gct.getToken();
301                if ("secs".equals(nextToken)) {
302                    double time = Double.parseDouble(token);
303                    transition.setProcessingTime((long) (time * 1000));
304                }
305                return true;
306            }
307            return false;
308        }
309    
310    }