changeset 17:5324a16e1e63

Runtime metrics graph.
author shade
date Wed, 01 Feb 2017 11:28:44 +0100
parents a54d31fa9630
children 7898f7c79d9d
files src/main/java/org/openjdk/shenandoah/Colors.java src/main/java/org/openjdk/shenandoah/DataProvider.java src/main/java/org/openjdk/shenandoah/RegionStat.java src/main/java/org/openjdk/shenandoah/ShenandoahVisualizer.java src/main/java/org/openjdk/shenandoah/Snapshot.java src/main/java/org/openjdk/shenandoah/SnapshotView.java
diffstat 6 files changed, 182 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- /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;
+}
--- 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);
     }
 
 }
--- 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<RegionFlag> flags() {
+        return flags;
+    }
+
 }
--- 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<SnapshotView> lastSnapshots = new LinkedList<>();
+
     static volatile Snapshot lastSnapshot;
 
-    public static BufferedImage render(Snapshot snapshot, int width, int height) {
+    public static BufferedImage render(Snapshot snapshot, LinkedList<SnapshotView> 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;
--- 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) {
--- /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;
+    }
+}