-/**
+/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
*/
package org.opendaylight.yangtools.yang.data.impl.tree;
-import java.io.IOException;
+import com.google.common.collect.Streams;
+import java.util.Arrays;
import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.*;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.openjdk.jmh.annotations.*;
+import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.tree.api.CursorAwareDataTreeModification;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.tree.impl.di.InMemoryDataTreeFactory;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
- * Benchmarking of InMemoryDataTree performance.
- *
- * JMH is used for microbenchmarking.
- *
- * @author Lukas Sedlak <lsedlak@cisco.com>
+ * Benchmarking of InMemoryDataTree performance. JMH is used for microbenchmarking.
*
+ * @author Lukas Sedlak <lsedlak@cisco.com>
* @see <a href="http://openjdk.java.net/projects/code-tools/jmh/">JMH</a>
*/
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Fork(1)
public class InMemoryDataTreeBenchmark {
+ private static final int WARMUP_ITERATIONS = 10;
+ private static final int MEASUREMENT_ITERATIONS = 10;
+
private static final int OUTER_LIST_100K = 100000;
private static final int OUTER_LIST_50K = 50000;
private static final int OUTER_LIST_10K = 10000;
- private static final YangInstanceIdentifier[] OUTER_LIST_100K_PATHS = initOuterListPaths(OUTER_LIST_100K);
- private static final YangInstanceIdentifier[] OUTER_LIST_50K_PATHS = initOuterListPaths(OUTER_LIST_50K);
- private static final YangInstanceIdentifier[] OUTER_LIST_10K_PATHS = initOuterListPaths(OUTER_LIST_10K);
+ private static final NodeIdentifierWithPredicates[] OUTER_LIST_IDS = Streams.mapWithIndex(
+ IntStream.range(0, OUTER_LIST_100K),
+ (i, index) -> NodeIdentifierWithPredicates.of(BenchmarkModel.OUTER_LIST_QNAME, BenchmarkModel.ID_QNAME, i))
+ .toArray(NodeIdentifierWithPredicates[]::new);
- private static YangInstanceIdentifier[] initOuterListPaths(final int outerListPathsCount) {
- final YangInstanceIdentifier[] paths = new YangInstanceIdentifier[outerListPathsCount];
-
- for (int outerListKey = 0; outerListKey < outerListPathsCount; ++outerListKey) {
- paths[outerListKey] = YangInstanceIdentifier.builder(BenchmarkModel.OUTER_LIST_PATH)
- .nodeWithKey(BenchmarkModel.OUTER_LIST_QNAME, BenchmarkModel.ID_QNAME, outerListKey)
- .build();
- }
- return paths;
- }
+ private static final YangInstanceIdentifier[] OUTER_LIST_PATHS = Arrays.stream(OUTER_LIST_IDS)
+ .map(id -> BenchmarkModel.OUTER_LIST_PATH.node(id).toOptimized())
+ .toArray(YangInstanceIdentifier[]::new);
+ private static final MapNode EMPTY_OUTER_LIST = ImmutableNodes.newSystemMapBuilder()
+ .withNodeIdentifier(BenchmarkModel.OUTER_LIST)
+ .build();
private static final MapNode ONE_ITEM_INNER_LIST = initInnerListItems(1);
private static final MapNode TWO_ITEM_INNER_LIST = initInnerListItems(2);
private static final MapNode TEN_ITEM_INNER_LIST = initInnerListItems(10);
private static MapNode initInnerListItems(final int count) {
- final CollectionNodeBuilder<MapEntryNode, MapNode> mapEntryBuilder = ImmutableNodes
- .mapNodeBuilder(BenchmarkModel.INNER_LIST_QNAME);
-
- for (int i = 1; i <= count; ++i) {
- mapEntryBuilder
- .withChild(ImmutableNodes.mapEntry(BenchmarkModel.INNER_LIST_QNAME, BenchmarkModel.NAME_QNAME, i));
+ final var mapEntryBuilder = ImmutableNodes.newSystemMapBuilder()
+ .withNodeIdentifier(BenchmarkModel.INNER_LIST);
+
+ for (int i = 0; i < count; ++i) {
+ mapEntryBuilder.withChild(ImmutableNodes.newMapEntryBuilder()
+ .withNodeIdentifier(
+ NodeIdentifierWithPredicates.of(BenchmarkModel.INNER_LIST_QNAME, BenchmarkModel.NAME_QNAME, i))
+ .withChild(ImmutableNodes.leafNode(BenchmarkModel.NAME_QNAME, i))
+ .build());
}
return mapEntryBuilder.build();
}
- private static final NormalizedNode<?, ?>[] OUTER_LIST_ONE_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_100K, ONE_ITEM_INNER_LIST);
- private static final NormalizedNode<?, ?>[] OUTER_LIST_TWO_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_50K, TWO_ITEM_INNER_LIST);
- private static final NormalizedNode<?, ?>[] OUTER_LIST_TEN_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_10K, TEN_ITEM_INNER_LIST);
-
- private static NormalizedNode<?,?>[] initOuterListItems(int outerListItemsCount, MapNode innerList) {
- final NormalizedNode<?,?>[] outerListItems = new NormalizedNode[outerListItemsCount];
-
- for (int i = 0; i < outerListItemsCount; ++i) {
- int outerListKey = i;
- outerListItems[i] = ImmutableNodes.mapEntryBuilder(BenchmarkModel.OUTER_LIST_QNAME, BenchmarkModel.ID_QNAME, outerListKey)
- .withChild(innerList).build();
- }
- return outerListItems;
+ private static final MapEntryNode[] OUTER_LIST_ONE_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_100K,
+ ONE_ITEM_INNER_LIST);
+ private static final MapEntryNode[] OUTER_LIST_TWO_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_50K,
+ TWO_ITEM_INNER_LIST);
+ private static final MapEntryNode[] OUTER_LIST_TEN_ITEM_INNER_LIST = initOuterListItems(OUTER_LIST_10K,
+ TEN_ITEM_INNER_LIST);
+
+ private static MapEntryNode[] initOuterListItems(final int outerListItemsCount, final MapNode innerList) {
+ return Arrays.stream(OUTER_LIST_IDS)
+ .limit(outerListItemsCount)
+ .map(id -> ImmutableNodes.newMapEntryBuilder().withNodeIdentifier(id).withChild(innerList).build())
+ .toArray(MapEntryNode[]::new);
}
- private SchemaContext schemaContext;
private DataTree datastore;
- public static void main(String... args) throws IOException, RunnerException {
+ public static void main(final String... args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(".*" + InMemoryDataTreeBenchmark.class.getSimpleName() + ".*")
.forks(1)
@Setup(Level.Trial)
public void setup() throws DataValidationFailedException {
- schemaContext = BenchmarkModel.createTestContext();
- final InMemoryDataTreeFactory factory = InMemoryDataTreeFactory.getInstance();
- datastore = factory.create();
- datastore.setSchemaContext(schemaContext);
- final DataTreeSnapshot snapshot = datastore.takeSnapshot();
- initTestNode(snapshot);
+ datastore = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_CONFIGURATION,
+ BenchmarkModel.createTestContext());
+
+ final DataTreeModification modification = begin();
+ modification.write(BenchmarkModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
+ .withNodeIdentifier(BenchmarkModel.TEST)
+ .withChild(EMPTY_OUTER_LIST)
+ .build());
+ commit(modification);
}
@TearDown
public void tearDown() {
- schemaContext = null;
datastore = null;
}
- private void initTestNode(final DataTreeSnapshot snapshot) throws DataValidationFailedException {
- final DataTreeModification modification = snapshot.newModification();
- final YangInstanceIdentifier testPath = YangInstanceIdentifier.builder(BenchmarkModel.TEST_PATH)
- .build();
-
- modification.write(testPath, provideOuterListNode());
- datastore.validate(modification);
- final DataTreeCandidate candidate = datastore.prepare(modification);
- datastore.commit(candidate);
+ @Benchmark
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write100KSingleNodeWithOneInnerItemInOneCommitBenchmark() throws DataValidationFailedException {
+ final DataTreeModification modification = begin();
+ for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
+ modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
+ }
+ commit(modification);
}
- private DataContainerChild<?, ?> provideOuterListNode() {
- return ImmutableContainerNodeBuilder
- .create()
- .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(BenchmarkModel.TEST_QNAME))
- .withChild(
- ImmutableNodes.mapNodeBuilder(BenchmarkModel.OUTER_LIST_QNAME)
- .build()).build();
+ @Benchmark
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write100KSingleNodeWithOneInnerItemInOneCommitCursorBenchmark() throws DataValidationFailedException {
+ final CursorAwareDataTreeModification modification = begin();
+ try (var cursor = modification.openCursor(BenchmarkModel.OUTER_LIST_PATH).orElseThrow()) {
+ for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
+ cursor.write(OUTER_LIST_IDS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
+ }
+ }
+ commit(modification);
}
@Benchmark
- @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
- @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
- public void write100KSingleNodeWithOneInnerItemInOneCommitBenchmark() throws Exception {
- final DataTreeSnapshot snapshot = datastore.takeSnapshot();
- final DataTreeModification modification = snapshot.newModification();
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write100KSingleNodeWithOneInnerItemInCommitPerWriteBenchmark() throws DataValidationFailedException {
for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
- modification.write(OUTER_LIST_100K_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
+ final DataTreeModification modification = begin();
+ modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
+ commit(modification);
}
- datastore.validate(modification);
- final DataTreeCandidate candidate = datastore.prepare(modification);
- datastore.commit(candidate);
}
@Benchmark
- @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
- @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
- public void write100KSingleNodeWithOneInnerItemInCommitPerWriteBenchmark() throws Exception {
- final DataTreeSnapshot snapshot = datastore.takeSnapshot();
- for (int outerListKey = 0; outerListKey < OUTER_LIST_100K; ++outerListKey) {
- final DataTreeModification modification = snapshot.newModification();
- modification.write(OUTER_LIST_100K_PATHS[outerListKey], OUTER_LIST_ONE_ITEM_INNER_LIST[outerListKey]);
- datastore.validate(modification);
- final DataTreeCandidate candidate = datastore.prepare(modification);
- datastore.commit(candidate);
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write50KSingleNodeWithTwoInnerItemsInOneCommitBenchmark() throws DataValidationFailedException {
+ final DataTreeModification modification = begin();
+ for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
+ modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
}
+ commit(modification);
}
@Benchmark
- @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
- @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
- public void write50KSingleNodeWithTwoInnerItemsInOneCommitBenchmark() throws Exception {
- final DataTreeSnapshot snapshot = datastore.takeSnapshot();
- final DataTreeModification modification = snapshot.newModification();
- for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
- modification.write(OUTER_LIST_50K_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write50KSingleNodeWithTwoInnerItemsInOneCommitCursorBenchmark() throws DataValidationFailedException {
+ final CursorAwareDataTreeModification modification = begin();
+ try (var cursor = modification.openCursor(BenchmarkModel.OUTER_LIST_PATH).orElseThrow()) {
+ for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
+ cursor.write(OUTER_LIST_IDS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
+ }
}
- datastore.validate(modification);
- final DataTreeCandidate candidate = datastore.prepare(modification);
- datastore.commit(candidate);
+ commit(modification);
}
@Benchmark
- @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
- @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
- public void write50KSingleNodeWithTwoInnerItemsInCommitPerWriteBenchmark() throws Exception {
- final DataTreeSnapshot snapshot = datastore.takeSnapshot();
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write50KSingleNodeWithTwoInnerItemsInCommitPerWriteBenchmark() throws DataValidationFailedException {
for (int outerListKey = 0; outerListKey < OUTER_LIST_50K; ++outerListKey) {
- final DataTreeModification modification = snapshot.newModification();
- modification.write(OUTER_LIST_50K_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
- datastore.validate(modification);
- final DataTreeCandidate candidate = datastore.prepare(modification);
- datastore.commit(candidate);
+ final DataTreeModification modification = begin();
+ modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TWO_ITEM_INNER_LIST[outerListKey]);
+ commit(modification);
}
}
@Benchmark
- @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
- @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
- public void write10KSingleNodeWithTenInnerItemsInOneCommitBenchmark() throws Exception {
- final DataTreeSnapshot snapshot = datastore.takeSnapshot();
- final DataTreeModification modification = snapshot.newModification();
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write10KSingleNodeWithTenInnerItemsInOneCommitBenchmark() throws DataValidationFailedException {
+ final DataTreeModification modification = begin();
for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++outerListKey) {
- modification.write(OUTER_LIST_10K_PATHS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
+ modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
}
- datastore.validate(modification);
- final DataTreeCandidate candidate = datastore.prepare(modification);
- datastore.commit(candidate);
+ commit(modification);
}
@Benchmark
- @Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS)
- @Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS)
- public void write10KSingleNodeWithTenInnerItemsInCommitPerWriteBenchmark() throws Exception {
- final DataTreeSnapshot snapshot = datastore.takeSnapshot();
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write10KSingleNodeWithTenInnerItemsInOneCommitCursorBenchmark() throws DataValidationFailedException {
+ final CursorAwareDataTreeModification modification = begin();
+ try (var cursor = modification.openCursor(BenchmarkModel.OUTER_LIST_PATH).orElseThrow()) {
+ for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++outerListKey) {
+ cursor.write(OUTER_LIST_IDS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
+ }
+ }
+ commit(modification);
+ }
+
+ @Benchmark
+ @Warmup(iterations = WARMUP_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = MEASUREMENT_ITERATIONS, timeUnit = TimeUnit.MILLISECONDS)
+ public void write10KSingleNodeWithTenInnerItemsInCommitPerWriteBenchmark() throws DataValidationFailedException {
for (int outerListKey = 0; outerListKey < OUTER_LIST_10K; ++outerListKey) {
- final DataTreeModification modification = snapshot.newModification();
- modification.write(OUTER_LIST_10K_PATHS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
- datastore.validate(modification);
- final DataTreeCandidate candidate = datastore.prepare(modification);
- datastore.commit(candidate);
+ final DataTreeModification modification = begin();
+ modification.write(OUTER_LIST_PATHS[outerListKey], OUTER_LIST_TEN_ITEM_INNER_LIST[outerListKey]);
+ commit(modification);
}
}
+
+ private CursorAwareDataTreeModification begin() {
+ return (CursorAwareDataTreeModification) datastore.takeSnapshot().newModification();
+ }
+
+ private void commit(final DataTreeModification modification) throws DataValidationFailedException {
+ modification.ready();
+ datastore.validate(modification);
+ datastore.commit(datastore.prepare(modification));
+ }
}