# HG changeset patch # User shade # Date 1485944924 -3600 # Node ID 5324a16e1e63ead7ac42518b9e896ce73d1a4d3e # Parent a54d31fa96303742285c4a7a6acddefcd8fc1abe Runtime metrics graph. diff -r a54d31fa9630 -r 5324a16e1e63 src/main/java/org/openjdk/shenandoah/Colors.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/openjdk/shenandoah/Colors.java Wed Feb 01 11:28:44 2017 +0100 @@ -0,0 +1,13 @@ +package org.openjdk.shenandoah; + +import java.awt.*; + +public class Colors { + + static final Color USED_ALLOC = new Color(0, 250, 250); + static final Color USED = new Color(150, 150, 150); + static final Color LIVE = new Color(0, 200, 0); + static final Color LIVE_BORDER = new Color(0, 100, 0); + static final Color CSET = Color.YELLOW; + static final Color HUMONGOUS = Color.RED; +} diff -r a54d31fa9630 -r 5324a16e1e63 src/main/java/org/openjdk/shenandoah/DataProvider.java --- a/src/main/java/org/openjdk/shenandoah/DataProvider.java Wed Feb 01 10:16:06 2017 +0100 +++ b/src/main/java/org/openjdk/shenandoah/DataProvider.java Wed Feb 01 11:28:44 2017 +0100 @@ -10,11 +10,13 @@ private final int maxRegions; private final long maxSize; private final LongMonitor[] data; + private final LongMonitor timestamp; private final LongMonitor status; public DataProvider(String id) throws Exception { MonitoredHost host = MonitoredHost.getMonitoredHost(id); MonitoredVm vm = host.getMonitoredVm(new VmIdentifier(id)); + timestamp = (LongMonitor) vm.findByName("sun.gc.shenandoah.regions.timestamp"); LongMonitor max_regions_mon = (LongMonitor) vm.findByName("sun.gc.shenandoah.regions.max_regions"); maxRegions = (int) max_regions_mon.longValue(); LongMonitor max_size_mon = (LongMonitor) vm.findByName("sun.gc.shenandoah.regions.region_size"); @@ -41,7 +43,8 @@ boolean isMarking = (status.longValue() & 0x1) > 0; boolean isEvacuating = (status.longValue() & 0x2) > 0; - return new Snapshot(System.currentTimeMillis(), maxSize, stats, isMarking, isEvacuating); + long time = timestamp.longValue(); + return new Snapshot(time, maxSize, stats, isMarking, isEvacuating); } } diff -r a54d31fa9630 -r 5324a16e1e63 src/main/java/org/openjdk/shenandoah/RegionStat.java --- a/src/main/java/org/openjdk/shenandoah/RegionStat.java Wed Feb 01 10:16:06 2017 +0100 +++ b/src/main/java/org/openjdk/shenandoah/RegionStat.java Wed Feb 01 11:28:44 2017 +0100 @@ -3,6 +3,8 @@ import java.awt.*; import java.util.EnumSet; +import static org.openjdk.shenandoah.Colors.*; + public class RegionStat { private static final int USED_MASK = 0x1fffffff; @@ -47,29 +49,28 @@ int usedWidth = (int) (width * usedLvl); g.setColor( flags.contains(RegionFlag.RECENTLY_ALLOCATED) ? - new Color(0, 250, 250) : - new Color(150, 150, 150) + USED_ALLOC : USED ); g.fillRect(x, y, usedWidth, height); if (!flags.contains(RegionFlag.RECENTLY_ALLOCATED)) { int liveWidth = (int) (width * liveLvl); - g.setColor(new Color(0, 200, 0)); + g.setColor(LIVE); g.fillRect(x, y, liveWidth, height); - g.setColor(new Color(0, 100, 0)); + g.setColor(LIVE_BORDER); g.drawLine(x + liveWidth, y, x + liveWidth, y + height); } if (flags.contains(RegionFlag.IN_COLLECTION_SET)) { - g.setColor(Color.YELLOW); + g.setColor(Colors.CSET); g.fillRect(x, y, width, height / 3); g.setColor(Color.BLACK); g.drawRect(x, y, width, height / 3); } if (flags.contains(RegionFlag.HUMONGOUS)) { - g.setColor(Color.RED); + g.setColor(Colors.HUMONGOUS); g.fillRect(x, y, width, height / 3); g.setColor(Color.BLACK); g.drawRect(x, y, width, height / 3); @@ -121,4 +122,9 @@ public double used() { return usedLvl; } + + public EnumSet flags() { + return flags; + } + } diff -r a54d31fa9630 -r 5324a16e1e63 src/main/java/org/openjdk/shenandoah/ShenandoahVisualizer.java --- a/src/main/java/org/openjdk/shenandoah/ShenandoahVisualizer.java Wed Feb 01 10:16:06 2017 +0100 +++ b/src/main/java/org/openjdk/shenandoah/ShenandoahVisualizer.java Wed Feb 01 11:28:44 2017 +0100 @@ -29,9 +29,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; -import java.util.EnumSet; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -47,7 +45,6 @@ static volatile BufferedImage renderedImage; private static volatile int width; private static volatile int height; - static final long START_TIME = System.currentTimeMillis(); static class VisPanel extends JPanel { public void paint(Graphics g) { @@ -84,18 +81,13 @@ ScheduledFuture f = service.scheduleAtFixedRate(() -> { Snapshot cur = data.snapshot(); if (!cur.equals(lastSnapshot)) { - renderedImage = render(cur, width, height); + renderedImage = render(cur, lastSnapshots, width, height); lastSnapshot = cur; + lastSnapshots.add(new SnapshotView(cur)); + if (lastSnapshots.size() > 2500) { + lastSnapshots.removeFirst(); + } } - long max = cur.total() / 1024 / 1024; - System.out.format("%d, %d, %d, %d, %d, %d, %n", - cur.time() - START_TIME, - max, - cur.isMarking() ? max : 0, - cur.isEvacuating() ? max : 0, - cur.live() / 1024 / 1024, - cur.used() / 1024 / 1024 - ); frame.repaint(); }, 0, 10, TimeUnit.MILLISECONDS); @@ -109,16 +101,18 @@ f.get(); } + static final LinkedList lastSnapshots = new LinkedList<>(); + static volatile Snapshot lastSnapshot; - public static BufferedImage render(Snapshot snapshot, int width, int height) { + public static BufferedImage render(Snapshot snapshot, LinkedList lastSnapshots, int width, int height) { BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = img.getGraphics(); final int PAD = 20; final int LINE = 20; - final int PAD_TOP = 100; + final int PAD_TOP = 200; final int PAD_RIGHT = 300; int fieldWidth = img.getWidth() - (PAD + PAD_RIGHT); @@ -133,7 +127,7 @@ // Draw extra data g.setColor(Color.BLACK); - g.drawString("Time: " + (snapshot.time() - START_TIME) + " ms", PAD, PAD); + g.drawString("Time: " + (snapshot.time() / 1024 / 1024) + " ms", 2*PAD + fieldWidth, PAD); // Draw status g.setColor(Color.BLACK); @@ -147,11 +141,52 @@ if (status.isEmpty()) { status = " (idle)"; } - g.drawString("Status: " + status, PAD, PAD + 1 * LINE); + g.drawString("Status: " + status, 2*PAD + fieldWidth, PAD + 1 * LINE); + + g.drawString("Total: " + (snapshot.total()) + " KB", 2*PAD + fieldWidth, PAD + 2 * LINE); + g.drawString("Used: " + (snapshot.used()) + " KB", 2*PAD + fieldWidth, PAD + 3 * LINE); + g.drawString("Live: " + (snapshot.live()) + " KB", 2*PAD + fieldWidth, PAD + 4 * LINE); + + // Draw graph + { + int Y_SIZE = PAD_TOP - PAD; + int X_SIZE = fieldWidth; + + g.setColor(Color.BLACK); + g.fillRect(PAD, PAD, X_SIZE, Y_SIZE); + + if (lastSnapshots.size() > 2) { + double stepY = 1D * Y_SIZE / snapshot.total(); + long firstTime = lastSnapshots.getFirst().time(); + long lastTime = lastSnapshots.getLast().time(); + double stepX = 1D * X_SIZE / (lastTime - firstTime); + for (SnapshotView s : lastSnapshots) { + int x = (int) (PAD + (s.time() - firstTime) * stepX); - g.drawString("Total: " + (snapshot.total() / 1024 / 1024) + " MB", PAD, PAD + 2 * LINE); - g.drawString("Used: " + (snapshot.used() / 1024 / 1024) + " MB", PAD, PAD + 3 * LINE); - g.drawString("Live: " + (snapshot.live() / 1024 / 1024) + " MB", PAD, PAD + 4 * LINE); + if (s.isMarking()) { + g.setColor(new Color(100, 100, 0)); + g.drawRect(x, PAD, 1, Y_SIZE); + } + + if (s.isEvacuating()) { + g.setColor(new Color(100, 0, 0)); + g.drawRect(x, PAD, 1, Y_SIZE); + } + + g.setColor(Colors.USED); + g.drawRect(x, PAD + (int) (Y_SIZE - s.used() * stepY), 1, 1); + g.setColor(Colors.USED_ALLOC); + g.drawRect(x, PAD + (int) (Y_SIZE - s.recentlyAllocated() * stepY), 1, 1); + g.setColor(Colors.HUMONGOUS); + g.drawRect(x, PAD + (int) (Y_SIZE - s.humongous() * stepY), 1, 1); + g.setColor(Colors.LIVE); + g.drawRect(x, PAD + (int) (Y_SIZE - s.live() * stepY), 1, 1); + g.setColor(Colors.CSET); + g.drawRect(x, PAD + (int) (Y_SIZE - s.collectionSet() * stepY), 1, 1); + + } + } + } // Draw legend final int LEGEND_X = PAD + fieldWidth + sqSize; diff -r a54d31fa9630 -r 5324a16e1e63 src/main/java/org/openjdk/shenandoah/Snapshot.java --- a/src/main/java/org/openjdk/shenandoah/Snapshot.java Wed Feb 01 10:16:06 2017 +0100 +++ b/src/main/java/org/openjdk/shenandoah/Snapshot.java Wed Feb 01 11:28:44 2017 +0100 @@ -41,6 +41,7 @@ Snapshot snapshot = (Snapshot) o; + if (time != snapshot.time) return false; if (isMarking != snapshot.isMarking) return false; if (isEvacuating != snapshot.isEvacuating) return false; return stats != null ? stats.equals(snapshot.stats) : snapshot.stats == null; @@ -48,7 +49,8 @@ @Override public int hashCode() { - int result = stats.hashCode(); + int result = (int) (time ^ (time >>> 32)); + result = 31 * result + (stats != null ? stats.hashCode() : 0); result = 31 * result + (isMarking ? 1 : 0); result = 31 * result + (isEvacuating ? 1 : 0); return result; @@ -70,6 +72,36 @@ return used; } + public long recentlyAllocated() { + long used = 0L; + for (RegionStat rs : stats) { + if (rs.flags().contains(RegionFlag.RECENTLY_ALLOCATED)) { + used += regionSize * rs.used(); + } + } + return used; + } + + public long collectionSet() { + long used = 0L; + for (RegionStat rs : stats) { + if (rs.flags().contains(RegionFlag.IN_COLLECTION_SET)) { + used += regionSize * rs.used(); + } + } + return used; + } + + public long humongous() { + long used = 0L; + for (RegionStat rs : stats) { + if (rs.flags().contains(RegionFlag.HUMONGOUS)) { + used += regionSize * rs.used(); + } + } + return used; + } + public long live() { long live = 0L; for (RegionStat rs : stats) { diff -r a54d31fa9630 -r 5324a16e1e63 src/main/java/org/openjdk/shenandoah/SnapshotView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/openjdk/shenandoah/SnapshotView.java Wed Feb 01 11:28:44 2017 +0100 @@ -0,0 +1,64 @@ +package org.openjdk.shenandoah; + +import java.util.List; + +public class SnapshotView { + + private final long time; + private final boolean isMarking; + private final boolean isEvacuating; + private final long total; + private final long used; + private final long live; + private final long recentlyAllocated; + private final long humongous; + private final long collectionSet; + + public SnapshotView(Snapshot s) { + this.time = s.time(); + this.isEvacuating = s.isEvacuating(); + this.isMarking = s.isMarking(); + total = total(); + used = s.used(); + live = s.live(); + recentlyAllocated = s.recentlyAllocated(); + humongous = s.humongous(); + collectionSet = s.collectionSet(); + } + + public boolean isMarking() { + return isMarking; + } + + public boolean isEvacuating() { + return isEvacuating; + } + + public long time() { + return time; + } + + public long total() { + return total; + } + + public long used() { + return used; + } + + public long recentlyAllocated() { + return recentlyAllocated; + } + + public long collectionSet() { + return collectionSet; + } + + public long humongous() { + return humongous; + } + + public long live() { + return live; + } +}