HONEYCOMB-288: JMH's CSV postprocessing to format accepted by Jenkin's plot plugin
[honeycomb.git] / infra / it / benchmark / src / main / java / io / fd / honeycomb / benchmark / data / DataBrokerOperReadBenchmark.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.FileManager;
28 import io.fd.honeycomb.benchmark.util.StaticReader;
29 import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
30 import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
31 import io.fd.honeycomb.translate.read.Reader;
32 import io.fd.honeycomb.translate.read.ReaderFactory;
33 import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
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.ReadOnlyTransaction;
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.ContainerWithListBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.openjdk.jmh.annotations.Benchmark;
49 import org.openjdk.jmh.annotations.BenchmarkMode;
50 import org.openjdk.jmh.annotations.Fork;
51 import org.openjdk.jmh.annotations.Level;
52 import org.openjdk.jmh.annotations.Measurement;
53 import org.openjdk.jmh.annotations.Mode;
54 import org.openjdk.jmh.annotations.Param;
55 import org.openjdk.jmh.annotations.Scope;
56 import org.openjdk.jmh.annotations.Setup;
57 import org.openjdk.jmh.annotations.State;
58 import org.openjdk.jmh.annotations.TearDown;
59 import org.openjdk.jmh.annotations.Timeout;
60 import org.openjdk.jmh.annotations.Warmup;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 /**
65  * Measures the performance of CONFIG writes into BA DataBroker, backed by HC infrastructure and then NOOP writers.
66  */
67 @Timeout(time = 20)
68 @Warmup(iterations = 2, time = 10)
69 @Measurement(iterations = 2, time = 10)
70 @Fork(2)
71 @State(Scope.Thread)
72 @BenchmarkMode(Mode.Throughput)
73 public class DataBrokerOperReadBenchmark extends AbstractModule implements FileManager {
74
75     private static final Logger LOG = LoggerFactory.getLogger(DataBrokerOperReadBenchmark.class);
76
77     @Param({"OPERATIONAL"})
78     private LogicalDatastoreType dsType;
79
80     // Persistence does not make a difference when only reading operational
81     @Param({"false"})
82     private boolean persistence;
83
84     @Param({DataProvider.SIMPLE_CONTAINER, DataProvider.LIST_IN_CONTAINER, DataProvider.COMPLEX_LIST_IN_CONTAINER})
85     private String data;
86     private DataProvider dataProvider;
87
88     // Infra modules to load
89     private final Module[] modules = new Module[] {
90             new io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule(),
91             new io.fd.honeycomb.infra.distro.schema.SchemaModule(),
92             new ConfigAndOperationalPipelineModule(),
93             new io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule(),
94             this};
95
96     private List<Reader<?, ?>> noopReaders = new ArrayList<>();
97     private DataBroker dataBroker;
98     private long counter = 0;
99     private ReadOnlyTransaction tx;
100     private HoneycombConfiguration instance;
101
102     @Setup(Level.Iteration)
103     public void setup() {
104         LOG.info("Setting up");
105         dataProvider = DataProvider.from(data);
106         Injector injector = Guice.createInjector(modules);
107         final HoneycombConfiguration cfg = injector.getInstance(HoneycombConfiguration.class);
108         LOG.info("Configuration for Honeycomb: {}", cfg);
109         dataBroker = injector.getInstance(Key.get(DataBroker.class,
110                 Names.named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG)));
111         tx = dataBroker.newReadOnlyTransaction();
112     }
113
114     @TearDown(Level.Iteration)
115     public void tearDown() {
116         LOG.info("Tearing down after {} executions", counter);
117         counter = 0;
118         LOG.info("Reader invocations: {}", noopReaders);
119         noopReaders.clear();
120
121         tx.close();
122         tx = null;
123         dataBroker = null;
124         deleteFile(Paths.get(instance.peristConfigPath));
125         deleteFile(Paths.get(instance.peristContextPath));
126     }
127
128     @Benchmark
129     public void read() {
130         try {
131             tx.read(dsType, dataProvider.getId(counter++)).get();
132         } catch (InterruptedException | ExecutionException e) {
133             throw new RuntimeException("Read failed", e);
134         }
135     }
136
137     /**
138      * Inject custom modules e.g. configuration.
139      */
140     @Override
141     protected void configure() {
142         try {
143             instance = getHoneycombConfiguration(persistence);
144             bind(HoneycombConfiguration.class).toInstance(instance);
145         } catch (IOException e) {
146             throw new RuntimeException("Unable to prepare configuration", e);
147         }
148
149         final Multibinder<ReaderFactory> writeBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
150         writeBinder.addBinding().toInstance(registry -> {
151
152             switch (data) {
153                 case DataProvider.SIMPLE_CONTAINER: {
154                     addReader(registry, new StaticReader<>(
155                             InstanceIdentifier.create(SimpleContainer.class),
156                             DataProvider.from(DataProvider.SIMPLE_CONTAINER)));
157                     break;
158                 }
159                 case DataProvider.LIST_IN_CONTAINER: {
160                     registry.addStructuralReader(
161                             InstanceIdentifier.create(ContainerWithList.class), ContainerWithListBuilder.class);
162                     addReader(registry, new StaticReader<>(
163                             InstanceIdentifier.create(ContainerWithList.class).child(ListInContainer.class),
164                             DataProvider.from(DataProvider.LIST_IN_CONTAINER)));
165                     break;
166                 }
167                 case DataProvider.COMPLEX_LIST_IN_CONTAINER: {
168                     registry.addStructuralReader(
169                             InstanceIdentifier.create(ContainerWithList.class), ContainerWithListBuilder.class);
170                     addReader(registry, new StaticReader<>(
171                             InstanceIdentifier.create(ContainerWithList.class).child(ListInContainer.class),
172                             DataProvider.from(DataProvider.COMPLEX_LIST_IN_CONTAINER)));
173                     break;
174                 }
175             }
176         });
177     }
178
179     private void addReader(final ModifiableReaderRegistryBuilder registry, final Reader<?, ?> handler) {
180         noopReaders.add(handler);
181         registry.add(handler);
182     }
183
184     private static HoneycombConfiguration getHoneycombConfiguration(final boolean persistence) throws IOException {
185         final HoneycombConfiguration instance = new HoneycombConfiguration();
186         instance.persistConfig = Optional.of(Boolean.toString(persistence));
187         instance.persistContext = Optional.of(Boolean.toString(persistence));
188         instance.peristConfigPath = FileManager.INSTANCE.createTempFile("config").toString();
189         instance.peristContextPath = FileManager.INSTANCE.createTempFile("context").toString();
190         return instance;
191     }
192 }