2 * Copyright (c) 2016 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package io.fd.honeycomb.benchmark.data;
19 import com.google.inject.AbstractModule;
20 import com.google.inject.Guice;
21 import com.google.inject.Injector;
22 import com.google.inject.Key;
23 import com.google.inject.Module;
24 import com.google.inject.multibindings.Multibinder;
25 import com.google.inject.name.Names;
26 import io.fd.honeycomb.benchmark.util.DataProvider;
27 import io.fd.honeycomb.benchmark.util.FileManager;
28 import io.fd.honeycomb.benchmark.util.StaticReader;
29 import io.fd.honeycomb.infra.distro.activation.ActivationConfig;
30 import io.fd.honeycomb.infra.distro.activation.ActiveModules;
31 import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
32 import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
33 import io.fd.honeycomb.translate.read.Reader;
34 import io.fd.honeycomb.translate.read.ReaderFactory;
35 import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
36 import java.io.IOException;
37 import java.nio.file.Paths;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.Optional;
42 import java.util.concurrent.ExecutionException;
43 import java.util.stream.Collectors;
44 import org.eclipse.jdt.annotation.NonNull;
45 import org.opendaylight.mdsal.binding.api.DataBroker;
46 import org.opendaylight.mdsal.binding.api.ReadTransaction;
47 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.openjdk.jmh.annotations.*;
54 import org.openjdk.jmh.annotations.Scope;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
59 * Measures the performance of CONFIG writes into BA DataBroker, backed by HC infrastructure and then NOOP writers.
62 * Timeout for one run of benchmark method
67 * 20 warmup iterations, each will run for 1 second. Serves to get more real-life results, as jvm has many internal
68 * optimizations that takes time to create profiles for.
70 @Warmup(iterations = 20, time = 1)
73 100 measurement iteration, each will run for 1 second.
74 It means that there will be 100 iterations, each will run tested method for 1 second and see how many iterations were
77 @Measurement(iterations = 100, time = 1)
80 * An instance will be allocated for each thread running the given test.
85 * Control code runs on one jvm, benchmark runs on different one to have isolation
90 * Measuring Maximum throughput of operations
92 @BenchmarkMode(Mode.Throughput)
93 public class DataBrokerOperReadBenchmark extends AbstractModule implements FileManager {
95 private static final Logger LOG = LoggerFactory.getLogger(DataBrokerOperReadBenchmark.class);
98 * Type of data used in benchmark
100 @Param({"OPERATIONAL"})
101 private LogicalDatastoreType dsType;
103 // Persistence does not make a difference when only reading operational
105 private boolean persistence;
108 * Data sample type used
110 @Param({DataProvider.SIMPLE_CONTAINER, DataProvider.LIST_IN_CONTAINER, DataProvider.COMPLEX_LIST_IN_CONTAINER})
112 private DataProvider dataProvider;
114 // Infra modules to load
115 private final Module[] modules = new Module[]{
116 new io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule(),
117 new io.fd.honeycomb.infra.distro.schema.SchemaModule(),
118 new ConfigAndOperationalPipelineModule(),
119 new io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule(),
122 private List<Reader<?, ?>> noopReaders = new ArrayList<>();
123 private DataBroker dataBroker;
124 private long counter = 0;
125 private @NonNull ReadTransaction tx;
126 private HoneycombConfiguration instance;
128 @Setup(Level.Iteration)
129 public void setup() {
130 LOG.info("Setting up");
131 dataProvider = DataProvider.from(data);
132 Injector injector = Guice.createInjector(modules);
133 final HoneycombConfiguration cfg = injector.getInstance(HoneycombConfiguration.class);
134 LOG.info("Configuration for Honeycomb: {}", cfg);
135 dataBroker = injector.getInstance(Key.get(DataBroker.class,
136 Names.named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG)));
137 tx = dataBroker.newReadOnlyTransaction();
140 @TearDown(Level.Iteration)
141 public void tearDown() {
142 LOG.info("Tearing down after {} executions", counter);
144 LOG.info("Reader invocations: {}", noopReaders);
150 deleteFile(Paths.get(instance.peristConfigPath));
151 deleteFile(Paths.get(instance.peristContextPath));
157 tx.read(dsType, dataProvider.getId(counter++)).get();
158 } catch (InterruptedException | ExecutionException e) {
159 throw new RuntimeException("Read failed", e);
164 * Inject custom modules e.g. configuration.
167 protected void configure() {
169 instance = getHoneycombConfiguration(persistence);
170 bind(HoneycombConfiguration.class).toInstance(instance);
171 bind(ActivationConfig.class).toInstance(getActivationConfig());
172 bind(ActiveModules.class).toInstance(
173 new ActiveModules(Arrays.stream(modules).map(Module::getClass).collect(Collectors.toSet())));
174 } catch (IOException e) {
175 throw new RuntimeException("Unable to prepare configuration", e);
178 final Multibinder<ReaderFactory> writeBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
179 writeBinder.addBinding().toInstance(registry -> {
182 case DataProvider.SIMPLE_CONTAINER: {
183 addReader(registry, new StaticReader<>(
184 InstanceIdentifier.create(SimpleContainer.class),
185 DataProvider.from(DataProvider.SIMPLE_CONTAINER)));
188 case DataProvider.LIST_IN_CONTAINER: {
189 registry.addStructuralReader(
190 InstanceIdentifier.create(ContainerWithList.class), ContainerWithListBuilder.class);
191 addReader(registry, new StaticReader<>(
192 InstanceIdentifier.create(ContainerWithList.class).child(ListInContainer.class),
193 DataProvider.from(DataProvider.LIST_IN_CONTAINER)));
196 case DataProvider.COMPLEX_LIST_IN_CONTAINER: {
197 registry.addStructuralReader(
198 InstanceIdentifier.create(ContainerWithList.class), ContainerWithListBuilder.class);
199 addReader(registry, new StaticReader<>(
200 InstanceIdentifier.create(ContainerWithList.class).child(ListInContainer.class),
201 DataProvider.from(DataProvider.COMPLEX_LIST_IN_CONTAINER)));
208 private void addReader(final ModifiableReaderRegistryBuilder registry, final Reader<?, ?> handler) {
209 noopReaders.add(handler);
210 registry.add(handler);
213 private static HoneycombConfiguration getHoneycombConfiguration(final boolean persistence) throws IOException {
214 final HoneycombConfiguration instance = new HoneycombConfiguration();
215 instance.persistConfig = Optional.of(Boolean.toString(persistence));
216 instance.persistContext = Optional.of(Boolean.toString(persistence));
217 instance.peristConfigPath = FileManager.INSTANCE.createTempFile("config").toString();
218 instance.peristContextPath = FileManager.INSTANCE.createTempFile("context").toString();
222 private static ActivationConfig getActivationConfig() {
223 final ActivationConfig activationConfig = new ActivationConfig();
224 activationConfig.yangModulesIndexPath = "yang-mapping";
225 return activationConfig;