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.Main;
009import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord;
010import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
011import org.openstreetmap.josm.tools.Utils;
012
013/**
014 * This class is notified of the various stages of a render pass.
015 *
016 * @author Michael Zangl
017 * @since 10697
018 */
019public class RenderBenchmarkCollector {
020    /**
021     * Notified when the renderer method starts preparing the data
022     * @param circum The current circum of the view.
023     */
024    public void renderStart(double circum) {
025        // nop
026    }
027
028    /**
029     * Notified when the renderer method starts sorting the styles
030     * @return <code>true</code> if the renderer should continue to render
031     */
032    public boolean renderSort() {
033        // nop
034        return true;
035    }
036
037    /**
038     * Notified when the renderer method starts drawing
039     * @param allStyleElems All the elements that are painted.
040     * @return <code>true</code> if the renderer should continue to render
041     */
042    public boolean renderDraw(List<StyleRecord> allStyleElems) {
043        // nop
044        return true;
045    }
046
047    /**
048     * Notified when the render method is done.
049     */
050    public void renderDone() {
051     // nop
052    }
053
054    /**
055     * A benchmark implementation that captures the times
056     * @author Michael Zangl
057     */
058    public static class CapturingBenchmark extends RenderBenchmarkCollector {
059        protected long timeStart;
060        protected long timeGenerateDone;
061        protected long timeSortingDone;
062        protected long timeFinished;
063
064        @Override
065        public void renderStart(double circum) {
066            timeStart = System.currentTimeMillis();
067            super.renderStart(circum);
068        }
069
070        @Override
071        public boolean renderSort() {
072            timeGenerateDone = System.currentTimeMillis();
073            return super.renderSort();
074        }
075
076        @Override
077        public boolean renderDraw(List<StyleRecord> allStyleElems) {
078            timeSortingDone = System.currentTimeMillis();
079            return super.renderDraw(allStyleElems);
080        }
081
082        /**
083         * Get the time needed for generating the styles
084         * @return The time in ms
085         */
086        public long getGenerateTime() {
087            return timeGenerateDone - timeStart;
088        }
089
090        /**
091         * Get the time needed for computing the draw order
092         * @return The time in ms
093         */
094        public long getSortTime() {
095            return timeSortingDone - timeGenerateDone;
096        }
097
098        @Override
099        public void renderDone() {
100            timeFinished = System.currentTimeMillis();
101            super.renderDone();
102        }
103
104        /**
105         * Get the draw time
106         * @return The time in ms
107         */
108        public long getDrawTime() {
109            return timeFinished - timeGenerateDone;
110        }
111    }
112
113    /**
114     * A special version of the benchmark class that logs the output to stderr.
115     * @author Michael Zangl
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}