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 = getCurrentTimeMilliseconds(); 068 super.renderStart(circum); 069 } 070 071 @Override 072 public boolean renderSort() { 073 timeGenerateDone = getCurrentTimeMilliseconds(); 074 return super.renderSort(); 075 } 076 077 @Override 078 public boolean renderDraw(List<StyleRecord> allStyleElems) { 079 timeSortingDone = getCurrentTimeMilliseconds(); 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 = getCurrentTimeMilliseconds(); 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 public static long getCurrentTimeMilliseconds() { 115 return System.nanoTime() / 1000000; // System.currentTimeMillis has low accuracy, sometimes multiples of 16ms 116 } 117 118 /** 119 * A special version of the benchmark class that logs the output to stderr. 120 * @author Michael Zangl 121 */ 122 public static class LoggingBenchmark extends RenderBenchmarkCollector.CapturingBenchmark { 123 private final PrintStream outStream = System.err; 124 private double circum; 125 126 @Override 127 public void renderStart(double circum) { 128 this.circum = circum; 129 super.renderStart(circum); 130 outStream.print("BENCHMARK: rendering "); 131 } 132 133 @Override 134 public boolean renderDraw(List<StyleRecord> allStyleElems) { 135 boolean res = super.renderDraw(allStyleElems); 136 outStream.print("phase 1 (calculate styles): " + Utils.getDurationString(timeSortingDone - timeStart)); 137 return res; 138 } 139 140 @Override 141 public void renderDone() { 142 super.renderDone(); 143 outStream.println("; phase 2 (draw): " + Utils.getDurationString(timeFinished - timeGenerateDone) + 144 "; total: " + Utils.getDurationString(timeFinished - timeStart) + 145 " (scale: " + circum + " zoom level: " + Selector.GeneralSelector.scale2level(circum) + ')'); 146 } 147 } 148 149 /** 150 * A supplier that gets the default benchmark class. 151 * @return A supplier that returns a nop or a logging benchmark. 152 */ 153 public static Supplier<RenderBenchmarkCollector> defaultBenchmarkSupplier() { 154 return () -> Logging.isTraceEnabled() || Config.getPref().getBoolean("mappaint.render.benchmark", false) 155 ? new LoggingBenchmark() : new RenderBenchmarkCollector(); 156 } 157}