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