summaryrefslogtreecommitdiffstats
path: root/infra/it
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-11-03 16:24:17 +0100
committerMaros Marsalek <mmarsale@cisco.com>2016-11-07 15:33:48 +0100
commit03a638b95da83e150d4f69451c8733b5f09c37aa (patch)
tree970f6f3afed85d073476b63108c7a12f1200557e /infra/it
parent5fd09f98a9fde773b275c2266f39552cda861713 (diff)
HONEYCOMB-287 Infra micro-benchmarks
Config (write) Operational (read) Add -Pbenchmark to maven execution to include benchmarks Change-Id: Ia4815ffc109e34629279b9418b962a9f91c38c30 Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'infra/it')
-rw-r--r--infra/it/benchmark/asciidoc/Readme.adoc3
-rw-r--r--infra/it/benchmark/pom.xml137
-rw-r--r--infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerConfigWriteBenchmark.java210
-rw-r--r--infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerOperReadBenchmark.java198
-rw-r--r--infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataProvider.java197
-rw-r--r--infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataSubmitter.java40
-rw-r--r--infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/FileManager.java41
-rw-r--r--infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/NoopWriter.java63
-rw-r--r--infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/StaticReader.java83
-rw-r--r--infra/it/benchmark/src/main/resources/logback.xml26
-rw-r--r--infra/it/pom.xml12
11 files changed, 1010 insertions, 0 deletions
diff --git a/infra/it/benchmark/asciidoc/Readme.adoc b/infra/it/benchmark/asciidoc/Readme.adoc
new file mode 100644
index 0000000..44d2262
--- /dev/null
+++ b/infra/it/benchmark/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= benchmark
+
+Overview of benchmark \ No newline at end of file
diff --git a/infra/it/benchmark/pom.xml b/infra/it/benchmark/pom.xml
new file mode 100644
index 0000000..5ee3c08
--- /dev/null
+++ b/infra/it/benchmark/pom.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ Copyright (c) 2016 Cisco and/or its affiliates.
+ ~
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>honeycomb-parent</artifactId>
+ <version>1.16.12-SNAPSHOT</version>
+ <relativePath>../../../common/honeycomb-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>benchmark</artifactId>
+ <version>1.16.12-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <properties>
+ <jmh.version>1.15</jmh.version>
+ <uberjar.name>benchmarks</uberjar.name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-core</artifactId>
+ <version>${jmh.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-generator-annprocess</artifactId>
+ <version>${jmh.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>minimal-distribution</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.honeycomb.it</groupId>
+ <artifactId>honeycomb-test-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/main/resources</directory>
+ <!-- Enable maven to replace properties in resource files -->
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>build-classpath</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>build-classpath</goal>
+ </goals>
+ <configuration>
+ <outputProperty>depClasspath</outputProperty>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>benchmark</id>
+ <phase>test</phase>
+ <goals>
+ <goal>java</goal>
+ </goals>
+ <configuration>
+ <mainClass>org.openjdk.jmh.Main</mainClass>
+ <systemProperties>
+ <systemProperty>
+ <key>java.class.path</key>
+ <value>${project.build.outputDirectory}${path.separator}${depClasspath}</value>
+ </systemProperty>
+ </systemProperties>
+ <arguments>
+ <!-- Reference org.openjdk.jmh.runner.options.CommandLineOptions -->
+
+ <!-- Fail on error -->
+ <argument>-foe=true</argument>
+
+ <!-- PROFILING -->
+ <!-- cl: Classloader profiling via standard MBeans
+ comp: JIT compiler profiling via standard MBeans
+ gc: GC profiling via standard MBeans
+ hs_cl: HotSpot (tm) classloader profiling via implementation-specific MBeans
+ hs_comp: HotSpot (tm) JIT compiler profiling via implementation-specific MBeans
+ hs_gc: HotSpot (tm) memory manager (GC) profiling via implementation-specific MBeans
+ hs_rt: HotSpot (tm) runtime profiling via implementation-specific MBeans
+ hs_thr: HotSpot (tm) threading subsystem via implementation-specific MBeans
+ pauses: Pauses profiler
+ stack: Simple and naive Java stack profiler -->
+ <!--<argument>-prof=gc</argument>-->
+
+ <!-- REPORT -->
+ <!-- formats = Available formats: text, csv, scsv, json, latex-->
+ <argument>-rf=csv</argument>
+ <argument>-rff=${project.build.directory}/benchmark.csv</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerConfigWriteBenchmark.java b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerConfigWriteBenchmark.java
new file mode 100644
index 0000000..145cd2b
--- /dev/null
+++ b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerConfigWriteBenchmark.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.benchmark.data;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+import io.fd.honeycomb.benchmark.util.DataProvider;
+import io.fd.honeycomb.benchmark.util.DataSubmitter;
+import io.fd.honeycomb.benchmark.util.FileManager;
+import io.fd.honeycomb.benchmark.util.NoopWriter;
+import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
+import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.Param;
+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.Timeout;
+import org.openjdk.jmh.annotations.Warmup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Measures the performance of CONFIG writes into BA DataBroker, backed by HC infrastructure and then NOOP writers.
+ */
+@Timeout(time = 20)
+@Warmup(iterations = 2, time = 10)
+@Measurement(iterations = 2, time = 10)
+@Fork(2)
+@State(Scope.Thread)
+@BenchmarkMode(Mode.Throughput)
+public class DataBrokerConfigWriteBenchmark extends AbstractModule implements FileManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DataBrokerConfigWriteBenchmark.class);
+
+ @Param({"1", "10"/*, "100"*/})
+ private int submitFrequency;
+
+ @Param({"true", "false"})
+ private boolean persistence;
+
+ @Param({"put"/*, "merge"*/})
+ private String operation;
+ private DataSubmitter submitter;
+
+ @Param({"CONFIGURATION"})
+ private LogicalDatastoreType dsType;
+
+ @Param({DataProvider.SIMPLE_CONTAINER, DataProvider.LIST_IN_CONTAINER , DataProvider.COMPLEX_LIST_IN_CONTAINER})
+ private String data;
+ private DataProvider dataProvider;
+
+ /*
+ * TODO HONEYCOMB-288 Visualization notes:
+ * - visualize as 3 graphs, 1 for each data
+ * - each graph should show 4 lines. for the combinations of parameters: submitFrequency and persistence
+ * (if that's too much split or reduce submitFrequecy values that are shown in graph)
+ *
+ * TODO data need to be prepared for such visualization. Maybe if each benchmark class exposed a method to prepare
+ * that data from aggregated results... it might be easy
+ * (just maven exec plugin + main that invokes some method on all benchmark classes)
+ */
+
+ // Infra modules to load
+ private final Module[] modules = new Module[] {
+ new io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule(),
+ new io.fd.honeycomb.infra.distro.schema.SchemaModule(),
+ new io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule(),
+ new io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule(),
+ this};
+
+ private List<NoopWriter<?>> noopWriters = new ArrayList<>();
+ private DataBroker dataBroker;
+ private long counter = 0;
+ private WriteTransaction tx;
+ private HoneycombConfiguration instance;
+
+ @Setup(Level.Iteration)
+ public void setup() {
+ LOG.info("Setting up");
+ submitter = DataSubmitter.from(operation);
+ dataProvider = DataProvider.from(data);
+ Injector injector = Guice.createInjector(modules);
+ final HoneycombConfiguration cfg = injector.getInstance(HoneycombConfiguration.class);
+ LOG.info("Configuration for Honeycomb: {}", cfg);
+ dataBroker = injector.getInstance(Key.get(DataBroker.class,
+ Names.named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG)));
+ }
+
+ @TearDown(Level.Iteration)
+ public void tearDown() {
+ LOG.info("Tearing down after {} executions", counter);
+ counter = 0;
+ LOG.info("Writer invocations: {}", noopWriters);
+ noopWriters.clear();
+
+ tx = null;
+ dataBroker = null;
+ deleteFile(Paths.get(instance.peristConfigPath));
+ deleteFile(Paths.get(instance.peristContextPath));
+ }
+
+ @Benchmark
+ public void write() {
+ // Count executions
+ counter++;
+
+ // New transaction after it was committed
+ if (tx == null) {
+ tx = dataBroker.newWriteOnlyTransaction();
+ }
+
+ submitter.submit(dsType, tx, dataProvider.getId(counter), dataProvider.getData(counter));
+
+ // Commit based on frequency set
+ if (counter % submitFrequency == 0) {
+ try {
+ tx.submit().get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException("Submit failed", e);
+ }
+ tx = null;
+ }
+ }
+
+ /**
+ * Inject custom modules e.g. configuration.
+ */
+ @Override
+ protected void configure() {
+ try {
+ instance = getHoneycombConfiguration(persistence);
+ bind(HoneycombConfiguration.class).toInstance(instance);
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to prepare configuration", e);
+ }
+
+ final Multibinder<WriterFactory> writeBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writeBinder.addBinding().toInstance(registry -> {
+ // Add noop writers for all data written in this benchmark
+ addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(SimpleContainer.class)));
+ addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)));
+ addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
+ .child(ListInContainer.class)));
+ addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
+ .child(ListInContainer.class)
+ .child(ContainerInList.class)));
+ addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
+ .child(ListInContainer.class)
+ .child(ContainerInList.class)
+ .child(NestedList.class)));
+ });
+ }
+
+ private void addWriter(final ModifiableWriterRegistryBuilder registry, final NoopWriter<?> handler) {
+ noopWriters.add(handler);
+ registry.add(handler);
+ }
+
+ private static HoneycombConfiguration getHoneycombConfiguration(final boolean persistence) throws IOException {
+ final HoneycombConfiguration instance = new HoneycombConfiguration();
+ instance.persistConfig = Optional.of(Boolean.toString(persistence));
+ instance.persistContext = Optional.of(Boolean.toString(persistence));
+ instance.peristConfigPath = FileManager.INSTANCE.createTempFile("config").toString();
+ instance.peristContextPath = FileManager.INSTANCE.createTempFile("context").toString();
+ return instance;
+ }
+}
diff --git a/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerOperReadBenchmark.java b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerOperReadBenchmark.java
new file mode 100644
index 0000000..2fd9fa2
--- /dev/null
+++ b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/data/DataBrokerOperReadBenchmark.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.benchmark.data;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+import io.fd.honeycomb.benchmark.util.DataProvider;
+import io.fd.honeycomb.benchmark.util.FileManager;
+import io.fd.honeycomb.benchmark.util.StaticReader;
+import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
+import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
+import io.fd.honeycomb.translate.read.Reader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.Param;
+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.Timeout;
+import org.openjdk.jmh.annotations.Warmup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Measures the performance of CONFIG writes into BA DataBroker, backed by HC infrastructure and then NOOP writers.
+ */
+@Timeout(time = 20)
+@Warmup(iterations = 2, time = 10)
+@Measurement(iterations = 2, time = 10)
+@Fork(2)
+@State(Scope.Thread)
+@BenchmarkMode(Mode.Throughput)
+public class DataBrokerOperReadBenchmark extends AbstractModule implements FileManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DataBrokerOperReadBenchmark.class);
+
+ @Param({"OPERATIONAL"})
+ private LogicalDatastoreType dsType;
+
+ // Persistence does not make a difference when only reading operational
+ @Param({"false"})
+ private boolean persistence;
+
+ @Param({DataProvider.SIMPLE_CONTAINER, DataProvider.LIST_IN_CONTAINER, DataProvider.COMPLEX_LIST_IN_CONTAINER})
+ private String data;
+ private DataProvider dataProvider;
+
+ /*
+ * TODO HONEYCOMB-288 Visualization notes:
+ * - visualize as 1 graph
+ * - just 3 lines
+ */
+
+ // Infra modules to load
+ private final Module[] modules = new Module[] {
+ new io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule(),
+ new io.fd.honeycomb.infra.distro.schema.SchemaModule(),
+ new ConfigAndOperationalPipelineModule(),
+ new io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule(),
+ this};
+
+ private List<Reader<?, ?>> noopReaders = new ArrayList<>();
+ private DataBroker dataBroker;
+ private long counter = 0;
+ private ReadOnlyTransaction tx;
+ private HoneycombConfiguration instance;
+
+ @Setup(Level.Iteration)
+ public void setup() {
+ LOG.info("Setting up");
+ dataProvider = DataProvider.from(data);
+ Injector injector = Guice.createInjector(modules);
+ final HoneycombConfiguration cfg = injector.getInstance(HoneycombConfiguration.class);
+ LOG.info("Configuration for Honeycomb: {}", cfg);
+ dataBroker = injector.getInstance(Key.get(DataBroker.class,
+ Names.named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG)));
+ tx = dataBroker.newReadOnlyTransaction();
+ }
+
+ @TearDown(Level.Iteration)
+ public void tearDown() {
+ LOG.info("Tearing down after {} executions", counter);
+ counter = 0;
+ LOG.info("Reader invocations: {}", noopReaders);
+ noopReaders.clear();
+
+ tx.close();
+ tx = null;
+ dataBroker = null;
+ deleteFile(Paths.get(instance.peristConfigPath));
+ deleteFile(Paths.get(instance.peristContextPath));
+ }
+
+ @Benchmark
+ public void read() {
+ try {
+ tx.read(dsType, dataProvider.getId(counter++)).get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException("Read failed", e);
+ }
+ }
+
+ /**
+ * Inject custom modules e.g. configuration.
+ */
+ @Override
+ protected void configure() {
+ try {
+ instance = getHoneycombConfiguration(persistence);
+ bind(HoneycombConfiguration.class).toInstance(instance);
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to prepare configuration", e);
+ }
+
+ final Multibinder<ReaderFactory> writeBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ writeBinder.addBinding().toInstance(registry -> {
+
+ switch (data) {
+ case DataProvider.SIMPLE_CONTAINER: {
+ addReader(registry, new StaticReader<>(
+ InstanceIdentifier.create(SimpleContainer.class),
+ DataProvider.from(DataProvider.SIMPLE_CONTAINER)));
+ break;
+ }
+ case DataProvider.LIST_IN_CONTAINER: {
+ registry.addStructuralReader(
+ InstanceIdentifier.create(ContainerWithList.class), ContainerWithListBuilder.class);
+ addReader(registry, new StaticReader<>(
+ InstanceIdentifier.create(ContainerWithList.class).child(ListInContainer.class),
+ DataProvider.from(DataProvider.LIST_IN_CONTAINER)));
+ break;
+ }
+ case DataProvider.COMPLEX_LIST_IN_CONTAINER: {
+ registry.addStructuralReader(
+ InstanceIdentifier.create(ContainerWithList.class), ContainerWithListBuilder.class);
+ addReader(registry, new StaticReader<>(
+ InstanceIdentifier.create(ContainerWithList.class).child(ListInContainer.class),
+ DataProvider.from(DataProvider.COMPLEX_LIST_IN_CONTAINER)));
+ break;
+ }
+ }
+ });
+ }
+
+ private void addReader(final ModifiableReaderRegistryBuilder registry, final Reader<?, ?> handler) {
+ noopReaders.add(handler);
+ registry.add(handler);
+ }
+
+ private static HoneycombConfiguration getHoneycombConfiguration(final boolean persistence) throws IOException {
+ final HoneycombConfiguration instance = new HoneycombConfiguration();
+ instance.persistConfig = Optional.of(Boolean.toString(persistence));
+ instance.persistContext = Optional.of(Boolean.toString(persistence));
+ instance.peristConfigPath = FileManager.INSTANCE.createTempFile("config").toString();
+ instance.peristContextPath = FileManager.INSTANCE.createTempFile("context").toString();
+ return instance;
+ }
+}
diff --git a/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataProvider.java b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataProvider.java
new file mode 100644
index 0000000..7d3df26
--- /dev/null
+++ b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataProvider.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.benchmark.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.collect.Lists;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface DataProvider {
+
+ String SIMPLE_CONTAINER = "simple-container";
+ String LIST_IN_CONTAINER = "list-in-container";
+ String COMPLEX_LIST_IN_CONTAINER = "complex-list-in-container";
+
+ InstanceIdentifier<?> getId(final long counter);
+
+ DataObject getData(final long counter);
+
+ static DataProvider from(String data) {
+ return new MapBackedDataProvider(data);
+ }
+
+ final class MapBackedDataProvider implements DataProvider {
+
+ private static final Map<String, DataProvider> map;
+
+ static {
+ map = new HashMap<>();
+
+ final InstanceIdentifier<SimpleContainer> simpleContainerId = InstanceIdentifier.create(SimpleContainer.class);
+ map.put(SIMPLE_CONTAINER, new MultiValueDataProvider(Lists.newArrayList(
+ // Multiple values of container to ensure each time the value in DS after commit changes to trigger
+ // writers in test
+ new SingleValueDataProvider<>(
+ new SimpleContainerBuilder().setSimpleContainerName("first").build(), simpleContainerId),
+ new SingleValueDataProvider<>(
+ new SimpleContainerBuilder().setSimpleContainerName("second").build(), simpleContainerId),
+ new SingleValueDataProvider<>(
+ new SimpleContainerBuilder().setSimpleContainerName("third").build(), simpleContainerId))
+ ));
+ map.put(LIST_IN_CONTAINER, new MultiValueDataProvider(getListInContainerValues(100_000)));
+ map.put(COMPLEX_LIST_IN_CONTAINER,
+ new MultiValueDataProvider(getComplexListInContainerValues(100_000)));
+ }
+
+ private final DataProvider delegate;
+
+ MapBackedDataProvider(final String data) {
+ checkArgument(map.containsKey(data));
+ this.delegate = map.get(data);
+ }
+
+ @Override
+ public InstanceIdentifier<?> getId(final long counter) {
+ return delegate.getId(counter);
+ }
+
+ @Override
+ public DataObject getData(final long counter) {
+ return delegate.getData(counter);
+ }
+
+ @Override
+ public String toString() {
+ return "MapBackedDataProvider{" +
+ "delegate=" + delegate +
+ '}';
+ }
+ }
+
+
+ static List<DataProvider> getListInContainerValues(final int i) {
+ return IntStream.range(0, i)
+ .mapToObj(idx -> new SingleValueDataProvider<>(
+ new ListInContainerBuilder()
+ .setId((long) idx)
+ .build(),
+ InstanceIdentifier.create(ContainerWithList.class)
+ .child(ListInContainer.class, new ListInContainerKey((long) idx))
+ ))
+ .collect(Collectors.toList());
+ }
+
+ static List<DataProvider> getComplexListInContainerValues(final int i) {
+ return IntStream.range(0, i)
+ .mapToObj(idx -> new SingleValueDataProvider<>(
+ new ListInContainerBuilder()
+ .setId((long) idx)
+ .setContainerInList(new ContainerInListBuilder()
+ .setName("nested container")
+ .setNestedList(Lists.newArrayList(
+ getNestedList("1"),
+ getNestedList("2"),
+ getNestedList("3")))
+ .build())
+ .build(),
+ InstanceIdentifier.create(ContainerWithList.class)
+ .child(ListInContainer.class, new ListInContainerKey((long) idx))
+ ))
+ .collect(Collectors.toList());
+ }
+
+ static NestedList getNestedList(final String value) {
+ return new NestedListBuilder()
+ .setNestedId(value)
+ .setNestedName(value + "N")
+ .build();
+ }
+
+ final class SingleValueDataProvider<T extends DataObject> implements DataProvider {
+
+ private final DataObject data;
+ private final InstanceIdentifier<?> id;
+
+ SingleValueDataProvider(final T data, final InstanceIdentifier<T> id) {
+ this.data = data;
+ this.id = id;
+ }
+
+ @Override
+ public InstanceIdentifier<?> getId(final long counter) {
+ return id;
+ }
+
+ @Override
+ public DataObject getData(final long counter) {
+ return data;
+ }
+
+ @Override
+ public String toString() {
+ return "SingleValueDataProvider{" +
+ "data=" + data +
+ ", id=" + id +
+ '}';
+ }
+ }
+
+ final class MultiValueDataProvider<T extends DataObject> implements DataProvider {
+
+ private final List<DataProvider> values;
+ private int valueSize;
+
+ public MultiValueDataProvider(final List<DataProvider> values) {
+ // Wrap as array list so that index lookup is fast
+ this.values = Lists.newArrayList(values);
+ this.valueSize = values.size();
+ }
+
+ @Override
+ public InstanceIdentifier<?> getId(final long counter) {
+ return values.get((int) (counter % valueSize)).getId(counter);
+ }
+
+ @Override
+ public DataObject getData(final long counter) {
+ return values.get((int) (counter % valueSize)).getData(counter);
+ }
+
+ @Override
+ public String toString() {
+ return "MultiValueDataProvider{" +
+ "valueSize=" + valueSize +
+ '}';
+ }
+ }
+}
diff --git a/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataSubmitter.java b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataSubmitter.java
new file mode 100644
index 0000000..ebad653
--- /dev/null
+++ b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/DataSubmitter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.benchmark.util;
+
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@FunctionalInterface
+public interface DataSubmitter {
+
+ void submit(LogicalDatastoreType type, WriteTransaction tx, InstanceIdentifier<?> id, DataObject data);
+
+ public static DataSubmitter from(String operation) {
+ switch (operation) {
+ case "put": {
+ return (type, tx, id, data) -> tx.put(type, (InstanceIdentifier) id, data);
+ }
+ case "merge": {
+ return (type, tx, id, data) -> tx.merge(type, (InstanceIdentifier) id, data);
+ }
+ default: throw new UnsupportedOperationException("Operation: " + operation);
+ }
+ }
+}
diff --git a/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/FileManager.java b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/FileManager.java
new file mode 100644
index 0000000..8aa9f93
--- /dev/null
+++ b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/FileManager.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.benchmark.util;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public interface FileManager {
+
+ FileManager INSTANCE = new FileManager() {};
+
+ default Path createTempFile(String config) throws IOException {
+ return Files.createTempFile("hcbenchmark", config);
+ }
+
+ default void deleteFile(final Path toDelete) {
+ if (toDelete != null) {
+ try {
+ Files.delete(toDelete);
+ } catch (IOException e) {
+ // NOOP, dont care about temp files too much
+ }
+ }
+ }
+
+}
diff --git a/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/NoopWriter.java b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/NoopWriter.java
new file mode 100644
index 0000000..f61bd1b
--- /dev/null
+++ b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/NoopWriter.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.benchmark.util;
+
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.write.Writer;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Noop writer suitable for lists as well.
+ */
+@NotThreadSafe
+public final class NoopWriter<T extends DataObject> implements Writer<T> {
+
+ private final InstanceIdentifier<T> id;
+ private long counter = 0;
+
+ public NoopWriter(final InstanceIdentifier<T> id) {
+ this.id = id;
+ }
+
+ @Override
+ public void update(@Nonnull final InstanceIdentifier<? extends DataObject> id,
+ @Nullable final DataObject dataBefore,
+ @Nullable final DataObject dataAfter,
+ @Nonnull final WriteContext ctx) throws WriteFailedException {
+ counter++;
+ // NOOP
+ }
+
+ @Nonnull
+ @Override
+ public InstanceIdentifier<T> getManagedDataObjectType() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return "NoopWriter{" +
+ id.getTargetType().getSimpleName() +
+ ", counter=" + counter +
+ '}';
+ }
+}
diff --git a/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/StaticReader.java b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/StaticReader.java
new file mode 100644
index 0000000..90e5601
--- /dev/null
+++ b/infra/it/benchmark/src/main/java/io/fd/honeycomb/benchmark/util/StaticReader.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.honeycomb.benchmark.util;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.read.Reader;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Statically preconfigured reader.
+ */
+@NotThreadSafe
+public final class StaticReader<T extends DataObject, B extends Builder<T>> implements Reader<T, B> {
+
+ private final InstanceIdentifier<T> id;
+ private final DataProvider data;
+ private long counter = 0;
+
+ public StaticReader(final InstanceIdentifier<T> id, final DataProvider data) {
+ this.id = id;
+ this.data = data;
+ }
+
+ @Nonnull
+ @Override
+ public InstanceIdentifier<T> getManagedDataObjectType() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return "NoopReader{" +
+ id.getTargetType().getSimpleName() +
+ ", counter=" + counter +
+ '}';
+ }
+
+ @Nonnull
+ @Override
+ public Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ counter++;
+ return Optional.of(data.getData(counter));
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<T> id, @Nonnull final B builder,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ throw new UnsupportedOperationException("No read current attrs!");
+ }
+
+ @Nonnull
+ @Override
+ public B getBuilder(final InstanceIdentifier<T> id) {
+ throw new UnsupportedOperationException("No builder!");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final T readValue) {
+ throw new UnsupportedOperationException("No merge!");
+ }
+}
diff --git a/infra/it/benchmark/src/main/resources/logback.xml b/infra/it/benchmark/src/main/resources/logback.xml
new file mode 100644
index 0000000..7553003
--- /dev/null
+++ b/infra/it/benchmark/src/main/resources/logback.xml
@@ -0,0 +1,26 @@
+ <configuration scan="true">
+
+ <appender name="honeycomb.log" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${project.build.directory}/logs/honeycomb.log</file>
+
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <fileNamePattern>${project.build.directory}/logs/honeycomb.%d.log.zip</fileNamePattern>
+ <maxHistory>1</maxHistory>
+ </rollingPolicy>
+
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>1MB</maxFileSize>
+ </triggeringPolicy>
+
+ <encoder>
+ <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{35} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="warn">
+ <appender-ref ref="honeycomb.log" />
+ </root>
+
+ <logger name="org.opendaylight" level="INFO"/>
+ <logger name="io.fd" level="INFO"/>
+</configuration>
diff --git a/infra/it/pom.xml b/infra/it/pom.xml
index 5e11734..3846955 100644
--- a/infra/it/pom.xml
+++ b/infra/it/pom.xml
@@ -33,6 +33,18 @@
<module>test-model</module>
<module>it-test</module>
</modules>
+
+
+ <!-- Activate from command line with mvn <goals> -Pbenchmark -->
+ <profiles>
+ <profile>
+ <id>benchmark</id>
+ <modules>
+ <module>benchmark</module>
+ </modules>
+ </profile>
+ </profiles>
+
<!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
<build>
<plugins>