Ticket #11709: 0001-Added-new-performance-test-for-OsmPrimitive-tag-hand.patch
File 0001-Added-new-performance-test-for-OsmPrimitive-tag-hand.patch, 17.2 KB (added by , 9 years ago) |
---|
-
new file test/performance/org/openstreetmap/josm/PerformanceTestUtils.java
From 03c8000a59a7a7b2a608ad4ef598f37120340eba Mon Sep 17 00:00:00 2001 From: Michael Zangl <michael.zangl@student.kit.edu> Date: Mon, 20 Jul 2015 13:04:02 +0200 Subject: [PATCH 1/4] Added new performance test for OsmPrimitive tag handling. --- .../openstreetmap/josm/PerformanceTestUtils.java | 44 +++++ .../josm/data/osm/KeyValuePerformanceTest.java | 204 ++++++++++++++++++++ .../josm/data/osm/OsmDataGenerator.java | 214 +++++++++++++++++++++ 3 files changed, 462 insertions(+) create mode 100644 test/performance/org/openstreetmap/josm/PerformanceTestUtils.java create mode 100644 test/performance/org/openstreetmap/josm/data/osm/KeyValuePerformanceTest.java create mode 100644 test/performance/org/openstreetmap/josm/data/osm/OsmDataGenerator.java diff --git a/test/performance/org/openstreetmap/josm/PerformanceTestUtils.java b/test/performance/org/openstreetmap/josm/PerformanceTestUtils.java new file mode 100644 index 0000000..f2d64ce
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm; 3 4 /** 5 * Timer utilities for performance tests. 6 * @author Michael Zangl 7 */ 8 public class PerformanceTestUtils { 9 /** 10 * A timer that measures the time from it's creation to the {@link #done()} call. 11 * @author Michael Zangl 12 */ 13 public static class PerformanceTestTimer { 14 private String name; 15 private long time; 16 17 protected PerformanceTestTimer(String name) { 18 this.name = name; 19 time = System.nanoTime(); 20 } 21 22 /** 23 * Prints the time since this timer was created. 24 */ 25 public void done() { 26 long dTime = System.nanoTime() - time; 27 System.out.println("TIMER " + name + ": " + dTime / 1000000 + "ms"); 28 } 29 } 30 31 private PerformanceTestUtils() { 32 } 33 34 /** 35 * Starts a new performance timer. 36 * @param name The name/description of the timer. 37 * @return A {@link PerformanceTestTimer} object of which you can call {@link PerformanceTestTimer#done()} when done. 38 */ 39 public static PerformanceTestTimer startTimer(String name) { 40 System.gc(); 41 System.runFinalization(); 42 return new PerformanceTestTimer(name); 43 } 44 } -
new file test/performance/org/openstreetmap/josm/data/osm/KeyValuePerformanceTest.java
diff --git a/test/performance/org/openstreetmap/josm/data/osm/KeyValuePerformanceTest.java b/test/performance/org/openstreetmap/josm/data/osm/KeyValuePerformanceTest.java new file mode 100644 index 0000000..83171b5
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.osm; 3 4 import static org.junit.Assert.assertFalse; 5 import static org.junit.Assert.assertTrue; 6 7 import java.util.ArrayList; 8 import java.util.Random; 9 10 import org.apache.commons.lang.RandomStringUtils; 11 import org.junit.Before; 12 import org.junit.BeforeClass; 13 import org.junit.Test; 14 import org.openstreetmap.josm.JOSMFixture; 15 import org.openstreetmap.josm.PerformanceTestUtils; 16 import org.openstreetmap.josm.PerformanceTestUtils.PerformanceTestTimer; 17 import org.openstreetmap.josm.data.osm.OsmDataGenerator.KeyValueDataGenerator; 18 19 /** 20 * This test measures the performance of {@link OsmPrimitive#get(String)} and related. 21 * @author Michael Zangl 22 */ 23 public class KeyValuePerformanceTest { 24 private static final int PUT_RUNS = 10000; 25 private static final int GET_RUNS = 100000; 26 private static final int TEST_STRING_COUNT = 10000; 27 private static final int STRING_INTERN_TESTS = 5000000; 28 private static final double[] TAG_NODE_RATIOS = new double[] { .05, .3, 3, 20, 200 }; 29 private ArrayList<String> testStrings = new ArrayList<>(); 30 private Random random; 31 32 /** 33 * Prepare the test. 34 */ 35 @BeforeClass 36 public static void createJOSMFixture() { 37 JOSMFixture.createPerformanceTestFixture().init(true); 38 } 39 40 /** 41 * See if there is a big difference between Strings that are interned and those that are not. 42 */ 43 @Test 44 public void meassureStringEqualsIntern() { 45 String str1Interned = "string1"; 46 String str1InternedB = "string1"; 47 String str1 = new String(str1Interned); 48 String str1B = new String(str1Interned); 49 String str2Interned = "string2"; 50 String str2 = new String(str2Interned); 51 52 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 53 // warm up 54 assertTrue(str1.equals(str1B)); 55 } 56 57 PerformanceTestTimer timer = PerformanceTestUtils.startTimer("Assertion overhead."); 58 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 59 assertTrue(true); 60 } 61 timer.done(); 62 63 timer = PerformanceTestUtils.startTimer("str1.equals(str2) succeeds (without intern)"); 64 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 65 assertTrue(str1.equals(str1B)); 66 } 67 timer.done(); 68 69 timer = PerformanceTestUtils.startTimer("str1 == str2 succeeds"); 70 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 71 assertTrue(str1Interned == str1InternedB); 72 } 73 timer.done(); 74 75 timer = PerformanceTestUtils.startTimer("str1 == str2.intern() succeeds"); 76 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 77 assertTrue(str1Interned == str1.intern()); 78 } 79 timer.done(); 80 81 timer = PerformanceTestUtils.startTimer("str1 == str2.intern() succeeds for interned string"); 82 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 83 assertTrue(str1Interned == str1InternedB.intern()); 84 } 85 timer.done(); 86 87 timer = PerformanceTestUtils.startTimer("str1.equals(str2) = fails (without intern)"); 88 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 89 assertFalse(str1.equals(str2)); 90 } 91 timer.done(); 92 93 timer = PerformanceTestUtils.startTimer("str1 == str2 fails"); 94 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 95 assertFalse(str1Interned == str2Interned); 96 } 97 timer.done(); 98 99 timer = PerformanceTestUtils.startTimer("str1 == str2.intern() fails"); 100 for (int i = 0; i < STRING_INTERN_TESTS; i++) { 101 assertFalse(str1Interned == str2.intern()); 102 } 103 timer.done(); 104 } 105 106 /** 107 * Generate an array of test strings. 108 */ 109 @Before 110 public void generateTestStrings() { 111 testStrings.clear(); 112 random = new Random(123); 113 for (int i = 0; i < TEST_STRING_COUNT; i++) { 114 testStrings.add(RandomStringUtils.random(10, 0, 0, true, true, null, random)); 115 } 116 } 117 118 /** 119 * Measure the speed of {@link OsmPrimitive#put(String, String)} 120 */ 121 @Test 122 public void testKeyValuePut() { 123 for (double tagNodeRatio : TAG_NODE_RATIOS) { 124 int nodeCount = (int) (PUT_RUNS / tagNodeRatio); 125 KeyValueDataGenerator generator = OsmDataGenerator.getKeyValue(nodeCount, 0); 126 generator.generateDataSet(); 127 128 PerformanceTestTimer timer = PerformanceTestUtils 129 .startTimer("OsmPrimitive#put(String, String) with put/node ratio " + tagNodeRatio); 130 131 for (int i = 0; i < PUT_RUNS; i++) { 132 String key = generator.randomKey(); 133 String value = generator.randomValue(); 134 generator.randomNode().put(key, value); 135 } 136 137 timer.done(); 138 } 139 } 140 141 /** 142 * Measure the speed of {@link OsmPrimitive#get(String)} 143 */ 144 @Test 145 public void testKeyValueGet() { 146 for (double tagNodeRatio : TAG_NODE_RATIOS) { 147 KeyValueDataGenerator generator = OsmDataGenerator.getKeyValue(tagNodeRatio); 148 generator.generateDataSet(); 149 150 PerformanceTestTimer timer = PerformanceTestUtils 151 .startTimer("OsmPrimitive#get(String) with tag/node ratio " + tagNodeRatio); 152 for (int i = 0; i < GET_RUNS; i++) { 153 String key = generator.randomKey(); 154 // to make comparison easier. 155 generator.randomValue(); 156 generator.randomNode().get(key); 157 } 158 timer.done(); 159 } 160 } 161 162 /** 163 * Measure the speed of {@link OsmPrimitive#getKeys()} 164 */ 165 @Test 166 public void testKeyValueGetKeys() { 167 for (double tagNodeRatio : TAG_NODE_RATIOS) { 168 KeyValueDataGenerator generator = OsmDataGenerator.getKeyValue(tagNodeRatio); 169 generator.generateDataSet(); 170 171 PerformanceTestTimer timer = PerformanceTestUtils.startTimer("OsmPrimitive#getKeys() with tag/node ratio " 172 + tagNodeRatio); 173 174 for (int i = 0; i < GET_RUNS; i++) { 175 // to make comparison easier. 176 generator.randomKey(); 177 generator.randomValue(); 178 generator.randomNode().getKeys(); 179 } 180 timer.done(); 181 } 182 } 183 184 /** 185 * Measure the speed of {@link OsmPrimitive#getKeys()}.get(key) 186 */ 187 @Test 188 public void testKeyValueGetKeysGet() { 189 for (double tagNodeRatio : TAG_NODE_RATIOS) { 190 KeyValueDataGenerator generator = OsmDataGenerator.getKeyValue(tagNodeRatio); 191 generator.generateDataSet(); 192 193 PerformanceTestTimer timer = PerformanceTestUtils 194 .startTimer("OsmPrimitive#getKeys().get(key) with tag/node ratio " + tagNodeRatio); 195 for (int i = 0; i < GET_RUNS; i++) { 196 String key = generator.randomKey(); 197 // to make comparison easier. 198 generator.randomValue(); 199 generator.randomNode().getKeys().get(key); 200 } 201 timer.done(); 202 } 203 } 204 } -
new file test/performance/org/openstreetmap/josm/data/osm/OsmDataGenerator.java
diff --git a/test/performance/org/openstreetmap/josm/data/osm/OsmDataGenerator.java b/test/performance/org/openstreetmap/josm/data/osm/OsmDataGenerator.java new file mode 100644 index 0000000..fce9c2d
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.osm; 3 4 import java.io.File; 5 import java.util.ArrayList; 6 import java.util.Random; 7 8 import org.apache.commons.lang.RandomStringUtils; 9 import org.openstreetmap.josm.data.coor.EastNorth; 10 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 11 12 /** 13 * This is an utility class that allows you to generate OSM test data. 14 * @author Michael Zangl 15 */ 16 public class OsmDataGenerator { 17 private static final int DEFAULT_KEY_VALUE_RATIO = 3; 18 private static final int DEFAULT_NODE_COUNT = 1000; 19 private static final String DATA_DIR = "data_nodist" + File.separator + "osmfiles"; 20 21 /** 22 * A generator that generates test data by filling a data set. 23 * @author Michael Zangl 24 */ 25 public static abstract class DataGenerator { 26 private String datasetName; 27 protected final Random random; 28 private DataSet ds; 29 30 /** 31 * Create a new generator. 32 * @param datasetName The name for the generator. Only used for human readability. 33 */ 34 protected DataGenerator(String datasetName) { 35 this.datasetName = datasetName; 36 this.random = new Random(1234); 37 } 38 39 /** 40 * Generates the data set. If this method is called twice, the same dataset is returned. 41 * @return The generated data set. 42 */ 43 public DataSet generateDataSet() { 44 ensureInitialized(); 45 return ds; 46 } 47 48 protected void ensureInitialized() { 49 if (ds == null) { 50 ds = new DataSet(); 51 fillData(ds); 52 } 53 } 54 55 protected abstract void fillData(DataSet ds); 56 57 /** 58 * Create a random node and add it to the dataset. 59 * @return 60 */ 61 protected Node createRandomNode(DataSet ds) { 62 Node node = new Node(); 63 node.setEastNorth(new EastNorth(random.nextDouble(), random.nextDouble())); 64 ds.addPrimitive(node); 65 return node; 66 } 67 68 protected String randomString() { 69 return RandomStringUtils.random(12, 0, 0, true, true, null, random); 70 } 71 72 /** 73 * Gets a file path where this data could be stored. 74 * @return A file path. 75 */ 76 public File getFile() { 77 return new File(DATA_DIR + File.separator + datasetName + ".osm"); 78 } 79 80 /** 81 * Creates a new {@link OsmDataLayer} that uses the underlying dataset of this generator. 82 * @return A new data layer. 83 */ 84 public OsmDataLayer createDataLayer() { 85 return new OsmDataLayer(generateDataSet(), datasetName, getFile()); 86 } 87 88 @Override 89 public String toString() { 90 return "DataGenerator [datasetName=" + datasetName + "]"; 91 } 92 } 93 94 /** 95 * A data generator that generates a bunch of random nodes. 96 * @author Michael Zangl 97 */ 98 public static class NodeDataGenerator extends DataGenerator { 99 protected final ArrayList<Node> nodes = new ArrayList<>(); 100 private final int nodeCount; 101 102 private NodeDataGenerator(String datasetName, int nodeCount) { 103 super(datasetName); 104 this.nodeCount = nodeCount; 105 } 106 107 @Override 108 public void fillData(DataSet ds) { 109 for (int i = 0; i < nodeCount; i++) { 110 nodes.add(createRandomNode(ds)); 111 } 112 } 113 114 /** 115 * Gets a random node of this dataset. 116 * @return A random node. 117 */ 118 public Node randomNode() { 119 ensureInitialized(); 120 return nodes.get(random.nextInt(nodes.size())); 121 } 122 } 123 124 /** 125 * A data generator that generates a bunch of random nodes and fills them with keys/values. 126 * @author Michael Zangl 127 */ 128 public static class KeyValueDataGenerator extends NodeDataGenerator { 129 130 private static final int VALUE_COUNT = 200; 131 private static final int KEY_COUNT = 150; 132 private final double tagNodeRation; 133 private ArrayList<String> keys; 134 private ArrayList<String> values; 135 136 private KeyValueDataGenerator(String datasetName, int nodeCount, double tagNodeRation) { 137 super(datasetName, nodeCount); 138 this.tagNodeRation = tagNodeRation; 139 } 140 141 @Override 142 public void fillData(DataSet ds) { 143 super.fillData(ds); 144 keys = new ArrayList<>(); 145 for (int i = 0; i < KEY_COUNT; i++) { 146 keys.add(randomString()); 147 } 148 values = new ArrayList<>(); 149 for (int i = 0; i < VALUE_COUNT; i++) { 150 values.add(randomString()); 151 } 152 153 double tags = nodes.size() * tagNodeRation; 154 for (int i = 0; i < tags; i++) { 155 String key = randomKey(); 156 String value = randomValue(); 157 nodes.get(random.nextInt(nodes.size())).put(key, value); 158 } 159 } 160 161 /** 162 * Gets a random value that was used to fill the tags. 163 * @return A random String probably used in as value somewhere. 164 */ 165 public String randomValue() { 166 ensureInitialized(); 167 return values.get(random.nextInt(values.size())); 168 } 169 170 /** 171 * Gets a random key that was used to fill the tags. 172 * @return A random String probably used in as key somewhere. 173 */ 174 public String randomKey() { 175 ensureInitialized(); 176 return keys.get(random.nextInt(keys.size())); 177 } 178 } 179 180 /** 181 * Generate a generator that creates some nodes and adds random keys and values to it. 182 * @return The generator 183 */ 184 public static KeyValueDataGenerator getKeyValue() { 185 return getKeyValue(DEFAULT_KEY_VALUE_RATIO); 186 } 187 188 /** 189 * Generate a generator that creates some nodes and adds random keys and values to it. 190 * @param tagNodeRation How many tags to add per node (on average). 191 * @return The generator 192 */ 193 public static KeyValueDataGenerator getKeyValue(double tagNodeRation) { 194 return getKeyValue(DEFAULT_NODE_COUNT, tagNodeRation); 195 } 196 197 /** 198 * Generate a generator that creates some nodes and adds random keys and values to it. 199 * @param nodeCount The number of nodes the dataset should contain. 200 * @param tagNodeRation How many tags to add per node (on average). 201 * @return The generator 202 */ 203 public static KeyValueDataGenerator getKeyValue(int nodeCount, double tagNodeRation) { 204 return new KeyValueDataGenerator("key-value", nodeCount, tagNodeRation); 205 } 206 207 /** 208 * Create a generator that generates a bunch of nodes. 209 * @return The generator 210 */ 211 public static DataGenerator getNodes() { 212 return new NodeDataGenerator("nodes", DEFAULT_NODE_COUNT); 213 } 214 }