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