Ticket #13258: patch-mappaint-extract-profiling.patch
File patch-mappaint-extract-profiling.patch, 16.7 KB (added by , 9 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. 2 package org.openstreetmap.josm.data.osm.visitor.paint; 3 4 import java.io.PrintStream; 5 import java.util.List; 6 import java.util.function.Supplier; 7 8 import org.openstreetmap.josm.Main; 9 import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord; 10 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; 11 import 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 */ 19 public 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; 36 36 import java.util.concurrent.ForkJoinPool; 37 37 import java.util.concurrent.ForkJoinTask; 38 38 import java.util.concurrent.RecursiveTask; 39 import java.util.function.Supplier; 39 40 40 41 import javax.swing.AbstractButton; 41 42 import javax.swing.FocusManager; … … import org.openstreetmap.josm.gui.mappaint.ElemStyles; 62 63 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; 63 64 import org.openstreetmap.josm.gui.mappaint.StyleElementList; 64 65 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource; 65 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;66 66 import org.openstreetmap.josm.gui.mappaint.styleelement.AreaElement; 67 67 import org.openstreetmap.josm.gui.mappaint.styleelement.BoxTextElement; 68 68 import org.openstreetmap.josm.gui.mappaint.styleelement.BoxTextElement.HorizontalTextAlignment; … … public class StyledMapRenderer extends AbstractMapRenderer { 191 191 } 192 192 } 193 193 194 p rivatestatic class StyleRecord implements Comparable<StyleRecord> {194 public static class StyleRecord implements Comparable<StyleRecord> { 195 195 private final StyleElement style; 196 196 private final OsmPrimitive osm; 197 197 private final int flags; … … public class StyledMapRenderer extends AbstractMapRenderer { 239 239 240 240 return Float.compare(this.style.objectZIndex, other.style.objectZIndex); 241 241 } 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 }264 242 243 /** 244 * Get the style for this style element. 245 * @return The style 246 */ 247 public StyleElement getStyle() { 248 return style; 265 249 } 266 250 } 267 251 268 /* can be set by tests, if detailed benchmark data is requested */269 public BenchmarkData benchmarkData;270 271 252 private static Map<Font, Boolean> IS_GLYPH_VECTOR_DOUBLE_TRANSLATION_BUG = new HashMap<>(); 272 253 273 254 /** … … public class StyledMapRenderer extends AbstractMapRenderer { 373 354 private boolean leftHandTraffic; 374 355 private Object antialiasing; 375 356 357 private Supplier<RenderBenchmarkCollector> benchmarkFactory = RenderBenchmarkCollector.defaultBenchmarkSupplier(); 358 376 359 /** 377 360 * Constructs a new {@code StyledMapRenderer}. 378 361 * … … public class StyledMapRenderer extends AbstractMapRenderer { 1901 1884 } 1902 1885 } 1903 1886 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 1904 1895 @Override 1905 1896 public void render(final DataSet data, boolean renderVirtualNodes, Bounds bounds) { 1897 RenderBenchmarkCollector benchmark = benchmarkFactory.get(); 1906 1898 BBox bbox = bounds.toBBox(); 1907 1899 getSettings(renderVirtualNodes); 1908 boolean benchmarkOutput = Main.isTraceEnabled() || Main.pref.getBoolean("mappaint.render.benchmark", false);1909 boolean benchmark = benchmarkOutput || benchmarkData != null;1910 1900 1911 1901 data.getReadLock().lock(); 1912 1902 try { 1913 1903 highlightWaySegments = data.getHighlightedWaySegments(); 1914 1904 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); 1922 1906 1923 1907 List<Node> nodes = data.searchNodes(bbox); 1924 1908 List<Way> ways = data.searchWays(bbox); … … public class StyledMapRenderer extends AbstractMapRenderer { 1936 1920 THREAD_POOL.invoke(new ComputeStyleListWorker(new CompositeList<>(nodes, ways), allStyleElems, 1937 1921 Math.max(100, (nodes.size() + ways.size()) / THREAD_POOL.getParallelism() / 3))); 1938 1922 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; 1947 1925 } 1948 1926 1949 1927 Collections.sort(allStyleElems); // TODO: try parallel sort when switching to Java 8 1950 1928 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; 1958 1931 } 1959 1932 1960 1933 for (StyleRecord r : allStyleElems) { … … public class StyledMapRenderer extends AbstractMapRenderer { 1968 1941 ); 1969 1942 } 1970 1943 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 1984 1944 drawVirtualNodes(data, bbox); 1945 1946 benchmark.renderDone(); 1985 1947 } finally { 1986 1948 data.getReadLock().unlock(); 1987 1949 } -
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; 10 10 import java.util.ArrayList; 11 11 import java.util.Collections; 12 12 import java.util.EnumMap; 13 import java.util.HashMap; 13 14 import java.util.List; 14 15 import java.util.Locale; 15 16 import java.util.Map; 17 import java.util.stream.Collectors; 16 18 17 19 import javax.imageio.ImageIO; 18 20 … … import org.openstreetmap.josm.TestUtils; 29 31 import org.openstreetmap.josm.data.Bounds; 30 32 import org.openstreetmap.josm.data.coor.LatLon; 31 33 import org.openstreetmap.josm.data.osm.DataSet; 34 import org.openstreetmap.josm.data.osm.visitor.paint.RenderBenchmarkCollector.CapturingBenchmark; 32 35 import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer; 36 import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord; 33 37 import org.openstreetmap.josm.data.projection.Projections; 34 38 import org.openstreetmap.josm.gui.NavigatableComponent; 35 39 import org.openstreetmap.josm.gui.mappaint.StyleSetting.BooleanStyleSetting; … … public class MapRendererPerformanceTest { 207 211 } catch (InterruptedException ex) { 208 212 Main.warn(ex); 209 213 } 210 StyledMapRenderer.BenchmarkData data = new StyledMapRenderer.BenchmarkData(); 211 data.skipDraw = skipDraw; 212 renderer.benchmarkData = data; 214 BenchmarkData data = new BenchmarkData(); 215 renderer.setBenchmarkFactory(() -> data); 213 216 renderer.render(dsCity, false, bounds); 214 217 215 218 if (i > noWarmup) { 216 generateTimes.add(data.ge nerateTime);217 sortTimes.add(data. sortTime);218 drawTimes.add(data. drawTime);219 totalTimes.add(data.ge nerateTime + 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()); 220 223 } 221 224 if (i == 1) { 222 225 dumpElementCount(data); … … public class MapRendererPerformanceTest { 317 320 ImageIO.write(img, "png", outputfile); 318 321 } 319 322 320 public static void dumpTimes( StyledMapRenderer.BenchmarkData bd) {321 System.out.print(String.format("gen. %3d, sort %3d, draw %3d%n", bd.ge nerateTime, 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())); 322 325 } 323 326 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); 331 351 } 332 System.out.print(e.getKey().getSimpleName().replace("Element", "") + ":" + e.getValue());352 return styleElementCount; 333 353 } 334 System.out.println();335 354 } 336 355 }