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.DataSubmitter;
28 import io.fd.honeycomb.benchmark.util.FileManager;
29 import io.fd.honeycomb.benchmark.util.NoopWriter;
30 import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
31 import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
32 import io.fd.honeycomb.translate.write.WriterFactory;
33 import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
34 import java.io.IOException;
35 import java.nio.file.Paths;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.Optional;
39 import java.util.concurrent.ExecutionException;
40 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
41 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
42 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
47 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;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.openjdk.jmh.annotations.Benchmark;
50 import org.openjdk.jmh.annotations.BenchmarkMode;
51 import org.openjdk.jmh.annotations.Fork;
52 import org.openjdk.jmh.annotations.Level;
53 import org.openjdk.jmh.annotations.Measurement;
54 import org.openjdk.jmh.annotations.Mode;
55 import org.openjdk.jmh.annotations.Param;
56 import org.openjdk.jmh.annotations.Scope;
57 import org.openjdk.jmh.annotations.Setup;
58 import org.openjdk.jmh.annotations.State;
59 import org.openjdk.jmh.annotations.TearDown;
60 import org.openjdk.jmh.annotations.Timeout;
61 import org.openjdk.jmh.annotations.Warmup;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
66 * Measures the performance of CONFIG writes into BA DataBroker, backed by HC infrastructure and then NOOP writers.
69 @Warmup(iterations = 2, time = 10)
70 @Measurement(iterations = 2, time = 10)
73 @BenchmarkMode(Mode.Throughput)
74 public class DataBrokerConfigWriteBenchmark extends AbstractModule implements FileManager {
76 private static final Logger LOG = LoggerFactory.getLogger(DataBrokerConfigWriteBenchmark.class);
78 @Param({"1", "10"/*, "100"*/})
79 private int submitFrequency;
81 @Param({"true", "false"})
82 private boolean persistence;
84 @Param({"put"/*, "merge"*/})
85 private String operation;
86 private DataSubmitter submitter;
88 @Param({"CONFIGURATION"})
89 private LogicalDatastoreType dsType;
91 @Param({DataProvider.SIMPLE_CONTAINER, DataProvider.LIST_IN_CONTAINER , DataProvider.COMPLEX_LIST_IN_CONTAINER})
93 private DataProvider dataProvider;
96 * TODO HONEYCOMB-288 Visualization notes:
97 * - visualize as 3 graphs, 1 for each data
98 * - each graph should show 4 lines. for the combinations of parameters: submitFrequency and persistence
99 * (if that's too much split or reduce submitFrequecy values that are shown in graph)
101 * TODO data need to be prepared for such visualization. Maybe if each benchmark class exposed a method to prepare
102 * that data from aggregated results... it might be easy
103 * (just maven exec plugin + main that invokes some method on all benchmark classes)
106 // Infra modules to load
107 private final Module[] modules = new Module[] {
108 new io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule(),
109 new io.fd.honeycomb.infra.distro.schema.SchemaModule(),
110 new io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule(),
111 new io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule(),
114 private List<NoopWriter<?>> noopWriters = new ArrayList<>();
115 private DataBroker dataBroker;
116 private long counter = 0;
117 private WriteTransaction tx;
118 private HoneycombConfiguration instance;
120 @Setup(Level.Iteration)
121 public void setup() {
122 LOG.info("Setting up");
123 submitter = DataSubmitter.from(operation);
124 dataProvider = DataProvider.from(data);
125 Injector injector = Guice.createInjector(modules);
126 final HoneycombConfiguration cfg = injector.getInstance(HoneycombConfiguration.class);
127 LOG.info("Configuration for Honeycomb: {}", cfg);
128 dataBroker = injector.getInstance(Key.get(DataBroker.class,
129 Names.named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG)));
132 @TearDown(Level.Iteration)
133 public void tearDown() {
134 LOG.info("Tearing down after {} executions", counter);
136 LOG.info("Writer invocations: {}", noopWriters);
141 deleteFile(Paths.get(instance.peristConfigPath));
142 deleteFile(Paths.get(instance.peristContextPath));
146 public void write() {
150 // New transaction after it was committed
152 tx = dataBroker.newWriteOnlyTransaction();
155 submitter.submit(dsType, tx, dataProvider.getId(counter), dataProvider.getData(counter));
157 // Commit based on frequency set
158 if (counter % submitFrequency == 0) {
161 } catch (InterruptedException | ExecutionException e) {
162 throw new RuntimeException("Submit failed", e);
169 * Inject custom modules e.g. configuration.
172 protected void configure() {
174 instance = getHoneycombConfiguration(persistence);
175 bind(HoneycombConfiguration.class).toInstance(instance);
176 } catch (IOException e) {
177 throw new RuntimeException("Unable to prepare configuration", e);
180 final Multibinder<WriterFactory> writeBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
181 writeBinder.addBinding().toInstance(registry -> {
182 // Add noop writers for all data written in this benchmark
183 addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(SimpleContainer.class)));
184 addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)));
185 addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
186 .child(ListInContainer.class)));
187 addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
188 .child(ListInContainer.class)
189 .child(ContainerInList.class)));
190 addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
191 .child(ListInContainer.class)
192 .child(ContainerInList.class)
193 .child(NestedList.class)));
197 private void addWriter(final ModifiableWriterRegistryBuilder registry, final NoopWriter<?> handler) {
198 noopWriters.add(handler);
199 registry.add(handler);
202 private static HoneycombConfiguration getHoneycombConfiguration(final boolean persistence) throws IOException {
203 final HoneycombConfiguration instance = new HoneycombConfiguration();
204 instance.persistConfig = Optional.of(Boolean.toString(persistence));
205 instance.persistContext = Optional.of(Boolean.toString(persistence));
206 instance.peristConfigPath = FileManager.INSTANCE.createTempFile("config").toString();
207 instance.peristContextPath = FileManager.INSTANCE.createTempFile("context").toString();