Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/RenderBenchmarkCollector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/RenderBenchmarkCollector.java	(revision 10697)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/RenderBenchmarkCollector.java	(revision 10697)
@@ -0,0 +1,152 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm.visitor.paint;
+
+import java.io.PrintStream;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * This class is notified of the various stages of a render pass.
+ *
+ * @author Michael Zangl
+ * @since 10697
+ */
+public class RenderBenchmarkCollector {
+    /**
+     * Notified when the renderer method starts preparing the data
+     * @param circum The current circum of the view.
+     */
+    public void renderStart(double circum) {
+        // nop
+    }
+
+    /**
+     * Notified when the renderer method starts sorting the styles
+     * @return <code>true</code> if the renderer should continue to render
+     */
+    public boolean renderSort() {
+        // nop
+        return true;
+    }
+
+    /**
+     * Notified when the renderer method starts drawing
+     * @param allStyleElems All the elements that are painted.
+     * @return <code>true</code> if the renderer should continue to render
+     */
+    public boolean renderDraw(List<StyleRecord> allStyleElems) {
+        // nop
+        return true;
+    }
+
+    /**
+     * Notified when the render method is done.
+     */
+    public void renderDone() {
+     // nop
+    }
+
+    /**
+     * A benchmark implementation that captures the times
+     * @author Michael Zangl
+     */
+    public static class CapturingBenchmark extends RenderBenchmarkCollector {
+        protected long timeStart;
+        protected long timeGenerateDone;
+        protected long timeSortingDone;
+        protected long timeFinished;
+
+        @Override
+        public void renderStart(double circum) {
+            timeStart = System.currentTimeMillis();
+            super.renderStart(circum);
+        }
+
+        @Override
+        public boolean renderSort() {
+            timeGenerateDone = System.currentTimeMillis();
+            return super.renderSort();
+        }
+
+        @Override
+        public boolean renderDraw(List<StyleRecord> allStyleElems) {
+            timeSortingDone = System.currentTimeMillis();
+            return super.renderDraw(allStyleElems);
+        }
+
+        /**
+         * Get the time needed for generating the styles
+         * @return The time in ms
+         */
+        public long getGenerateTime() {
+            return timeGenerateDone - timeStart;
+        }
+
+        /**
+         * Get the time needed for computing the draw order
+         * @return The time in ms
+         */
+        public long getSortTime() {
+            return timeSortingDone - timeGenerateDone;
+        }
+
+        @Override
+        public void renderDone() {
+            timeFinished = System.currentTimeMillis();
+            super.renderDone();
+        }
+
+        /**
+         * Get the draw time
+         * @return The time in ms
+         */
+        public long getDrawTime() {
+            return timeFinished - timeGenerateDone;
+        }
+    }
+
+    /**
+     * A special version of the benchmark class that logs the output to stderr.
+     * @author Michael Zangl
+     */
+    public static class LoggingBenchmark extends RenderBenchmarkCollector.CapturingBenchmark {
+        private final PrintStream outStream = System.err;
+        private double circum;
+
+        @Override
+        public void renderStart(double circum) {
+            this.circum = circum;
+            super.renderStart(circum);
+            outStream.print("BENCHMARK: rendering ");
+        }
+
+        @Override
+        public boolean renderDraw(List<StyleRecord> allStyleElems) {
+            boolean res = super.renderDraw(allStyleElems);
+            outStream.print("phase 1 (calculate styles): " + Utils.getDurationString(timeSortingDone - timeStart));
+            return res;
+        }
+
+        @Override
+        public void renderDone() {
+            super.renderDone();
+            outStream.println("; phase 2 (draw): " + Utils.getDurationString(timeFinished - timeGenerateDone) +
+                    "; total: " + Utils.getDurationString(timeFinished - timeStart) +
+                    " (scale: " + circum + " zoom level: " + Selector.GeneralSelector.scale2level(circum) + ')');
+        }
+    }
+
+    /**
+     * A supplier that gets the default benchmark class.
+     * @return A supplier that returns a nop or a logging benchmark.
+     */
+    public static Supplier<RenderBenchmarkCollector> defaultBenchmarkSupplier() {
+        return () -> Main.isTraceEnabled() || Main.pref.getBoolean("mappaint.render.benchmark", false)
+                ? new LoggingBenchmark() : new RenderBenchmarkCollector();
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 10696)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 10697)
@@ -37,4 +37,5 @@
 import java.util.concurrent.ForkJoinTask;
 import java.util.concurrent.RecursiveTask;
+import java.util.function.Supplier;
 
 import javax.swing.AbstractButton;
@@ -63,5 +64,4 @@
 import org.openstreetmap.josm.gui.mappaint.StyleElementList;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
 import org.openstreetmap.josm.gui.mappaint.styleelement.AreaElement;
 import org.openstreetmap.josm.gui.mappaint.styleelement.BoxTextElement;
@@ -192,5 +192,5 @@
     }
 
-    private static class StyleRecord implements Comparable<StyleRecord> {
+    public static class StyleRecord implements Comparable<StyleRecord> {
         private final StyleElement style;
         private final OsmPrimitive osm;
@@ -240,32 +240,13 @@
             return Float.compare(this.style.objectZIndex, other.style.objectZIndex);
         }
-    }
-
-    /**
-     * Saves benchmark data for tests.
-     */
-    public static class BenchmarkData {
-        public long generateTime;
-        public long sortTime;
-        public long drawTime;
-        public Map<Class<? extends StyleElement>, Integer> styleElementCount;
-        public boolean skipDraw;
-
-        private void recordElementStats(List<StyleRecord> srs) {
-            styleElementCount = new HashMap<>();
-            for (StyleRecord r : srs) {
-                Class<? extends StyleElement> klass = r.style.getClass();
-                Integer count = styleElementCount.get(klass);
-                if (count == null) {
-                    count = 0;
-                }
-                styleElementCount.put(klass, count + 1);
-            }
-
-        }
-    }
-
-    /* can be set by tests, if detailed benchmark data is requested */
-    public BenchmarkData benchmarkData;
+
+        /**
+         * Get the style for this style element.
+         * @return The style
+         */
+        public StyleElement getStyle() {
+            return style;
+        }
+    }
 
     private static Map<Font, Boolean> IS_GLYPH_VECTOR_DOUBLE_TRANSLATION_BUG = new HashMap<>();
@@ -373,4 +354,6 @@
     private boolean leftHandTraffic;
     private Object antialiasing;
+
+    private Supplier<RenderBenchmarkCollector> benchmarkFactory = RenderBenchmarkCollector.defaultBenchmarkSupplier();
 
     /**
@@ -1902,10 +1885,18 @@
     }
 
+    /**
+     * Sets the factory that creates the benchmark data receivers.
+     * @param benchmarkFactory The factory.
+     * @since 10697
+     */
+    public void setBenchmarkFactory(Supplier<RenderBenchmarkCollector> benchmarkFactory) {
+        this.benchmarkFactory = benchmarkFactory;
+    }
+
     @Override
     public void render(final DataSet data, boolean renderVirtualNodes, Bounds bounds) {
+        RenderBenchmarkCollector benchmark = benchmarkFactory.get();
         BBox bbox = bounds.toBBox();
         getSettings(renderVirtualNodes);
-        boolean benchmarkOutput = Main.isTraceEnabled() || Main.pref.getBoolean("mappaint.render.benchmark", false);
-        boolean benchmark = benchmarkOutput || benchmarkData != null;
 
         data.getReadLock().lock();
@@ -1913,11 +1904,5 @@
             highlightWaySegments = data.getHighlightedWaySegments();
 
-            long timeStart = 0, timeGenerateDone = 0, timeSortingDone = 0, timeFinished;
-            if (benchmark) {
-                timeStart = System.currentTimeMillis();
-                if (benchmarkOutput) {
-                    System.err.print("BENCHMARK: rendering ");
-                }
-            }
+            benchmark.renderStart(circum);
 
             List<Node> nodes = data.searchNodes(bbox);
@@ -1937,23 +1922,12 @@
                     Math.max(100, (nodes.size() + ways.size()) / THREAD_POOL.getParallelism() / 3)));
 
-            if (benchmark) {
-                timeGenerateDone = System.currentTimeMillis();
-                if (benchmarkOutput) {
-                    System.err.print("phase 1 (calculate styles): " + Utils.getDurationString(timeGenerateDone - timeStart));
-                }
-                if (benchmarkData != null) {
-                    benchmarkData.generateTime = timeGenerateDone - timeStart;
-                }
+            if (!benchmark.renderSort()) {
+                return;
             }
 
             Collections.sort(allStyleElems); // TODO: try parallel sort when switching to Java 8
 
-            if (benchmarkData != null) {
-                timeSortingDone = System.currentTimeMillis();
-                benchmarkData.sortTime = timeSortingDone - timeGenerateDone;
-                if (benchmarkData.skipDraw) {
-                    benchmarkData.recordElementStats(allStyleElems);
-                    return;
-                }
+            if (!benchmark.renderDraw(allStyleElems)) {
+                return;
             }
 
@@ -1969,18 +1943,7 @@
             }
 
-            if (benchmark) {
-                timeFinished = System.currentTimeMillis();
-                if (benchmarkData != null) {
-                    benchmarkData.drawTime = timeFinished - timeGenerateDone;
-                    benchmarkData.recordElementStats(allStyleElems);
-                }
-                if (benchmarkOutput) {
-                    System.err.println("; phase 2 (draw): " + Utils.getDurationString(timeFinished - timeGenerateDone) +
-                        "; total: " + Utils.getDurationString(timeFinished - timeStart) +
-                        " (scale: " + circum + " zoom level: " + Selector.GeneralSelector.scale2level(circum) + ')');
-                }
-            }
-
             drawVirtualNodes(data, bbox);
+
+            benchmark.renderDone();
         } finally {
             data.getReadLock().unlock();
