source: josm/trunk/test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java@ 9793

Last change on this file since 9793 was 9793, checked in by Don-vip, 8 years ago

checkstyle

  • Property svn:eol-style set to native
File size: 11.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import java.awt.Color;
5import java.awt.Graphics2D;
6import java.awt.image.BufferedImage;
7import java.io.File;
8import java.io.IOException;
9import java.io.InputStream;
10import java.util.ArrayList;
11import java.util.Collections;
12import java.util.EnumMap;
13import java.util.List;
14import java.util.Map;
15
16import javax.imageio.ImageIO;
17
18import org.junit.AfterClass;
19import org.junit.Assert;
20import org.junit.BeforeClass;
21import org.junit.Rule;
22import org.junit.Test;
23import org.junit.rules.Timeout;
24import org.openstreetmap.josm.JOSMFixture;
25import org.openstreetmap.josm.Main;
26import org.openstreetmap.josm.PerformanceTestUtils;
27import org.openstreetmap.josm.TestUtils;
28import org.openstreetmap.josm.data.Bounds;
29import org.openstreetmap.josm.data.coor.LatLon;
30import org.openstreetmap.josm.data.osm.DataSet;
31import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
32import org.openstreetmap.josm.data.projection.Projections;
33import org.openstreetmap.josm.gui.NavigatableComponent;
34import org.openstreetmap.josm.gui.mappaint.StyleSetting.BooleanStyleSetting;
35import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
36import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
37import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
38import org.openstreetmap.josm.gui.preferences.SourceEntry;
39import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
40import org.openstreetmap.josm.io.Compression;
41import org.openstreetmap.josm.io.OsmReader;
42
43public class MapRendererPerformanceTest {
44
45 private static final boolean DUMP_IMAGE = false; // dump images to file for debugging purpose
46
47 private static final int IMG_WIDTH = 2048;
48 private static final int IMG_HEIGHT = 1536;
49
50 private static Graphics2D g;
51 private static BufferedImage img;
52 private static NavigatableComponent nc;
53 private static DataSet dsCity;
54 private static final Bounds BOUNDS_CITY_ALL = new Bounds(53.4382, 13.1094, 53.6153, 13.4074, false);
55 private static final LatLon LL_CITY = new LatLon(53.5574458, 13.2602781);
56 private static final double SCALE_Z17 = 1.5;
57
58 private static int defaultStyleIdx;
59 private static BooleanStyleSetting hideIconsSetting;
60
61 private static int filterStyleIdx;
62 private static StyleSource filterStyle;
63
64 private enum Feature {
65 ICON, SYMBOL, NODE_TEXT, LINE, LINE_TEXT, AREA;
66 public String label() {
67 return name().toLowerCase();
68 }
69 }
70
71 private static final EnumMap<Feature, BooleanStyleSetting> filters = new EnumMap<>(Feature.class);
72
73 /**
74 * Global timeout applied to all test methods.
75 */
76 @Rule
77 public Timeout globalTimeout = Timeout.seconds(15*60);
78
79 @BeforeClass
80 public static void load() throws Exception {
81 JOSMFixture.createPerformanceTestFixture().init(true);
82
83 img = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_ARGB);
84 g = (Graphics2D) img.getGraphics();
85 g.setClip(0, 0, IMG_WIDTH, IMG_WIDTH);
86 g.setColor(Color.BLACK);
87 g.fillRect(0, 0, IMG_WIDTH, IMG_WIDTH);
88 nc = Main.map.mapView;
89 nc.setBounds(0, 0, IMG_WIDTH, IMG_HEIGHT);
90
91 MapPaintStyles.readFromPreferences();
92
93 SourceEntry se = new MapCSSStyleSource(TestUtils.getTestDataRoot() + "styles/filter.mapcss", "filter", "");
94 filterStyle = MapPaintStyles.addStyle(se);
95 List<StyleSource> sources = MapPaintStyles.getStyles().getStyleSources();
96 filterStyleIdx = sources.indexOf(filterStyle);
97 Assert.assertEquals(2, filterStyleIdx);
98
99 Assert.assertEquals(Feature.values().length, filterStyle.settings.size());
100 for (StyleSetting set : filterStyle.settings) {
101 BooleanStyleSetting bset = (BooleanStyleSetting) set;
102 String prefKey = bset.prefKey;
103 boolean found = false;
104 for (Feature f : Feature.values()) {
105 if (prefKey.endsWith(":" + f.label() + "_off")) {
106 filters.put(f, bset);
107 found = true;
108 break;
109 }
110 }
111 Assert.assertTrue(prefKey, found);
112 }
113
114 MapCSSStyleSource defaultStyle = null;
115 for (int i = 0; i < sources.size(); i++) {
116 StyleSource s = sources.get(i);
117 if ("resource://styles/standard/elemstyles.mapcss".equals(s.url)) {
118 defaultStyle = (MapCSSStyleSource) s;
119 defaultStyleIdx = i;
120 break;
121 }
122 }
123 Assert.assertNotNull(defaultStyle);
124
125 for (StyleSetting set : defaultStyle.settings) {
126 if (set instanceof BooleanStyleSetting) {
127 BooleanStyleSetting bset = (BooleanStyleSetting) set;
128 if (bset.prefKey.endsWith(":hide_icons")) {
129 hideIconsSetting = bset;
130 }
131 }
132 }
133 Assert.assertNotNull(hideIconsSetting);
134 hideIconsSetting.setValue(false);
135 MapPaintStyles.reloadStyles(defaultStyleIdx);
136
137 try (
138 InputStream fisC = Compression.getUncompressedFileInputStream(new File("data_nodist/neubrandenburg.osm.bz2"));
139 ) {
140 dsCity = OsmReader.parseDataSet(fisC, NullProgressMonitor.INSTANCE);
141 }
142 }
143
144 @AfterClass
145 public static void cleanUp() {
146 setFilterStyleActive(false);
147 if (hideIconsSetting != null) {
148 hideIconsSetting.setValue(true);
149 }
150 MapPaintStyles.reloadStyles(defaultStyleIdx);
151 }
152
153 private static class PerformanceTester {
154 public double scale = 0;
155 public LatLon center = LL_CITY;
156 public Bounds bounds;
157 public int noWarmup = 3;
158 public int noIterations = 7;
159 public boolean dumpImage = DUMP_IMAGE;
160 public boolean skipDraw = false;
161 public boolean clearStyleCache = true;
162 public String label = "";
163 public boolean mpGenerate = false;
164 public boolean mpSort = false;
165 public boolean mpDraw = false;
166 public boolean mpTotal = false;
167
168 private final List<Long> generateTimes = new ArrayList<>();
169 private final List<Long> sortTimes = new ArrayList<>();
170 private final List<Long> drawTimes = new ArrayList<>();
171 private final List<Long> totalTimes = new ArrayList<>();
172
173 public void run() throws IOException {
174 boolean checkScale = false;
175 if (scale == 0) {
176 checkScale = true;
177 scale = SCALE_Z17;
178 }
179 nc.zoomTo(Projections.project(center), scale);
180 if (checkScale) {
181 int lvl = Selector.OptimizedGeneralSelector.scale2level(nc.getDist100Pixel());
182 Assert.assertEquals(17, lvl);
183 }
184
185 if (bounds == null) {
186 bounds = nc.getLatLonBounds(g.getClipBounds());
187 }
188
189 StyledMapRenderer renderer = new StyledMapRenderer(g, nc, false);
190
191 int noTotal = noWarmup + noIterations;
192 for (int i = 1; i <= noTotal; i++) {
193 g.setColor(Color.BLACK);
194 g.fillRect(0, 0, IMG_WIDTH, IMG_WIDTH);
195 if (clearStyleCache) {
196 MapPaintStyles.getStyles().clearCached();
197 }
198 System.gc();
199 System.runFinalization();
200 try {
201 Thread.sleep(300);
202 } catch (InterruptedException ex) {
203 Main.warn(ex);
204 }
205 StyledMapRenderer.BenchmarkData data = new StyledMapRenderer.BenchmarkData();
206 data.skipDraw = skipDraw;
207 renderer.benchmarkData = data;
208 renderer.render(dsCity, false, bounds);
209
210 if (i > noWarmup) {
211 generateTimes.add(data.generateTime);
212 sortTimes.add(data.sortTime);
213 drawTimes.add(data.drawTime);
214 totalTimes.add(data.generateTime + data.sortTime + data.drawTime);
215 }
216 if (i == 1) {
217 dumpElementCount(data);
218 }
219 dumpTimes(data);
220 if (dumpImage && i == noTotal) {
221 dumpRenderedImage(label);
222 }
223 }
224
225 if (mpGenerate) {
226 processTimes(generateTimes, "generate");
227 }
228 if (mpSort) {
229 processTimes(sortTimes, "sort");
230 }
231 if (mpDraw) {
232 processTimes(drawTimes, "draw");
233 }
234 if (mpTotal) {
235 processTimes(totalTimes, "total");
236 }
237 }
238
239 private void processTimes(List<Long> times, String sublabel) {
240 Collections.sort(times);
241 // Take median instead of average. This should give a more stable
242 // result and avoids distortions by outliers.
243 long medianTime = times.get(times.size() / 2);
244 PerformanceTestUtils.measurementPlotsPluginOutput(label + " " + sublabel + " (ms)", medianTime);
245 }
246 }
247
248 /**
249 * Test phase 1, the calculation of {@link StyleElement}s.
250 * @throws IOException in case of an I/O error
251 */
252 @Test
253 public void testPerformanceGenerate() throws IOException {
254 setFilterStyleActive(false);
255 PerformanceTester test = new PerformanceTester();
256 test.bounds = BOUNDS_CITY_ALL;
257 test.label = "big";
258 test.skipDraw = true;
259 test.dumpImage = false;
260 test.noWarmup = 3;
261 test.noIterations = 10;
262 test.mpGenerate = true;
263 test.clearStyleCache = true;
264 test.run();
265 }
266
267 private static void testDrawFeature(Feature feature) throws IOException {
268 PerformanceTester test = new PerformanceTester();
269 test.noWarmup = 3;
270 test.noIterations = 10;
271 test.mpDraw = true;
272 test.clearStyleCache = false;
273 if (feature != null) {
274 BooleanStyleSetting filterSetting = filters.get(feature);
275 test.label = filterSetting.label;
276 setFilterStyleActive(true);
277 for (Feature f : Feature.values()) {
278 filters.get(f).setValue(true);
279 }
280 filterSetting.setValue(false);
281 } else {
282 test.label = "all";
283 setFilterStyleActive(false);
284 }
285 MapPaintStyles.reloadStyles(filterStyleIdx);
286 test.run();
287 }
288
289 /**
290 * Test phase 2, the actual drawing.
291 * Several runs: Icons, lines, etc. are tested separately (+ one run with
292 * all features activated)
293 * @throws IOException in case of an I/O error
294 */
295 @Test
296 public void testPerformanceDrawFeatures() throws IOException {
297 testDrawFeature(null);
298 for (Feature f : Feature.values()) {
299 testDrawFeature(f);
300 }
301 }
302
303 private static void setFilterStyleActive(boolean active) {
304 if (filterStyle.active != active) {
305 MapPaintStyles.toggleStyleActive(filterStyleIdx);
306 }
307 Assert.assertEquals(active, filterStyle.active);
308 }
309
310 private static void dumpRenderedImage(String id) throws IOException {
311 File outputfile = new File("test-neubrandenburg-"+id+".png");
312 ImageIO.write(img, "png", outputfile);
313 }
314
315 public static void dumpTimes(StyledMapRenderer.BenchmarkData bd) {
316 System.out.print(String.format("gen. %3d, sort %3d, draw %3d\n", bd.generateTime, bd.sortTime, bd.drawTime));
317 }
318
319 public static void dumpElementCount(StyledMapRenderer.BenchmarkData bd) {
320 String sep = null;
321 for (Map.Entry<Class<? extends StyleElement>, Integer> e : bd.styleElementCount.entrySet()) {
322 if (sep == null) {
323 sep = " ";
324 } else {
325 System.out.print(sep);
326 }
327 System.out.print(e.getKey().getSimpleName().replace("Element", "") + ":" + e.getValue());
328 }
329 System.out.println();
330 }
331}
Note: See TracBrowser for help on using the repository browser.