Rework NormalizedNode type hierarchy
[yangtools.git] / benchmarks / src / main / java / org / opendaylight / yangtools / yang / data / impl / tree / InMemoryDataTreeBenchmark.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.impl.tree;
9
10 import com.google.common.collect.Streams;
11 import java.util.Arrays;
12 import java.util.concurrent.TimeUnit;
13 import java.util.stream.Collectors;
14 import java.util.stream.IntStream;
15 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
17 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeModification;
22 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
23 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
24 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
25 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
26 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
28 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
29 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
30 import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
31 import org.openjdk.jmh.annotations.Benchmark;
32 import org.openjdk.jmh.annotations.BenchmarkMode;
33 import org.openjdk.jmh.annotations.Fork;
34 import org.openjdk.jmh.annotations.Level;
35 import org.openjdk.jmh.annotations.Measurement;
36 import org.openjdk.jmh.annotations.Mode;
37 import org.openjdk.jmh.annotations.OutputTimeUnit;
38 import org.openjdk.jmh.annotations.Scope;
39 import org.openjdk.jmh.annotations.Setup;
40 import org.openjdk.jmh.annotations.State;
41 import org.openjdk.jmh.annotations.TearDown;
42 import org.openjdk.jmh.annotations.Warmup;
43 import org.openjdk.jmh.runner.Runner;
44 import org.openjdk.jmh.runner.RunnerException;
45 import org.openjdk.jmh.runner.options.Options;
46 import org.openjdk.jmh.runner.options.OptionsBuilder;
47
48 /**
49  * Benchmarking of InMemoryDataTree performance. JMH is used for microbenchmarking.
50  *
51  * @author Lukas Sedlak <lsedlak@cisco.com>
52  * @see <a href="http://openjdk.java.net/projects/code-tools/jmh/">JMH</a>
53  */
54 @State(Scope.Thread)
55 @BenchmarkMode(Mode.AverageTime)
56 @OutputTimeUnit(TimeUnit.MILLISECONDS)
57 @Fork(1)
58 public class InMemoryDataTreeBenchmark {
59
60     private static final int WARMUP_ITERATIONS = 10;
61     private static final int MEASUREMENT_ITERATIONS = 10;
62
63     private static final int OUTER_LIST_100K = 100000;
64     private static final int OUTER_LIST_50K = 50000;
65     private static final int OUTER_LIST_10K = 10000;
66
67     private static final NodeIdentifierWithPredicates[] OUTER_LIST_IDS = Streams.mapWithIndex(
68         IntStream.range(0, OUTER_LIST_100K),
69         (i, index) -> NodeIdentifierWithPredicates.of(BenchmarkModel.OUTER_LIST_QNAME, BenchmarkModel.ID_QNAME, i))
70             .collect(Collectors.toList()).toArray(new NodeIdentifierWithPredicates[0]);
71
72     private static final YangInstanceIdentifier[] OUTER_LIST_PATHS = Arrays.stream(OUTER_LIST_IDS)
73             .map(id -> BenchmarkModel.OUTER_LIST_PATH.node(id).toOptimized())
74             .collect(Collectors.toList()).toArray(new YangInstanceIdentifier[0]);
75
76     private static final MapNode EMPTY_OUTER_LIST = ImmutableNodes.mapNodeBuilder(BenchmarkModel.OUTER_LIST).build();
77     private static final MapNode ONE_ITEM_INNER_LIST = initInnerListItems(1);
78     private static final MapNode TWO_ITEM_INNER_LIST = initInnerListItems(2);
79     private static final MapNode TEN_ITEM_INNER_LIST = initInnerListItems(10);
80
81     private static MapNode initInnerListItems(final int count) {
82         final CollectionNodeBuilder<MapEntryNode, SystemMapNode> mapEntryBuilder = ImmutableNodes
83             .mapNodeBuilder(BenchmarkModel.INNER_LIST);
84
85         for (int i = 0; i < count; ++i) {
86             mapEntryBuilder
87                 .withChild(ImmutableNodes.mapEntry(BenchmarkModel.INNER_LIST_QNAME, BenchmarkModel.NAME_QNAME, i));
88         }
89
90         return mapEntryBuilder.build();
91     }
92
93     private static final NormalizedNode[] OUTER_LIST_ONE_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_100K,
94         ONE_ITEM_INNER_LIST);
95     private static final NormalizedNode[] OUTER_LIST_TWO_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_50K,
96         TWO_ITEM_INNER_LIST);
97     private static final NormalizedNode[] OUTER_LIST_TEN_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_10K,
98         TEN_ITEM_INNER_LIST);
99
100     private static NormalizedNode[] initOuterListItems(final int outerListItemsCount, final MapNode innerList) {
101         return Arrays.stream(OUTER_LIST_IDS).limit(outerListItemsCount)
102                 .map(id -> ImmutableNodes.mapEntryBuilder().withNodeIdentifier(id).withChild(innerList).build())
103                 .collect(Collectors.toList()).toArray(new NormalizedNode[0]);
104     }
105
106     private DataTree datastore;
107
108     public static void main(final String... args) throws RunnerException {
109         Options opt = new OptionsBuilder()
110             .include(".*" + InMemoryDataTreeBenchmark.class.getSimpleName() + ".*")
111             .forks(1)
112             .build();
113
114         new Runner(opt).run();
115     }
116
117     @Setup(Level.Trial)
118     public void setup() throws DataValidationFailedException {
119         datastore = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_CONFIGURATION,
120             BenchmarkModel.createTestContext());
121
122         final DataTreeModification modification = begin();
123         modification.write(BenchmarkModel.TEST_PATH, ImmutableContainerNodeBuilder.create()
124             .withNodeIdentifier(BenchmarkModel.TEST).withChild(EMPTY_OUTER_LIST).build());
125         commit(modification);
126     }
127
128     @TearDown
129     public void tearDown() {
130         datastore = null;
131     }
132
133     @Benchmark
134     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
135     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
136     public void write100KSingleNodeWithOneInnerItemInOneCommitBenchmark() throws DataValidationFailedException {
137         final DataTreeModification modification = begin();
138         for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
139             modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
140         }
141         commit(modification);
142     }
143
144     @Benchmark
145     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
146     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
147     public void write100KSingleNodeWithOneInnerItemInOneCommitCursorBenchmark() throws DataValidationFailedException {
148         final CursorAwareDataTreeModification modification = begin();
149         try (DataTreeModificationCursor cursor = modification.openCursor(BenchmarkModel.OUTER_LIST_PATH).get()) {
150             for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
151                 cursor.write(OUTER_LIST_IDS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
152             }
153         }
154         commit(modification);
155     }
156
157     @Benchmark
158     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
159     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
160     public void write100KSingleNodeWithOneInnerItemInCommitPerWriteBenchmark() throws DataValidationFailedException {
161         for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
162             final DataTreeModification modification = begin();
163             modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
164             commit(modification);
165         }
166     }
167
168     @Benchmark
169     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
170     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
171     public void write50KSingleNodeWithTwoInnerItemsInOneCommitBenchmark() throws DataValidationFailedException {
172         final DataTreeModification modification = begin();
173         for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
174             modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
175         }
176         commit(modification);
177     }
178
179     @Benchmark
180     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
181     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
182     public void write50KSingleNodeWithTwoInnerItemsInOneCommitCursorBenchmark() throws DataValidationFailedException {
183         final CursorAwareDataTreeModification modification = begin();
184         try (DataTreeModificationCursor cursor = modification.openCursor(BenchmarkModel.OUTER_LIST_PATH).get()) {
185             for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
186                 cursor.write(OUTER_LIST_IDS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
187             }
188         }
189         commit(modification);
190     }
191
192     @Benchmark
193     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
194     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
195     public void write50KSingleNodeWithTwoInnerItemsInCommitPerWriteBenchmark() throws DataValidationFailedException {
196         for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
197             final DataTreeModification modification = begin();
198             modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
199             commit(modification);
200         }
201     }
202
203     @Benchmark
204     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
205     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
206     public void write10KSingleNodeWithTenInnerItemsInOneCommitBenchmark() throws DataValidationFailedException {
207         final DataTreeModification modification = begin();
208         for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++outerListKey) {
209             modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
210         }
211         commit(modification);
212     }
213
214     @Benchmark
215     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
216     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
217     public void write10KSingleNodeWithTenInnerItemsInOneCommitCursorBenchmark() throws DataValidationFailedException {
218         final CursorAwareDataTreeModification modification = begin();
219         try (DataTreeModificationCursor cursor = modification.openCursor(BenchmarkModel.OUTER_LIST_PATH).get()) {
220             for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++outerListKey) {
221                 cursor.write(OUTER_LIST_IDS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
222             }
223         }
224         commit(modification);
225     }
226
227     @Benchmark
228     @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
229     @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
230     public void write10KSingleNodeWithTenInnerItemsInCommitPerWriteBenchmark() throws DataValidationFailedException {
231         for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++outerListKey) {
232             final DataTreeModification modification = begin();
233             modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
234             commit(modification);
235         }
236     }
237
238     private CursorAwareDataTreeModification begin() {
239         return (CursorAwareDataTreeModification) datastore.takeSnapshot().newModification();
240     }
241
242     private void commit(final DataTreeModification modification) throws DataValidationFailedException {
243         modification.ready();
244         datastore.validate(modification);
245         datastore.commit(datastore.prepare(modification));
246     }
247 }