001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm.visitor.paint;
003
004import java.io.PrintStream;
005import java.util.List;
006import java.util.function.Supplier;
007
008import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord;
009import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
010import org.openstreetmap.josm.spi.preferences.Config;
011import org.openstreetmap.josm.tools.Logging;
012import org.openstreetmap.josm.tools.Utils;
013
014/**
015 * This class is notified of the various stages of a render pass.
016 *
017 * @author Michael Zangl
018 * @since 10697
019 */
020public class RenderBenchmarkCollector {
021    /**
022     * Notified when the renderer method starts preparing the data
023     * @param circum The current circum of the view.
024     */
025    public void renderStart(double circum) {
026        // nop
027    }
028
029    /**
030     * Notified when the renderer method starts sorting the styles
031     * @return <code>true</code> if the renderer should continue to render
032     */
033    public boolean renderSort() {
034        // nop
035        return true;
036    }
037
038    /**
039     * Notified when the renderer method starts drawing
040     * @param allStyleElems All the elements that are painted. Unsorted
041     * @return <code>true</code> if the renderer should continue to render
042     */
043    public boolean renderDraw(List<StyleRecord> allStyleElems) {
044        // nop
045        return true;
046    }
047
048    /**
049     * Notified when the render method is done.
050     */
051    public void renderDone() {
052     // nop
053    }
054
055    /**
056     * A benchmark implementation that captures the times
057     * @author Michael Zangl
058     */
059    public static class CapturingBenchmark extends RenderBenchmarkCollector {
060        protected long timeStart;
061        protected long timeGenerateDone;
062        protected long timeSortingDone;
063        protected long timeFinished;
064
065        @Override
066        public void renderStart(double circum) {
067            timeStart = System.currentTimeMillis();
068            super.renderStart(circum);
069        }
070
071        @Override
072        public boolean renderSort() {
073            timeGenerateDone = System.currentTimeMillis();
074            return super.renderSort();
075        }
076
077        @Override
078        public boolean renderDraw(List<StyleRecord> allStyleElems) {
079            timeSortingDone = System.currentTimeMillis();
080            return super.renderDraw(allStyleElems);
081        }
082
083        /**
084         * Get the time needed for generating the styles
085         * @return The time in ms
086         */
087        public long getGenerateTime() {
088            return timeGenerateDone - timeStart;
089        }
090
091        /**
092         * Get the time needed for computing the draw order
093         * @return The time in ms
094         */
095        public long getSortTime() {
096            return timeSortingDone - timeGenerateDone;
097        }
098
099        @Override
100        public void renderDone() {
101            timeFinished = System.currentTimeMillis();
102            super.renderDone();
103        }
104
105        /**
106         * Get the draw time
107         * @return The time in ms
108         */
109        public long getDrawTime() {
110            return timeFinished - timeGenerateDone;
111        }
112    }
113
114    /**
115     * A special version of the benchmark class that logs the output to stderr.
116     * @author Michael Zangl
117     */
118    public static class LoggingBenchmark extends RenderBenchmarkCollector.CapturingBenchmark {
119        private final PrintStream outStream = System.err;
120        private double circum;
121
122        @Override
123        public void renderStart(double circum) {
124            this.circum = circum;
125            super.renderStart(circum);
126            outStream.print("BENCHMARK: rendering ");
127        }
128
129        @Override
130        public boolean renderDraw(List<StyleRecord> allStyleElems) {
131            boolean res = super.renderDraw(allStyleElems);
132            outStream.print("phase 1 (calculate styles): " + Utils.getDurationString(timeSortingDone - timeStart));
133            return res;
134        }
135
136        @Override
137        public void renderDone() {
138            super.renderDone();
139            outStream.println("; phase 2 (draw): " + Utils.getDurationString(timeFinished - timeGenerateDone) +
140                    "; total: " + Utils.getDurationString(timeFinished - timeStart) +
141                    " (scale: " + circum + " zoom level: " + Selector.GeneralSelector.scale2level(circum) + ')');
142        }
143    }
144
145    /**
146     * A supplier that gets the default benchmark class.
147     * @return A supplier that returns a nop or a logging benchmark.
148     */
149    public static Supplier<RenderBenchmarkCollector> defaultBenchmarkSupplier() {
150        return () -> Logging.isTraceEnabled() || Config.getPref().getBoolean("mappaint.render.benchmark", false)
151                ? new LoggingBenchmark() : new RenderBenchmarkCollector();
152    }
153}