001: package com.tagtraum.perf.gcviewer;
002:
003: import com.tagtraum.perf.gcviewer.math.DoubleData;
004: import com.tagtraum.perf.gcviewer.math.IntData;
005: import com.tagtraum.perf.gcviewer.math.RegressionLine;
006:
007: import java.io.File;
008: import java.io.Serializable;
009: import java.io.IOException;
010: import java.io.InputStream;
011: import java.util.ArrayList;
012: import java.util.Iterator;
013: import java.util.List;
014: import java.util.logging.Logger;
015: import java.util.logging.Level;
016: import java.net.URL;
017: import java.net.URLConnection;
018: import java.net.HttpURLConnection;
019:
020: /**
021: * Collection of GCEvents.
022: * <p/>
023: * Date: Jan 30, 2002
024: * Time: 5:01:45 PM
025: *
026: * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
027: * @version $Id: $
028: */
029: public class GCModel implements Serializable {
030:
031: private static Logger LOG = Logger.getLogger(GCModel.class
032: .getName());
033:
034: private List allEvents;
035: private List events;
036: private List gcEvents;
037: private List concurrentGCEvents;
038: private List currentNoFullGCEvents;
039: private List fullGCEvents;
040: private long lastModified;
041: private long length;
042:
043: private long footprint;
044: private double runningTime;
045: private DoubleData pause;
046: private DoubleData fullGCPause;
047: private DoubleData gcPause;
048: private long freedMemory;
049: private Format format;
050: private IntData postGCUsedMemory;
051: private IntData postFullGCUsedMemory;
052: private IntData freedMemoryByGC;
053: private IntData freedMemoryByFullGC;
054: private DoubleData postGCSlope;
055: private RegressionLine currentPostGCSlope;
056: private RegressionLine currentRelativePostGCIncrease;
057: private DoubleData relativePostGCIncrease;
058: private RegressionLine postFullGCSlope;
059: private RegressionLine relativePostFullGCIncrease;
060: private boolean countTenuredAsFull = true;
061: private URL url;
062:
063: public GCModel(boolean countTenuredAsFull) {
064: this .countTenuredAsFull = countTenuredAsFull;
065: this .allEvents = new ArrayList();
066: this .events = new ArrayList();
067: this .gcEvents = new ArrayList();
068: this .concurrentGCEvents = new ArrayList();
069: this .fullGCEvents = new ArrayList();
070: this .currentNoFullGCEvents = new ArrayList();
071: this .currentPostGCSlope = new RegressionLine();
072: this .postFullGCSlope = new RegressionLine();
073: this .postGCSlope = new DoubleData();
074: this .freedMemoryByGC = new IntData();
075: this .freedMemoryByFullGC = new IntData();
076: this .postFullGCUsedMemory = new IntData();
077: this .postGCUsedMemory = new IntData();
078: this .pause = new DoubleData();
079: this .fullGCPause = new DoubleData();
080: this .gcPause = new DoubleData();
081: this .currentRelativePostGCIncrease = new RegressionLine();
082: this .relativePostGCIncrease = new DoubleData();
083: this .relativePostFullGCIncrease = new RegressionLine();
084: }
085:
086: public boolean isCountTenuredAsFull() {
087: return countTenuredAsFull;
088: }
089:
090: public long getLastModified() {
091: return lastModified;
092: }
093:
094: public URL getURL() {
095: return url;
096: }
097:
098: public void setURL(final URL url) {
099: this .url = url;
100: if (url.getProtocol().startsWith("http")) {
101: HttpURLConnection urlConnection = null;
102: try {
103: urlConnection = (HttpURLConnection) url
104: .openConnection();
105: urlConnection.setRequestMethod("HEAD");
106: this .length = urlConnection.getContentLength();
107: this .lastModified = urlConnection.getLastModified();
108: } catch (IOException e) {
109: if (LOG.isLoggable(Level.WARNING))
110: LOG.log(Level.WARNING,
111: "Failed to obtain age and length of URL "
112: + url, e);
113: } finally {
114: try {
115: if (urlConnection != null) {
116: final InputStream inputStream = urlConnection
117: .getInputStream();
118: if (inputStream != null) {
119: try {
120: inputStream.close();
121: } catch (IOException ignore) {
122: // ignore
123: }
124: }
125: }
126: } catch (IOException ignore) {
127: // ignore
128: }
129: }
130: } else {
131: URLConnection urlConnection = null;
132: try {
133: urlConnection = url.openConnection();
134: this .length = urlConnection.getContentLength();
135: this .lastModified = urlConnection.getLastModified();
136: } catch (IOException e) {
137: if (LOG.isLoggable(Level.WARNING))
138: LOG.log(Level.WARNING,
139: "Failed to obtain age and length of URL "
140: + url, e);
141: } finally {
142: try {
143: if (urlConnection != null) {
144: final InputStream inputStream = urlConnection
145: .getInputStream();
146: if (inputStream != null) {
147: try {
148: inputStream.close();
149: } catch (IOException ignore) {
150: // ignore
151: }
152: }
153: }
154: } catch (IOException ignore) {
155: // ignore
156: }
157: }
158: }
159: }
160:
161: public boolean isDifferent(File otherFile) {
162: // we just ignore the file name for now...
163: return this .lastModified != otherFile.lastModified()
164: || this .length != otherFile.length();
165: }
166:
167: public boolean isDifferent(URL otherURL) {
168: long otherLength = 0;
169: long otherLastModified = 0;
170: if (otherURL.getProtocol().startsWith("http")) {
171: HttpURLConnection urlConnection = null;
172: try {
173: urlConnection = (HttpURLConnection) otherURL
174: .openConnection();
175: urlConnection.setRequestMethod("HEAD");
176: otherLength = urlConnection.getContentLength();
177: otherLastModified = urlConnection.getLastModified();
178: } catch (IOException e) {
179: if (LOG.isLoggable(Level.WARNING))
180: LOG.log(Level.WARNING,
181: "Failed to obtain age and otherLength of URL "
182: + otherURL, e);
183: } finally {
184: try {
185: if (urlConnection != null) {
186: final InputStream inputStream = urlConnection
187: .getInputStream();
188: if (inputStream != null) {
189: try {
190: inputStream.close();
191: } catch (IOException ignore) {
192: // ignore
193: }
194: }
195: }
196: } catch (IOException ignore) {
197: // ignore
198: }
199: }
200: } else {
201: URLConnection urlConnection = null;
202: try {
203: urlConnection = otherURL.openConnection();
204: otherLength = urlConnection.getContentLength();
205: otherLastModified = urlConnection.getLastModified();
206: } catch (IOException e) {
207: if (LOG.isLoggable(Level.WARNING))
208: LOG.log(Level.WARNING,
209: "Failed to obtain age and otherLength of URL "
210: + otherURL, e);
211: } finally {
212: try {
213: if (urlConnection != null) {
214: final InputStream inputStream = urlConnection
215: .getInputStream();
216: if (inputStream != null) {
217: try {
218: inputStream.close();
219: } catch (IOException ignore) {
220: // ignore
221: }
222: }
223: }
224: } catch (IOException ignore) {
225: // ignore
226: }
227: }
228: }
229:
230: return this .lastModified != otherLastModified
231: || this .length != otherLength;
232: }
233:
234: public Iterator getGCEvents() {
235: return events.iterator();
236: }
237:
238: public Iterator getConcurrentGCEvents() {
239: return concurrentGCEvents.iterator();
240: }
241:
242: public Iterator getEvents() {
243: return allEvents.iterator();
244: }
245:
246: public void add(final AbstractGCEvent abstractEvent) {
247: allEvents.add(abstractEvent);
248: if (abstractEvent instanceof ConcurrentGCEvent) {
249: concurrentGCEvents.add(abstractEvent);
250: } else if (abstractEvent instanceof GCEvent) {
251: events.add(abstractEvent);
252: final GCEvent event = (GCEvent) abstractEvent;
253: footprint = Math.max(footprint, event.getTotal());
254: runningTime = Math.max(runningTime, event.getTimestamp());
255: freedMemory += event.getPreUsed() - event.getPostUsed();
256: pause.add(event.getPause());
257: if (event.getType().getGeneration() != GCEvent.Generation.TENURED
258: && !event.hasTenuredDetail()) {
259: gcEvents.add(event);
260: postGCUsedMemory.add(event.getPostUsed());
261: freedMemoryByGC.add(event.getPreUsed()
262: - event.getPostUsed());
263: currentNoFullGCEvents.add(event);
264: currentPostGCSlope.addPoint(event.getTimestamp(), event
265: .getPostUsed());
266: currentRelativePostGCIncrease.addPoint(
267: currentRelativePostGCIncrease.getPointCount(),
268: event.getPostUsed());
269: gcPause.add(event.getPause());
270: } else {
271: if (event.getType().getGeneration() == GCEvent.Generation.TENURED
272: || event.hasTenuredDetail()) {
273: fullGCEvents.add(event);
274: postFullGCUsedMemory.add(event.getPostUsed());
275: final int freed = event.getPreUsed()
276: - event.getPostUsed();
277: freedMemoryByFullGC.add(freed);
278: fullGCPause.add(event.getPause());
279: postFullGCSlope.addPoint(event.getTimestamp(),
280: event.getPostUsed());
281: relativePostFullGCIncrease.addPoint(
282: relativePostFullGCIncrease.getPointCount(),
283: event.getPostUsed());
284: }
285: // process no full-gc run data
286: if (currentPostGCSlope.hasPoints()) {
287: // make sure we have at least _two_ data points
288: if (currentPostGCSlope.isLine()) {
289: postGCSlope.add(currentPostGCSlope.slope(),
290: currentPostGCSlope.getPointCount());
291: relativePostGCIncrease.add(
292: currentRelativePostGCIncrease.slope(),
293: currentRelativePostGCIncrease
294: .getPointCount());
295: }
296: currentPostGCSlope.reset();
297: currentRelativePostGCIncrease.reset();
298: }
299: }
300: }
301: }
302:
303: public int size() {
304: return events.size();
305: }
306:
307: public AbstractGCEvent get(final int index) {
308: return (AbstractGCEvent) events.get(index);
309: }
310:
311: /**
312: * Pauses caused by full garbage collections.
313: */
314: public DoubleData getFullGCPause() {
315: return fullGCPause;
316: }
317:
318: /**
319: * Pauses caused by garbage collections.
320: */
321: public DoubleData getGCPause() {
322: return gcPause;
323: }
324:
325: /**
326: * The increase in memory consumption after a full collection in relation to the amount that was
327: * used after the previous full collection.
328: */
329: public RegressionLine getRelativePostFullGCIncrease() {
330: return relativePostFullGCIncrease;
331: }
332:
333: /**
334: * The increase in memory consumption after a collection in relation to the amount that was
335: * used after the previous collection.
336: */
337: public DoubleData getRelativePostGCIncrease() {
338: return relativePostGCIncrease;
339: }
340:
341: /**
342: * The average slope of the regression lines of the memory consumption after
343: * a garbage collection in between <em>full</em> garbage collections.
344: * <p/>
345: * The unit is kb/s.
346: */
347: public double getPostGCSlope() {
348: return postGCSlope.average();
349: }
350:
351: public IntData getPostGCUsedMemory() {
352: return postGCUsedMemory;
353: }
354:
355: public RegressionLine getCurrentPostGCSlope() {
356: return currentPostGCSlope;
357: }
358:
359: public RegressionLine getPostFullGCSlope() {
360: return postFullGCSlope;
361: }
362:
363: public IntData getPostFullGCUsedMemory() {
364: return postFullGCUsedMemory;
365: }
366:
367: /**
368: * Heap memory freed by a (small) garbage collection.
369: */
370: public IntData getFreedMemoryByGC() {
371: return freedMemoryByGC;
372: }
373:
374: /**
375: * Heap memory freed by a <em>full</em> garbage collection.
376: */
377: public IntData getFreedMemoryByFullGC() {
378: return freedMemoryByFullGC;
379: }
380:
381: /**
382: * Heap memory consumption after a (small) garbage collection.
383: */
384: public IntData getFootprintAfterGC() {
385: return postGCUsedMemory;
386: }
387:
388: /**
389: * Heap memory consumption after a <em>full</em> garbage collection.
390: */
391: public IntData getFootprintAfterFullGC() {
392: return postFullGCUsedMemory;
393: }
394:
395: /**
396: * Pause in sec.
397: */
398: public DoubleData getPause() {
399: return pause;
400: }
401:
402: /**
403: * Throughput in percent.
404: */
405: public double getThroughput() {
406: return 100 * (runningTime - pause.getSum()) / runningTime;
407: }
408:
409: /**
410: * Footprint in KB.
411: */
412: public long getFootprint() {
413: return footprint;
414: }
415:
416: /**
417: * Running time in sec.
418: */
419: public double getRunningTime() {
420: return runningTime;
421: }
422:
423: /**
424: * Freed memory in KB.
425: */
426: public long getFreedMemory() {
427: return freedMemory;
428: }
429:
430: public Format getFormat() {
431: return format;
432: }
433:
434: public void setFormat(final Format format) {
435: this .format = format;
436: }
437:
438: public boolean hasCorrectTimestamp() {
439: return format == Format.IBM_VERBOSE_GC
440: || format == Format.SUN_X_LOG_GC
441: || format == Format.SUN_1_2_2VERBOSE_GC;
442: }
443:
444: public String toString() {
445: return events.toString();
446: }
447:
448: public static class Format implements Serializable {
449: private String format;
450:
451: private Format(final String format) {
452: this .format = format;
453: }
454:
455: public String toString() {
456: return format;
457: }
458:
459: public static final Format SUN_VERBOSE_GC = new Format(
460: "Sun -verbose:gc");
461: public static final Format SUN_X_LOG_GC = new Format(
462: "Sun -Xloggc:<file>");
463: public static final Format IBM_VERBOSE_GC = new Format(
464: "IBM -verbose:gc");
465: public static final Format SUN_1_2_2VERBOSE_GC = new Format(
466: "Sun 1.2.2 -verbose:gc");
467: }
468: }
|