001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.caching;
017:
018: import com.vividsolutions.jts.geom.Coordinate;
019: import com.vividsolutions.jts.geom.Envelope;
020:
021: import junit.framework.Test;
022: import junit.framework.TestCase;
023: import junit.framework.TestSuite;
024:
025: import org.geotools.caching.Generator;
026: import org.geotools.caching.impl.InMemoryDataCache;
027: import org.geotools.caching.impl.InMemoryFeatureCache;
028: import org.geotools.caching.impl.SpatialQueryTracker;
029:
030: import org.geotools.data.DataStore;
031: import org.geotools.data.FeatureLocking;
032: import org.geotools.data.FeatureSource;
033: import org.geotools.data.Query;
034: import org.geotools.data.memory.MemoryDataStore;
035: import org.geotools.data.shapefile.ShapefileDataStore;
036:
037: import org.geotools.feature.DefaultFeatureCollection;
038: import org.geotools.feature.FeatureCollection;
039: import org.geotools.feature.FeatureIterator;
040: import org.geotools.feature.FeatureType;
041: import org.geotools.feature.SchemaException;
042:
043: import org.geotools.filter.FilterFactoryImpl;
044: import org.geotools.filter.spatial.BBOXImpl;
045:
046: import java.io.File;
047: import java.io.IOException;
048:
049: import java.net.MalformedURLException;
050: import java.net.URI;
051: import java.net.URL;
052:
053: import java.util.ArrayList;
054: import java.util.Collection;
055: import java.util.Iterator;
056: import java.util.List;
057: import java.util.TreeSet;
058:
059: public class InMemoryFeatureCacheBenchmarkTest extends TestCase {
060: private final static short UNCHANGED = 0;
061: private final static short OPTIMIZED = 1;
062: private final static short EMPTYQUERY = 2;
063: private final List querySet = new ArrayList();
064: private Collection data = null;
065: private FeatureType type = null;
066:
067: private void createQuerySet(int numberOfQueries) {
068: System.out.println("=== Creating Query Set");
069:
070: Coordinate p = Generator.pickRandomPoint(new Coordinate(500,
071: 500), 950, 950);
072: Coordinate last = p;
073:
074: for (int i = 0; i < numberOfQueries; i++) {
075: querySet.add(Generator.createBboxQuery(p, 100, 100));
076: p = Generator.pickRandomPoint(p, 50, 50);
077: querySet.add(Generator.createBboxQuery(p, 50, 50));
078: p = Generator.pickRandomPoint(p, 20, 20);
079: querySet.add(Generator.createBboxQuery(p, 20, 20));
080:
081: Coordinate temp = p;
082: p = last;
083: last = temp;
084: }
085: }
086:
087: private void createRandomQuerySet(int numberOfQueries) {
088: System.out.println("=== Creating Query Set");
089:
090: for (int i = 0; i < numberOfQueries; i++) {
091: Coordinate p = Generator.pickRandomPoint(new Coordinate(
092: 500, 500), 950, 950);
093: querySet.add(Generator.createBboxQuery(p, 10, 10));
094: }
095: }
096:
097: private List createDataSet(int numberOfData) {
098: System.out.println("=== Creating Data Set");
099:
100: Generator gen = new Generator(1000, 1000);
101: type = gen.getFeatureType();
102:
103: List ret = new ArrayList();
104:
105: for (int i = 0; i < numberOfData; i++) {
106: ret.add(gen.createFeature(i));
107: }
108:
109: return ret;
110: }
111:
112: protected void setUp() throws Exception {
113: super .setUp();
114: data = createDataSet(2000);
115: }
116:
117: public static Test suite() {
118: return new TestSuite(InMemoryFeatureCacheBenchmarkTest.class);
119: }
120:
121: public void ztestShapefileStore() throws IOException,
122: MalformedURLException {
123: File f = new File("target/test.shp");
124: ShapefileDataStore sds = new ShapefileDataStore(f.toURL(), URI
125: .create("testStore"));
126:
127: if (!f.exists()) {
128: sds.createSchema(type);
129:
130: if (sds.getFeatureSource() instanceof FeatureLocking) {
131: FeatureLocking fl = (FeatureLocking) sds
132: .getFeatureSource();
133: FeatureCollection col = new DefaultFeatureCollection(
134: "testStore", type);
135: col.addAll(data);
136: fl.addFeatures(col);
137: }
138: } else {
139: if (sds.getSchema().equals(type)) {
140: System.out.println("Schema ok");
141: } else {
142: System.out.println(sds.getSchema());
143: System.out.println(type);
144: }
145: }
146: }
147:
148: public void testDataCacheConformance() throws IOException,
149: SchemaException, FeatureCacheException {
150: createRandomQuerySet(50);
151:
152: MemoryDataStore control = new MemoryDataStore();
153: control.createSchema(type);
154: control.addFeatures(data);
155:
156: MemoryDataStore ds = new MemoryDataStore();
157: ds.createSchema(type);
158: ds.addFeatures(data);
159:
160: InMemoryFeatureCache tested = new InMemoryFeatureCache(ds,
161: type, 1000);
162: Iterator iter = querySet.iterator();
163:
164: while (iter.hasNext()) {
165: Query q = (Query) iter.next();
166: FeatureCollection controlSet = control.getView(q)
167: .getFeatures();
168: FeatureCollection testedSet = tested.getFeatures(q);
169: assertTrue(compareFeatureCollectionByHash(controlSet,
170: testedSet));
171: }
172:
173: System.out.println("Cache reads = " + tested.getCacheReads());
174: System.out.println("Store reads = " + tested.getStoreReads());
175: System.out.println("Evictions = " + tested.getEvictions());
176: }
177:
178: public void testDataCachePerformance() throws IOException,
179: FeatureCacheException {
180: createQuerySet(25);
181:
182: MemoryDataStore control = new MemoryDataStore();
183: control.createSchema(type);
184: control.addFeatures(data);
185:
186: MemoryDataStore ds = new MemoryDataStore();
187: ds.createSchema(type);
188: ds.addFeatures(data);
189:
190: InMemoryFeatureCache tested = new InMemoryFeatureCache(ds,
191: type, 2500);
192: tested.getFeatures(new FilterFactoryImpl().bbox("", 0, 0, 1000,
193: 1000, ""));
194:
195: long diff = compareDataStores(tested, control
196: .getFeatureSource(type.getTypeName()), querySet);
197:
198: //assertTrue(diff < 0);
199: System.out.println("Cache reads = " + tested.getCacheReads());
200: System.out.println("Store reads = " + tested.getStoreReads());
201: System.out.println("Evictions = " + tested.getEvictions());
202: }
203:
204: public void ztestDataCachePerformanceRandomQueries()
205: throws IOException, FeatureCacheException {
206: createRandomQuerySet(50);
207:
208: MemoryDataStore control = new MemoryDataStore();
209: control.createSchema(type);
210: control.addFeatures(data);
211:
212: MemoryDataStore ds = new MemoryDataStore();
213: ds.createSchema(type);
214: ds.addFeatures(data);
215:
216: InMemoryFeatureCache tested = new InMemoryFeatureCache(ds,
217: type, 1000);
218: long diff = compareDataStores(tested, control
219: .getFeatureSource(type.getTypeName()), querySet);
220:
221: System.out.println("Cache reads = " + tested.getCacheReads());
222: System.out.println("Store reads = " + tested.getStoreReads());
223: System.out.println("Evictions = " + tested.getEvictions());
224: }
225:
226: private short compareQuery(Query q1, Query q2) {
227: if (q1.equals(q2)) {
228: return UNCHANGED;
229: }
230:
231: if ((q1.getFilter() instanceof BBOXImpl)
232: && (q2.getFilter() instanceof BBOXImpl)) {
233: BBOXImpl bb = (BBOXImpl) q1.getFilter();
234: Envelope env1 = new Envelope(bb.getMinX(), bb.getMaxX(), bb
235: .getMinY(), bb.getMaxY());
236: bb = (BBOXImpl) q2.getFilter();
237:
238: Envelope env2 = new Envelope(bb.getMinX(), bb.getMaxX(), bb
239: .getMinY(), bb.getMaxY());
240:
241: if (env1.equals(env2)) {
242: return UNCHANGED;
243: } else {
244: return OPTIMIZED;
245: }
246: } else {
247: return EMPTYQUERY;
248: }
249: }
250:
251: private static QueryStatistics[] runQueries(FeatureSource fs,
252: List querySet) {
253: QueryStatistics[] stats = new QueryStatistics[querySet.size()];
254: Iterator iter = querySet.iterator();
255: int i = 0;
256:
257: while (iter.hasNext()) {
258: Query q = (Query) iter.next();
259: stats[i] = new QueryStatistics();
260:
261: try {
262: long startTime = System.currentTimeMillis();
263:
264: //System.out.print(".") ;
265: FeatureCollection resultSet = fs.getFeatures(q);
266: FeatureIterator fiter = resultSet.features();
267:
268: while (fiter.hasNext()) {
269: fiter.next();
270: }
271:
272: resultSet.close(fiter);
273:
274: long endTime = System.currentTimeMillis();
275: stats[i].setNumberOfFeatures(resultSet.size());
276: stats[i].setExecutionTime(endTime - startTime);
277: } catch (IOException e) {
278: // TODO Auto-generated catch block
279: e.printStackTrace();
280: }
281:
282: i++;
283: }
284:
285: return stats;
286: }
287:
288: protected static long compareDataStores(FeatureSource ds,
289: FeatureSource control, List querySet) {
290: QueryStatistics[] ds_stats = runQueries(ds, querySet);
291: QueryStatistics[] control_stats = runQueries(control, querySet);
292: long meanDifference = 0;
293: long meanOverhead = 0;
294: int overheadCount = 0;
295: long meanLeverage = 0;
296: int leverageCount = 0;
297:
298: for (int i = 0; i < querySet.size(); i++) {
299: if (i > 1) {
300: long diff = ds_stats[i].getExecutionTime()
301: - control_stats[i].getExecutionTime();
302: meanDifference += diff;
303:
304: if (diff > 0) {
305: overheadCount++;
306: meanOverhead += diff;
307: } else {
308: leverageCount++;
309: meanLeverage += diff;
310: }
311: }
312:
313: /*System.out.println("Test: " + ds_stats[i].getNumberOfFeatures() + " features ; "
314: + ds_stats[i].getExecutionTime() + " ms ; " + "Control: "
315: + control_stats[i].getNumberOfFeatures() + " features ; "
316: + control_stats[i].getExecutionTime() + " ms ; "); */
317: }
318:
319: meanDifference = ((querySet.size() - 2) > 0) ? (meanDifference / (querySet
320: .size() - 2))
321: : 0;
322: meanOverhead = (overheadCount > 0) ? (meanOverhead / overheadCount)
323: : 0;
324: meanLeverage = (leverageCount > 0) ? (meanLeverage / leverageCount)
325: : 0;
326: System.out.println("Mean execution time difference = "
327: + meanDifference + " ms.");
328: System.out
329: .println("Mean overhead = "
330: + meanOverhead
331: + " ms. ("
332: + ((100 * overheadCount) / (overheadCount + leverageCount))
333: + " %)");
334: System.out
335: .println("Mean leverage = "
336: + meanLeverage
337: + " ms. ("
338: + ((100 * leverageCount) / (overheadCount + leverageCount))
339: + " %)");
340:
341: return meanDifference;
342: }
343:
344: protected static boolean compareFeatureCollectionByID(
345: FeatureCollection set1, FeatureCollection set2) {
346: if (set1.size() == set2.size()) {
347: FeatureIterator iter = set1.features();
348: TreeSet ids1 = new TreeSet();
349:
350: while (iter.hasNext()) {
351: ids1.add(iter.next().getID());
352: }
353:
354: set1.close(iter);
355: iter = set2.features();
356:
357: TreeSet ids2 = new TreeSet();
358:
359: while (iter.hasNext()) {
360: ids2.add(iter.next().getID());
361: }
362:
363: set2.close(iter);
364:
365: Iterator i2 = ids2.iterator();
366:
367: for (Iterator i1 = ids1.iterator(); i1.hasNext();) {
368: String id1 = (String) i1.next();
369: String id2 = (String) i2.next();
370:
371: if (!id1.equals(id2)) {
372: return false;
373: }
374: }
375:
376: return true;
377: }
378:
379: return false;
380: }
381:
382: protected static boolean compareFeatureCollectionByHash(
383: FeatureCollection set1, FeatureCollection set2) {
384: if (set1.size() == set2.size()) {
385: FeatureIterator iter = set1.features();
386: TreeSet ids1 = new TreeSet();
387:
388: while (iter.hasNext()) {
389: ids1.add(new Integer(iter.next().hashCode()));
390: }
391:
392: set1.close(iter);
393: iter = set2.features();
394:
395: TreeSet ids2 = new TreeSet();
396:
397: while (iter.hasNext()) {
398: ids2.add(new Integer(iter.next().hashCode()));
399: }
400:
401: set2.close(iter);
402:
403: Iterator i2 = ids2.iterator();
404:
405: for (Iterator i1 = ids1.iterator(); i1.hasNext();) {
406: Integer id1 = (Integer) i1.next();
407: Integer id2 = (Integer) i2.next();
408:
409: if (!id1.equals(id2)) {
410: return false;
411: }
412: }
413:
414: return true;
415: }
416:
417: return false;
418: }
419: }
|