/** * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.waveprotocol.wave.model.document.indexed; import org.waveprotocol.wave.model.document.ReadableAnnotationSet; import org.waveprotocol.wave.model.operation.OperationException; import org.waveprotocol.wave.model.util.CollectionFactory; import org.waveprotocol.wave.model.util.CollectionUtils; import java.util.Random; /** * Code that performs random operations on an AnnotationTree for profiling * purposes. Not really a test case. * * @author ohler@google.com (Christian Ohler) */ public class AnnotationTreePerformanceTester { CollectionFactory getFactory() { return CollectionUtils.getCollectionFactory(); } static final int INSERT_LENGTH_LIMIT = 20000; static final int DELETE_LENGTH_LIMIT = 10000; static final int MAX_LENGTH = 1000000; static final int NUM_KEYS = 50; static final int NUM_VALUES = 3; static final int NUM_UPDATES = 10000; static final int QUERIES_PER_UPDATE = 5; public void testPerformance() { Random random = new Random(2); for (int i = 0; i < 5; i++) { System.err.println("run " + i); testPerformance1(random); } } void testPerformance1(Random random) { RawAnnotationSet<Object> a = new SimpleAnnotationSet(null); RawAnnotationSet<Object> b = new AnnotationTree<Object>(new Object(), new Object(), null); String[] keys = new String[NUM_KEYS]; for (int i = 0; i < keys.length; i++) { keys[i] = "k" + i; } String[] values = new String[NUM_KEYS]; for (int i = 0; i < values.length; i++) { values[i] = "v" + i; } int maxLength = 0; RawAnnotationSet<Object> c = b; for (int i = 0; i < NUM_UPDATES; i++) { applyRandomOperation(null, c, keys, values, random); maxLength = Math.max(maxLength, c.size()); for (int j = 0; j < QUERIES_PER_UPDATE; j++) { performRandomQuery(c, keys, random); } } System.err.println("final length=" + c.size() + ", max length=" + maxLength); } void performRandomQuery(ReadableAnnotationSet<Object> a, String[] keys, Random random) { if (a.size() > 0) { int start = random.nextInt(a.size()); int end = 1 + random.nextInt(a.size()); if (start > end) { int swap = start; start = end; end = swap; } for (String key : keys) { a.firstAnnotationChange(start, end, key, "foo"); a.lastAnnotationChange(start, end, key, "foo"); Object value = a.getAnnotation(start, key); a.firstAnnotationChange(start, end, key, value); a.lastAnnotationChange(start, end, key, value); value = a.getAnnotation(end - 1, key); a.firstAnnotationChange(start, end, key, value); a.lastAnnotationChange(start, end, key, value); } } } void applyRandomOperation(RawAnnotationSet<Object> a, RawAnnotationSet<Object> b, String[] keys, String[] values, Random random) { if (a != null) { assert a.size() == b.size(); } try { if (b.size() == 0) { applyRandomInsert(a, b, random); } else if (b.size() >= MAX_LENGTH) { switch (random.nextInt(2)) { case 0: applyRandomDelete(a, b, random); break; case 1: applyRandomSet(a, b, keys, values, random); break; } } else { switch (random.nextInt(3)) { case 0: applyRandomInsert(a, b, random); break; case 1: applyRandomDelete(a, b, random); break; case 2: applyRandomSet(a, b, keys, values, random); break; } } } catch (OperationException e) { throw new RuntimeException(e); } } void setAnnotation(RawAnnotationSet<Object> a, int start, int end, String key, Object value) throws OperationException { a.begin(); if (start > 0) { a.skip(start); } a.startAnnotation(key, value); if (end - start > 0) { a.skip(end - start); } a.endAnnotation(key); a.finish(); } void insert(RawAnnotationSet<Object> a, int firstShiftedIndex, int length) throws OperationException { a.begin(); if (firstShiftedIndex > 0) { a.skip(firstShiftedIndex); } if (length > 0) { a.insert(length); } a.finish(); } void delete(RawAnnotationSet<Object> a, int start, int length) throws OperationException { a.begin(); if (start > 0) { a.skip(start); } if (length > 0) { a.delete(length); } a.finish(); } void applyRandomDelete(RawAnnotationSet<Object> a, RawAnnotationSet<Object> b, Random random) throws OperationException { int pos = random.nextInt(b.size()); int length = random.nextInt(Math.min(DELETE_LENGTH_LIMIT, b.size() - pos)); if (a != null) { delete(a, pos, length); } delete(b, pos, length); } void applyRandomInsert(RawAnnotationSet<Object> a, RawAnnotationSet<Object> b, Random random) throws OperationException { int pos = random.nextInt(b.size() + 1); int length = random.nextInt(INSERT_LENGTH_LIMIT); if (a != null) { insert(a, pos, length); } insert(b, pos, length); } void applyRandomSet(RawAnnotationSet<Object> a, RawAnnotationSet<Object> b, String[] keys, String[] values, Random random) throws OperationException { int start = random.nextInt(b.size()); int end = 1 + random.nextInt(b.size()); if (start > end) { int swap = start; start = end; end = swap; } String key = keys[random.nextInt(keys.length)]; Object value = values[random.nextInt(values.length)]; if (a != null) { setAnnotation(a, start, end, key, value); } setAnnotation(b, start, end, key, value); } public static void main(String[] args) { long startTime = System.currentTimeMillis(); new AnnotationTreePerformanceTester().testPerformance(); long endTime = System.currentTimeMillis(); long time = endTime - startTime; long seconds = time / 1000; System.out.println("time: " + seconds + "s"); } }