Merge " Expose more information about a Shard via JMX"
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / test / java / org / opendaylight / controller / md / sal / dom / broker / impl / DOMBrokerPerformanceTest.java
1 package org.opendaylight.controller.md.sal.dom.broker.impl;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertTrue;
5 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
6 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
7
8 import java.util.ArrayList;
9 import java.util.List;
10 import java.util.concurrent.Callable;
11 import java.util.concurrent.Executors;
12
13 import org.junit.Before;
14 import org.junit.Test;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
17 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
18 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
19 import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
20 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
23 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 import com.google.common.base.Optional;
29 import com.google.common.collect.ImmutableMap;
30 import com.google.common.util.concurrent.Futures;
31 import com.google.common.util.concurrent.ListenableFuture;
32 import com.google.common.util.concurrent.ListeningExecutorService;
33 import com.google.common.util.concurrent.MoreExecutors;
34
35 public class DOMBrokerPerformanceTest {
36
37     private static final Logger log = LoggerFactory.getLogger(DOMBrokerPerformanceTest.class);
38
39     private static NormalizedNode<?, ?> outerList(final int i) {
40         return ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i);
41     }
42
43     private static YangInstanceIdentifier outerListPath(final int i) {
44         return YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)//
45                 .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i) //
46                 .build();
47     }
48
49     private SchemaContext schemaContext;
50     private DOMDataBrokerImpl domBroker;
51
52     private static <V> V measure(final String name, final Callable<V> callable) throws Exception {
53         // TODO Auto-generated method stub
54         log.debug("Measurement:{} Start", name);
55         long startNano = System.nanoTime();
56         try {
57             return callable.call();
58         } finally {
59             long endNano = System.nanoTime();
60             log.info("Measurement:\"{}\" Time:{} ms", name, (endNano - startNano) / 1000000.0d);
61         }
62     }
63
64     @Before
65     public void setupStore() {
66         InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
67                  MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor());
68         InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
69                  MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor());
70         schemaContext = TestModel.createTestContext();
71
72         operStore.onGlobalContextUpdated(schemaContext);
73         configStore.onGlobalContextUpdated(schemaContext);
74
75         ImmutableMap<LogicalDatastoreType, DOMStore> stores = ImmutableMap.<LogicalDatastoreType, DOMStore> builder() //
76                 .put(CONFIGURATION, configStore) //
77                 .put(OPERATIONAL, operStore) //
78                 .build();
79         ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
80         domBroker = new DOMDataBrokerImpl(stores, executor);
81     }
82
83     @Test
84     public void testPerformance() throws Exception {
85         measure("Test Suite (all tests)", new Callable<Void>() {
86
87             @Override
88             public Void call() throws Exception {
89                 smallTestSuite(10, 1000);
90                 //smallTestSuite(10, 100);
91                 smallTestSuite(100, 100);
92                 //smallTestSuite(100, 100);
93                 //smallTestSuite(1000, 10);
94                 smallTestSuite(1000, 10);
95                 //smallTestSuite(1000, 1000);
96                 return null;
97             }
98         });
99     }
100
101     private void smallTestSuite(final int txNum, final int innerListWriteNum) throws Exception {
102         measure("TestSuite (Txs:" + txNum + " innerWrites:" + innerListWriteNum + ")", new Callable<Void>() {
103
104             @Override
105             public Void call() throws Exception {
106                 measureOneTransactionTopContainer();
107                 measureSeparateWritesOneLevel(txNum, innerListWriteNum);
108                 return null;
109             }
110         });
111     }
112
113     private void measureSeparateWritesOneLevel(final int txNum, final int innerNum) throws Exception {
114         final List<DOMDataReadWriteTransaction> transactions = measure("Txs:"+ txNum + " Allocate",
115                 new Callable<List<DOMDataReadWriteTransaction>>() {
116                     @Override
117                     public List<DOMDataReadWriteTransaction> call() throws Exception {
118                         List<DOMDataReadWriteTransaction> builder = new ArrayList<>(txNum);
119                         for (int i = 0; i < txNum; i++) {
120                             DOMDataReadWriteTransaction writeTx = domBroker.newReadWriteTransaction();
121                             builder.add(writeTx);
122                         }
123                         return builder;
124                     }
125                 });
126         assertEquals(txNum, transactions.size());
127         measure("Txs:"+ txNum + " Writes:1", new Callable<Void>() {
128             @Override
129             public Void call() throws Exception {
130                 int i = 0;
131                 for (DOMDataReadWriteTransaction writeTx :transactions) {
132                     // Writes /test/outer-list/i in writeTx
133                     writeTx.put(OPERATIONAL, outerListPath(i), outerList(i));
134                     i++;
135                 }
136                 return null;
137             }
138         });
139
140         measure("Txs:"+ txNum +  " Writes:" + innerNum, new Callable<Void>() {
141             @Override
142             public Void call() throws Exception {
143                 int i = 0;
144                 for (DOMDataReadWriteTransaction writeTx :transactions) {
145                     // Writes /test/outer-list/i in writeTx
146                     YangInstanceIdentifier path = YangInstanceIdentifier.builder(outerListPath(i))
147                             .node(TestModel.INNER_LIST_QNAME).build();
148                     writeTx.put(OPERATIONAL, path, ImmutableNodes.mapNodeBuilder(TestModel.INNER_LIST_QNAME).build());
149                     for (int j = 0; j < innerNum; j++) {
150                         YangInstanceIdentifier innerPath = YangInstanceIdentifier.builder(path)
151                                 .nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, String.valueOf(j))
152                                 .build();
153                         writeTx.put(
154                                 OPERATIONAL,
155                                 innerPath,
156                                 ImmutableNodes.mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME,
157                                         String.valueOf(j)));
158                     }
159                     i++;
160                 }
161                 return null;
162             }
163         });
164
165         measure("Txs:" + txNum + " Submit, Finish", new Callable<Void>() {
166             @Override
167             public Void call() throws Exception {
168                 List<ListenableFuture<?>> allFutures = measure(txNum + " Submits",
169                         new Callable<List<ListenableFuture<?>>>() {
170                             @Override
171                             public List<ListenableFuture<?>> call() throws Exception {
172                                 List<ListenableFuture<?>> builder = new ArrayList<>(txNum);
173                                 for (DOMDataReadWriteTransaction tx :transactions) {
174                                     builder.add(tx.submit());
175                                 }
176                                 return builder;
177                             }
178                         });
179                 Futures.allAsList(allFutures).get();
180                 return null;
181             }
182         });
183
184         final DOMDataReadTransaction readTx = measure("Txs:1 (ro), Allocate", new Callable<DOMDataReadTransaction>() {
185             @Override
186             public DOMDataReadTransaction call() throws Exception {
187                 return domBroker.newReadOnlyTransaction();
188
189             }
190         });
191
192
193         measure("Txs:1 (ro) Reads:" + txNum + " (1-level)" , new Callable<Void>() {
194             @Override
195             public Void call() throws Exception {
196                 for (int i = 0; i < txNum; i++) {
197                     ListenableFuture<Optional<NormalizedNode<?, ?>>> potential = readTx.read(OPERATIONAL,
198                             outerListPath(i));
199                     assertTrue("outerList/" + i, potential.get().isPresent());
200                 }
201                 return null;
202             }
203         });
204
205         measure("Txs:1 (ro) Reads:" + txNum * innerNum + " (2-level)", new Callable<Void>() {
206             @Override
207             public Void call() throws Exception {
208                 for (int i = 0; i < txNum; i++) {
209                     for (int j = 0; j < innerNum; j++) {
210                         YangInstanceIdentifier path = YangInstanceIdentifier
211                                 .builder(outerListPath(i))
212                                 //
213                                 .node(TestModel.INNER_LIST_QNAME)
214                                 .nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, String.valueOf(j))
215                                 .build();
216                         ListenableFuture<Optional<NormalizedNode<?, ?>>> potential = readTx.read(OPERATIONAL, path);
217                         assertTrue("outer-list/" + i + "/inner-list/" + j, potential.get().isPresent());
218                     }
219                 }
220                 return null;
221             }
222         });
223     }
224
225     private void measureOneTransactionTopContainer() throws Exception {
226
227         final DOMDataReadWriteTransaction writeTx = measure("Txs:1 Allocate", new Callable<DOMDataReadWriteTransaction>() {
228             @Override
229             public DOMDataReadWriteTransaction call() throws Exception {
230                 return domBroker.newReadWriteTransaction();
231             }
232         });
233
234         measure("Txs:1 Write", new Callable<Void>() {
235             @Override
236             public Void call() throws Exception {
237                 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
238                 writeTx.put(OPERATIONAL, TestModel.OUTER_LIST_PATH,
239                         ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
240                 return null;
241             }
242         });
243
244         measure("Txs:1 Reads:1", new Callable<Void>() {
245             @Override
246             public Void call() throws Exception {
247                 // Reads /test in writeTx
248                 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(OPERATIONAL,
249                         TestModel.TEST_PATH);
250                 assertTrue(writeTxContainer.get().isPresent());
251                 return null;
252             }
253         });
254
255         measure("Txs:1 Reads:1", new Callable<Void>() {
256             @Override
257             public Void call() throws Exception {
258                 // Reads /test in writeTx
259                 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(OPERATIONAL,
260                         TestModel.TEST_PATH);
261                 assertTrue(writeTxContainer.get().isPresent());
262                 return null;
263             }
264         });
265
266         measure("Txs:1 Submit, Finish", new Callable<Void>() {
267             @Override
268             public Void call() throws Exception {
269                 measure("Txs:1 Submit", new Callable<ListenableFuture<?>>() {
270                     @Override
271                     public ListenableFuture<?> call() throws Exception {
272                         return writeTx.submit();
273                     }
274                 }).get();
275                 return null;
276             }
277         });
278     }
279 }