Ticket #13258: patch-mappaint-extract-profiling.patch

File patch-mappaint-extract-profiling.patch, 16.7 KB (added by michael2402, 8 years ago)
  • new file src/org/openstreetmap/josm/data/osm/visitor/paint/RenderBenchmarkCollector.java

    diff --git a/src/org/openstreetmap/josm/data/osm/visitor/paint/RenderBenchmarkCollector.java b/src/org/openstreetmap/josm/data/osm/visitor/paint/RenderBenchmarkCollector.java
    new file mode 100644
    index 0000000..7f17d60
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.osm.visitor.paint;
     3
     4import java.io.PrintStream;
     5import java.util.List;
     6import java.util.function.Supplier;
     7
     8import org.openstreetmap.josm.Main;
     9import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord;
     10import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
     11import org.openstreetmap.josm.tools.Utils;
     12
     13/**
     14 * This class is notified of the various stages of a render pass.
     15 *
     16 * @author Michael Zangl
     17 * @since xxx
     18 */
     19public class RenderBenchmarkCollector {
     20    /**
     21     * Notified when the renderer method starts preparing the data
     22     * @param circum The current circum of the view.
     23     */
     24    public void renderStart(double circum) {
     25        // nop
     26    }
     27    /**
     28     * Notified when the renderer method starts sorting the styles
     29     * @return <code>true</code> if the renderer should continue to render
     30     */
     31    public boolean renderSort() {
     32        // nop
     33        return true;
     34    }
     35    /**
     36     * Notified when the renderer method starts drawing
     37     * @param allStyleElems All the elements that are painted.
     38     * @return <code>true</code> if the renderer should continue to render
     39     */
     40    public boolean renderDraw(List<StyleRecord> allStyleElems) {
     41        // nop
     42        return true;
     43    }
     44
     45    /**
     46     * Notified when the render method is done.
     47     */
     48    public void renderDone() {
     49     // nop
     50    }
     51
     52    /**
     53     * A benchmark implementation that captures the times
     54     * @author Michael Zangl
     55     * @since xxx
     56     */
     57    public static class CapturingBenchmark extends RenderBenchmarkCollector {
     58        protected long timeStart;
     59        protected long timeGenerateDone;
     60        protected long timeSortingDone;
     61        protected long timeFinished;
     62
     63        @Override
     64        public void renderStart(double circum) {
     65            timeStart = System.currentTimeMillis();
     66            super.renderStart(circum);
     67        }
     68
     69        @Override
     70        public boolean renderSort() {
     71            timeGenerateDone = System.currentTimeMillis();
     72            return super.renderSort();
     73        }
     74
     75        @Override
     76        public boolean renderDraw(List<StyleRecord> allStyleElems) {
     77            timeSortingDone = System.currentTimeMillis();
     78            return super.renderDraw(allStyleElems);
     79        }
     80
     81        /**
     82         * Get the time needed for generating the styles
     83         * @return The time in ms
     84         */
     85        public long getGenerateTime() {
     86            return timeGenerateDone - timeStart;
     87        }
     88
     89        /**
     90         * Get the time needed for computing the draw order
     91         * @return The time in ms
     92         */
     93        public long getSortTime() {
     94            return timeSortingDone - timeGenerateDone;
     95        }
     96
     97        @Override
     98        public void renderDone() {
     99            timeFinished = System.currentTimeMillis();
     100            super.renderDone();
     101        }
     102
     103        /**
     104         * Get the draw time
     105         * @return The time in ms
     106         */
     107        public long getDrawTime() {
     108            return timeFinished - timeGenerateDone;
     109        }
     110    }
     111
     112    /**
     113     * A special version of the benchmark class that logs the output to stderr.
     114     * @author Michael Zangl
     115     * @since xxx
     116     */
     117    public static class LoggingBenchmark extends RenderBenchmarkCollector.CapturingBenchmark {
     118        private final PrintStream outStream = System.err;
     119        private double circum;
     120
     121        @Override
     122        public void renderStart(double circum) {
     123            this.circum = circum;
     124            super.renderStart(circum);
     125            outStream.print("BENCHMARK: rendering ");
     126        }
     127
     128        @Override
     129        public boolean renderDraw(List<StyleRecord> allStyleElems) {
     130            boolean res = super.renderDraw(allStyleElems);
     131            outStream.print("phase 1 (calculate styles): " + Utils.getDurationString(timeSortingDone - timeStart));
     132            return res;
     133        }
     134
     135        @Override
     136        public void renderDone() {
     137            super.renderDone();
     138            outStream.println("; phase 2 (draw): " + Utils.getDurationString(timeFinished - timeGenerateDone) +
     139                    "; total: " + Utils.getDurationString(timeFinished - timeStart) +
     140                    " (scale: " + circum + " zoom level: " + Selector.GeneralSelector.scale2level(circum) + ')');
     141        }
     142    }
     143
     144    /**
     145     * A supplier that gets the default benchmark class.
     146     * @return A supplier that returns a nop or a logging benchmark.
     147     */
     148    public static Supplier<RenderBenchmarkCollector> defaultBenchmarkSupplier() {
     149        return () -> Main.isTraceEnabled() || Main.pref.getBoolean("mappaint.render.benchmark", false)
     150                ? new LoggingBenchmark() : new RenderBenchmarkCollector();
     151    }
     152}
  • src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    diff --git a/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java b/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
    index 3bef3af..ec4f480 100644
    a b import java.util.NoSuchElementException;  
    3636import java.util.concurrent.ForkJoinPool;
    3737import java.util.concurrent.ForkJoinTask;
    3838import java.util.concurrent.RecursiveTask;
     39import java.util.function.Supplier;
    3940
    4041import javax.swing.AbstractButton;
    4142import javax.swing.FocusManager;
    import org.openstreetmap.josm.gui.mappaint.ElemStyles;  
    6263import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    6364import org.openstreetmap.josm.gui.mappaint.StyleElementList;
    6465import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
    65 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
    6666import org.openstreetmap.josm.gui.mappaint.styleelement.AreaElement;
    6767import org.openstreetmap.josm.gui.mappaint.styleelement.BoxTextElement;
    6868import org.openstreetmap.josm.gui.mappaint.styleelement.BoxTextElement.HorizontalTextAlignment;
    public class StyledMapRenderer extends AbstractMapRenderer {  
    191191        }
    192192    }
    193193
    194     private static class StyleRecord implements Comparable<StyleRecord> {
     194    public static class StyleRecord implements Comparable<StyleRecord> {
    195195        private final StyleElement style;
    196196        private final OsmPrimitive osm;
    197197        private final int flags;
    public class StyledMapRenderer extends AbstractMapRenderer {  
    239239
    240240            return Float.compare(this.style.objectZIndex, other.style.objectZIndex);
    241241        }
    242     }
    243 
    244     /**
    245      * Saves benchmark data for tests.
    246      */
    247     public static class BenchmarkData {
    248         public long generateTime;
    249         public long sortTime;
    250         public long drawTime;
    251         public Map<Class<? extends StyleElement>, Integer> styleElementCount;
    252         public boolean skipDraw;
    253 
    254         private void recordElementStats(List<StyleRecord> srs) {
    255             styleElementCount = new HashMap<>();
    256             for (StyleRecord r : srs) {
    257                 Class<? extends StyleElement> klass = r.style.getClass();
    258                 Integer count = styleElementCount.get(klass);
    259                 if (count == null) {
    260                     count = 0;
    261                 }
    262                 styleElementCount.put(klass, count + 1);
    263             }
    264242
     243        /**
     244         * Get the style for this style element.
     245         * @return The style
     246         */
     247        public StyleElement getStyle() {
     248            return style;
    265249        }
    266250    }
    267251
    268     /* can be set by tests, if detailed benchmark data is requested */
    269     public BenchmarkData benchmarkData;
    270 
    271252    private static Map<Font, Boolean> IS_GLYPH_VECTOR_DOUBLE_TRANSLATION_BUG = new HashMap<>();
    272253
    273254    /**
    public class StyledMapRenderer extends AbstractMapRenderer {  
    373354    private boolean leftHandTraffic;
    374355    private Object antialiasing;
    375356
     357    private Supplier<RenderBenchmarkCollector> benchmarkFactory = RenderBenchmarkCollector.defaultBenchmarkSupplier();
     358
    376359    /**
    377360     * Constructs a new {@code StyledMapRenderer}.
    378361     *
    public class StyledMapRenderer extends AbstractMapRenderer {  
    19011884        }
    19021885    }
    19031886
     1887    /**
     1888     * Sets the factory that creates the benchmark data receivers.
     1889     * @param benchmarkFactory The factory.
     1890     */
     1891    public void setBenchmarkFactory(Supplier<RenderBenchmarkCollector> benchmarkFactory) {
     1892        this.benchmarkFactory = benchmarkFactory;
     1893    }
     1894
    19041895    @Override
    19051896    public void render(final DataSet data, boolean renderVirtualNodes, Bounds bounds) {
     1897        RenderBenchmarkCollector benchmark = benchmarkFactory.get();
    19061898        BBox bbox = bounds.toBBox();
    19071899        getSettings(renderVirtualNodes);
    1908         boolean benchmarkOutput = Main.isTraceEnabled() || Main.pref.getBoolean("mappaint.render.benchmark", false);
    1909         boolean benchmark = benchmarkOutput || benchmarkData != null;
    19101900
    19111901        data.getReadLock().lock();
    19121902        try {
    19131903            highlightWaySegments = data.getHighlightedWaySegments();
    19141904
    1915             long timeStart = 0, timeGenerateDone = 0, timeSortingDone = 0, timeFinished;
    1916             if (benchmark) {
    1917                 timeStart = System.currentTimeMillis();
    1918                 if (benchmarkOutput) {
    1919                     System.err.print("BENCHMARK: rendering ");
    1920                 }
    1921             }
     1905            benchmark.renderStart(circum);
    19221906
    19231907            List<Node> nodes = data.searchNodes(bbox);
    19241908            List<Way> ways = data.searchWays(bbox);
    public class StyledMapRenderer extends AbstractMapRenderer {  
    19361920            THREAD_POOL.invoke(new ComputeStyleListWorker(new CompositeList<>(nodes, ways), allStyleElems,
    19371921                    Math.max(100, (nodes.size() + ways.size()) / THREAD_POOL.getParallelism() / 3)));
    19381922
    1939             if (benchmark) {
    1940                 timeGenerateDone = System.currentTimeMillis();
    1941                 if (benchmarkOutput) {
    1942                     System.err.print("phase 1 (calculate styles): " + Utils.getDurationString(timeGenerateDone - timeStart));
    1943                 }
    1944                 if (benchmarkData != null) {
    1945                     benchmarkData.generateTime = timeGenerateDone - timeStart;
    1946                 }
     1923            if (!benchmark.renderSort()) {
     1924                return;
    19471925            }
    19481926
    19491927            Collections.sort(allStyleElems); // TODO: try parallel sort when switching to Java 8
    19501928
    1951             if (benchmarkData != null) {
    1952                 timeSortingDone = System.currentTimeMillis();
    1953                 benchmarkData.sortTime = timeSortingDone - timeGenerateDone;
    1954                 if (benchmarkData.skipDraw) {
    1955                     benchmarkData.recordElementStats(allStyleElems);
    1956                     return;
    1957                 }
     1929            if (!benchmark.renderDraw(allStyleElems)) {
     1930                return;
    19581931            }
    19591932
    19601933            for (StyleRecord r : allStyleElems) {
    public class StyledMapRenderer extends AbstractMapRenderer {  
    19681941                );
    19691942            }
    19701943
    1971             if (benchmark) {
    1972                 timeFinished = System.currentTimeMillis();
    1973                 if (benchmarkData != null) {
    1974                     benchmarkData.drawTime = timeFinished - timeGenerateDone;
    1975                     benchmarkData.recordElementStats(allStyleElems);
    1976                 }
    1977                 if (benchmarkOutput) {
    1978                     System.err.println("; phase 2 (draw): " + Utils.getDurationString(timeFinished - timeGenerateDone) +
    1979                         "; total: " + Utils.getDurationString(timeFinished - timeStart) +
    1980                         " (scale: " + circum + " zoom level: " + Selector.GeneralSelector.scale2level(circum) + ')');
    1981                 }
    1982             }
    1983 
    19841944            drawVirtualNodes(data, bbox);
     1945
     1946            benchmark.renderDone();
    19851947        } finally {
    19861948            data.getReadLock().unlock();
    19871949        }
  • test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java

    diff --git a/test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java b/test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java
    index 8357e65..8e5d8d5 100644
    a b import java.io.InputStream;  
    1010import java.util.ArrayList;
    1111import java.util.Collections;
    1212import java.util.EnumMap;
     13import java.util.HashMap;
    1314import java.util.List;
    1415import java.util.Locale;
    1516import java.util.Map;
     17import java.util.stream.Collectors;
    1618
    1719import javax.imageio.ImageIO;
    1820
    import org.openstreetmap.josm.TestUtils;  
    2931import org.openstreetmap.josm.data.Bounds;
    3032import org.openstreetmap.josm.data.coor.LatLon;
    3133import org.openstreetmap.josm.data.osm.DataSet;
     34import org.openstreetmap.josm.data.osm.visitor.paint.RenderBenchmarkCollector.CapturingBenchmark;
    3235import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
     36import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord;
    3337import org.openstreetmap.josm.data.projection.Projections;
    3438import org.openstreetmap.josm.gui.NavigatableComponent;
    3539import org.openstreetmap.josm.gui.mappaint.StyleSetting.BooleanStyleSetting;
    public class MapRendererPerformanceTest {  
    207211                } catch (InterruptedException ex) {
    208212                    Main.warn(ex);
    209213                }
    210                 StyledMapRenderer.BenchmarkData data = new StyledMapRenderer.BenchmarkData();
    211                 data.skipDraw = skipDraw;
    212                 renderer.benchmarkData = data;
     214                BenchmarkData data = new BenchmarkData();
     215                renderer.setBenchmarkFactory(() -> data);
    213216                renderer.render(dsCity, false, bounds);
    214217
    215218                if (i > noWarmup) {
    216                     generateTimes.add(data.generateTime);
    217                     sortTimes.add(data.sortTime);
    218                     drawTimes.add(data.drawTime);
    219                     totalTimes.add(data.generateTime + data.sortTime + data.drawTime);
     219                    generateTimes.add(data.getGenerateTime());
     220                    sortTimes.add(data.getSortTime());
     221                    drawTimes.add(data.getDrawTime());
     222                    totalTimes.add(data.getGenerateTime() + data.getSortTime() + data.getDrawTime());
    220223                }
    221224                if (i == 1) {
    222225                    dumpElementCount(data);
    public class MapRendererPerformanceTest {  
    317320        ImageIO.write(img, "png", outputfile);
    318321    }
    319322
    320     public static void dumpTimes(StyledMapRenderer.BenchmarkData bd) {
    321         System.out.print(String.format("gen. %3d, sort %3d, draw %3d%n", bd.generateTime, bd.sortTime, bd.drawTime));
     323    public static void dumpTimes(BenchmarkData bd) {
     324        System.out.print(String.format("gen. %3d, sort %3d, draw %3d%n", bd.getGenerateTime(), bd.getSortTime(), bd.getDrawTime()));
    322325    }
    323326
    324     public static void dumpElementCount(StyledMapRenderer.BenchmarkData bd) {
    325         String sep = null;
    326         for (Map.Entry<Class<? extends StyleElement>, Integer> e : bd.styleElementCount.entrySet()) {
    327             if (sep == null) {
    328                 sep = " ";
    329             } else {
    330                 System.out.print(sep);
     327    public static void dumpElementCount(BenchmarkData bd) {
     328        System.out.println(bd.recordElementStats().entrySet().stream()
     329                .map(e -> e.getKey().getSimpleName().replace("Element", "") + ":" + e.getValue()).collect(Collectors.joining(" ")));
     330    }
     331
     332    public static class BenchmarkData extends CapturingBenchmark {
     333
     334        private List<StyleRecord> allStyleElems;
     335
     336        @Override
     337        public boolean renderDraw(List<StyleRecord> allStyleElems) {
     338            this.allStyleElems = allStyleElems;
     339            return super.renderDraw(allStyleElems);
     340        }
     341
     342        private Map<Class<? extends StyleElement>, Integer> recordElementStats() {
     343            Map<Class<? extends StyleElement>, Integer> styleElementCount = new HashMap<>();
     344            for (StyleRecord r : allStyleElems) {
     345                Class<? extends StyleElement> klass = r.getStyle().getClass();
     346                Integer count = styleElementCount.get(klass);
     347                if (count == null) {
     348                    count = 0;
     349                }
     350                styleElementCount.put(klass, count + 1);
    331351            }
    332             System.out.print(e.getKey().getSimpleName().replace("Element", "") + ":" + e.getValue());
     352            return styleElementCount;
    333353        }
    334         System.out.println();
    335354    }
    336355}