HONEYCOMB-443: fix benchmark after ODL Neon bump
[honeycomb.git] / infra / it / benchmark / src / main / java / io / fd / honeycomb / benchmark / data / DataBrokerConfigWriteBenchmark.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package io.fd.honeycomb.benchmark.data;
18
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.activation.ActivationConfig;
31 import io.fd.honeycomb.infra.distro.activation.ActiveModules;
32 import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
33 import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
34 import io.fd.honeycomb.translate.write.WriterFactory;
35 import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
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.opendaylight.mdsal.binding.api.DataBroker;
45 import org.opendaylight.mdsal.binding.api.WriteTransaction;
46 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
51 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;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.openjdk.jmh.annotations.Benchmark;
54 import org.openjdk.jmh.annotations.BenchmarkMode;
55 import org.openjdk.jmh.annotations.Fork;
56 import org.openjdk.jmh.annotations.Level;
57 import org.openjdk.jmh.annotations.Measurement;
58 import org.openjdk.jmh.annotations.Mode;
59 import org.openjdk.jmh.annotations.Param;
60 import org.openjdk.jmh.annotations.Scope;
61 import org.openjdk.jmh.annotations.Setup;
62 import org.openjdk.jmh.annotations.State;
63 import org.openjdk.jmh.annotations.TearDown;
64 import org.openjdk.jmh.annotations.Timeout;
65 import org.openjdk.jmh.annotations.Warmup;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 /**
70  * Measures the performance of CONFIG writes into BA DataBroker, backed by HC infrastructure and then NOOP writers.
71  */
72 /*
73  * Timeout for one run of benchmark method
74  * */
75 @Timeout(time = 1)
76
77 /*
78 * 20 warmup iterations, each will run for 1 second. Serves to get more real-life results, as jvm has many internal
79 * optimizations that takes time to create profiles for.
80 * */
81 @Warmup(iterations = 20, time = 1)
82
83 /*
84  100 measurement iteration, each will run for 1 second.
85  It means that there will be 100 iterations, each will run tested method for 1 second and see how many iterations were
86  possible
87  */
88 @Measurement(iterations = 100, time = 1)
89
90 /*
91 * An instance will be allocated for each thread running the given test.
92 * */
93 @State(Scope.Thread)
94
95 /*
96 * Control code runs on one jvm, benchmark runs on different one to have isolation
97 * */
98 @Fork(1)
99
100 /*
101 * Measuring Maximum throughput of operations
102 * */
103 @BenchmarkMode(Mode.Throughput)
104 public class DataBrokerConfigWriteBenchmark extends AbstractModule implements FileManager {
105
106     private static final Logger LOG = LoggerFactory.getLogger(DataBrokerConfigWriteBenchmark.class);
107
108     /*
109     * This params says after how many operations should commit to data tree be executed
110     * */
111     @Param({"1", "10"/*, "100"*/})
112     private int submitFrequency;
113
114     /*
115     * Enables/disables persisting content of transaction
116     * */
117     @Param({"true", "false"})
118     private boolean persistence;
119
120     /*
121     * Crud operation used in benchmark
122     * */
123     @Param({"put"/*, "merge"*/})
124     private String operation;
125     private DataSubmitter submitter;
126
127     /*
128     * Type of data used
129     * */
130     @Param({"CONFIGURATION"})
131     private LogicalDatastoreType dsType;
132
133     /*
134     * Data sample type used
135     * */
136     @Param({DataProvider.SIMPLE_CONTAINER, DataProvider.LIST_IN_CONTAINER, DataProvider.COMPLEX_LIST_IN_CONTAINER})
137     private String data;
138     private DataProvider dataProvider;
139
140     // Infra modules to load
141     private final Module[] modules = new Module[]{
142             new io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule(),
143             new io.fd.honeycomb.infra.distro.schema.SchemaModule(),
144             new io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule(),
145             new io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule(),
146             this};
147
148     private List<NoopWriter<?>> noopWriters = new ArrayList<>();
149     private DataBroker dataBroker;
150     private long counter = 0;
151     private WriteTransaction tx;
152     private HoneycombConfiguration instance;
153
154     @Setup(Level.Iteration)
155     public void setup() {
156         LOG.info("Setting up");
157         submitter = DataSubmitter.from(operation);
158         dataProvider = DataProvider.from(data);
159         Injector injector = Guice.createInjector(modules);
160         final HoneycombConfiguration cfg = injector.getInstance(HoneycombConfiguration.class);
161         LOG.info("Configuration for Honeycomb: {}", cfg);
162         dataBroker = injector.getInstance(Key.get(DataBroker.class,
163                 Names.named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG)));
164     }
165
166     @TearDown(Level.Iteration)
167     public void tearDown() {
168         LOG.info("Tearing down after {} executions", counter);
169         counter = 0;
170         LOG.info("Writer invocations: {}", noopWriters);
171         noopWriters.clear();
172
173         tx = null;
174         dataBroker = null;
175         deleteFile(Paths.get(instance.peristConfigPath));
176         deleteFile(Paths.get(instance.peristContextPath));
177     }
178
179     @Benchmark
180     public void write() {
181         // Count executions
182         counter++;
183
184         // New transaction after it was committed
185         if (tx == null) {
186             tx = dataBroker.newWriteOnlyTransaction();
187         }
188
189         submitter.submit(dsType, tx, dataProvider.getId(counter), dataProvider.getData(counter));
190
191         // Commit based on frequency set
192         if (counter % submitFrequency == 0) {
193             try {
194                 tx.commit().get();
195             } catch (InterruptedException | ExecutionException e) {
196                 throw new RuntimeException("Submit failed", e);
197             }
198             tx = null;
199         }
200     }
201
202     /**
203      * Inject custom modules e.g. configuration.
204      */
205     @Override
206     protected void configure() {
207         try {
208             instance = getHoneycombConfiguration(persistence);
209             bind(HoneycombConfiguration.class).toInstance(instance);
210             bind(ActivationConfig.class).toInstance(getActivationConfig());
211             bind(ActiveModules.class).toInstance(
212                     new ActiveModules(Arrays.stream(modules).map(Module::getClass).collect(Collectors.toSet())));
213         } catch (IOException e) {
214             throw new RuntimeException("Unable to prepare configuration", e);
215         }
216
217         final Multibinder<WriterFactory> writeBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
218         writeBinder.addBinding().toInstance(registry -> {
219             // Add noop writers for all data written in this benchmark
220             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(SimpleContainer.class)));
221             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)));
222             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
223                     .child(ListInContainer.class)));
224             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
225                     .child(ListInContainer.class)
226                     .child(ContainerInList.class)));
227             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
228                     .child(ListInContainer.class)
229                     .child(ContainerInList.class)
230                     .child(NestedList.class)));
231         });
232     }
233
234     private void addWriter(final ModifiableWriterRegistryBuilder registry, final NoopWriter<?> handler) {
235         noopWriters.add(handler);
236         registry.add(handler);
237     }
238
239     private static HoneycombConfiguration getHoneycombConfiguration(final boolean persistence) throws IOException {
240         final HoneycombConfiguration instance = new HoneycombConfiguration();
241         instance.persistConfig = Optional.of(Boolean.toString(persistence));
242         instance.persistContext = Optional.of(Boolean.toString(persistence));
243         instance.peristConfigPath = FileManager.INSTANCE.createTempFile("config").toString();
244         instance.peristContextPath = FileManager.INSTANCE.createTempFile("context").toString();
245         return instance;
246     }
247
248     private static ActivationConfig getActivationConfig() {
249         final ActivationConfig activationConfig = new ActivationConfig();
250         activationConfig.yangModulesIndexPath = "yang-mapping";
251         return activationConfig;
252     }
253 }