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

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

findbugs - fix/suppress most of warnings reported in unit tests + enable low confidence warnings for core

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