6d76ad2d3eb86517054b925c82c606a47aaa0114
[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.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;
64
65 /**
66  * Measures the performance of CONFIG writes into BA DataBroker, backed by HC infrastructure and then NOOP writers.
67  */
68 @Timeout(time = 20)
69 @Warmup(iterations = 2, time = 10)
70 @Measurement(iterations = 2, time = 10)
71 @Fork(2)
72 @State(Scope.Thread)
73 @BenchmarkMode(Mode.Throughput)
74 public class DataBrokerConfigWriteBenchmark extends AbstractModule implements FileManager {
75
76     private static final Logger LOG = LoggerFactory.getLogger(DataBrokerConfigWriteBenchmark.class);
77
78     @Param({"1", "10"/*, "100"*/})
79     private int submitFrequency;
80
81     @Param({"true", "false"})
82     private boolean persistence;
83
84     @Param({"put"/*, "merge"*/})
85     private String operation;
86     private DataSubmitter submitter;
87
88     @Param({"CONFIGURATION"})
89     private LogicalDatastoreType dsType;
90
91     @Param({DataProvider.SIMPLE_CONTAINER, DataProvider.LIST_IN_CONTAINER , DataProvider.COMPLEX_LIST_IN_CONTAINER})
92     private String data;
93     private DataProvider dataProvider;
94
95     // Infra modules to load
96     private final Module[] modules = new Module[] {
97             new io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule(),
98             new io.fd.honeycomb.infra.distro.schema.SchemaModule(),
99             new io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule(),
100             new io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule(),
101             this};
102
103     private List<NoopWriter<?>> noopWriters = new ArrayList<>();
104     private DataBroker dataBroker;
105     private long counter = 0;
106     private WriteTransaction tx;
107     private HoneycombConfiguration instance;
108
109     @Setup(Level.Iteration)
110     public void setup() {
111         LOG.info("Setting up");
112         submitter = DataSubmitter.from(operation);
113         dataProvider = DataProvider.from(data);
114         Injector injector = Guice.createInjector(modules);
115         final HoneycombConfiguration cfg = injector.getInstance(HoneycombConfiguration.class);
116         LOG.info("Configuration for Honeycomb: {}", cfg);
117         dataBroker = injector.getInstance(Key.get(DataBroker.class,
118                 Names.named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG)));
119     }
120
121     @TearDown(Level.Iteration)
122     public void tearDown() {
123         LOG.info("Tearing down after {} executions", counter);
124         counter = 0;
125         LOG.info("Writer invocations: {}", noopWriters);
126         noopWriters.clear();
127
128         tx = null;
129         dataBroker = null;
130         deleteFile(Paths.get(instance.peristConfigPath));
131         deleteFile(Paths.get(instance.peristContextPath));
132     }
133
134     @Benchmark
135     public void write() {
136         // Count executions
137         counter++;
138
139         // New transaction after it was committed
140         if (tx == null) {
141             tx = dataBroker.newWriteOnlyTransaction();
142         }
143
144         submitter.submit(dsType, tx, dataProvider.getId(counter), dataProvider.getData(counter));
145
146         // Commit based on frequency set
147         if (counter % submitFrequency == 0) {
148             try {
149                 tx.submit().get();
150             } catch (InterruptedException | ExecutionException e) {
151                 throw new RuntimeException("Submit failed", e);
152             }
153             tx = null;
154         }
155     }
156
157     /**
158      * Inject custom modules e.g. configuration.
159      */
160     @Override
161     protected void configure() {
162         try {
163             instance = getHoneycombConfiguration(persistence);
164             bind(HoneycombConfiguration.class).toInstance(instance);
165         } catch (IOException e) {
166             throw new RuntimeException("Unable to prepare configuration", e);
167         }
168
169         final Multibinder<WriterFactory> writeBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
170         writeBinder.addBinding().toInstance(registry -> {
171             // Add noop writers for all data written in this benchmark
172             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(SimpleContainer.class)));
173             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)));
174             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
175                     .child(ListInContainer.class)));
176             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
177                     .child(ListInContainer.class)
178                     .child(ContainerInList.class)));
179             addWriter(registry, new NoopWriter<>(InstanceIdentifier.create(ContainerWithList.class)
180                     .child(ListInContainer.class)
181                     .child(ContainerInList.class)
182                     .child(NestedList.class)));
183         });
184     }
185
186     private void addWriter(final ModifiableWriterRegistryBuilder registry, final NoopWriter<?> handler) {
187         noopWriters.add(handler);
188         registry.add(handler);
189     }
190
191     private static HoneycombConfiguration getHoneycombConfiguration(final boolean persistence) throws IOException {
192         final HoneycombConfiguration instance = new HoneycombConfiguration();
193         instance.persistConfig = Optional.of(Boolean.toString(persistence));
194         instance.persistContext = Optional.of(Boolean.toString(persistence));
195         instance.peristConfigPath = FileManager.INSTANCE.createTempFile("config").toString();
196         instance.peristContextPath = FileManager.INSTANCE.createTempFile("context").toString();
197         return instance;
198     }
199 }