increase tempest timeout
[integration/test.git] / tools / mdsal_benchmark / dsbenchmark.py
index 43e3242e984471cb2e3836b2ea7bf705725bf70f..15d6607f3903b8ca99cbd1451d1bdf7bb28a3ef6 100755 (executable)
@@ -1,8 +1,4 @@
 #!/usr/bin/python
-__author__ = "Jan Medved"
-__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
-__license__ = "New-style BSD"
-__email__ = "jmedved@cisco.com"
 
 import argparse
 import requests
@@ -11,6 +7,13 @@ import csv
 import time
 import re
 
+
+__author__ = "Jan Medved"
+__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
+__license__ = "New-style BSD"
+__email__ = "jmedved@cisco.com"
+
+
 parser = argparse.ArgumentParser(description='Datastore Benchmarking'
                                              ''
                                              'See documentation @:'
@@ -33,6 +36,9 @@ parser.add_argument("--optype", choices=["PUT", "MERGE", "DELETE", "READ"], narg
                     default=["PUT", "MERGE", "DELETE", "READ"], help="list of the types operations to execute.")
 parser.add_argument("--format", choices=["BINDING-AWARE", "BINDING-INDEPENDENT"], nargs='+',
                     default=["BINDING-AWARE", "BINDING-INDEPENDENT"], help="list of data formats to execute.")
+parser.add_argument("--datastore", choices=["CONFIG", "OPERATIONAL", "BOTH"], nargs='+',
+                    default=["OPERATIONAL", "CONFIG"], help="data-store type (config/operational) to use")
+# There is also "listeners" parameter specified in the Yang file now.
 parser.add_argument("--warmup", type=int, default=10, help="number of warmup runs before official test runs")
 parser.add_argument("--runs", type=int, default=10,
                     help="number of official test runs. Note: Reported results are based on these runs.")
@@ -40,6 +46,10 @@ parser.add_argument("--plot", type=str, default='none',
                     help="keywords filter for results to be drawn in plot (special keywords: all, none).")
 parser.add_argument("--units", choices=["miliseconds", "microseconds"], default="microseconds",
                     help="units of test duration values provided by dsbenchmark controller feature")
+parser.add_argument("--outfile-struct", dest="outfilestruct", default="perf_per_struct.csv",
+                    help="units of test duration values provided by dsbenchmark controller feature")
+parser.add_argument("--outfile-ops", dest="outfileops", default="perf_per_ops.csv",
+                    help="units of test duration values provided by dsbenchmark controller feature")
 args = parser.parse_args()
 
 
@@ -58,13 +68,14 @@ def send_clear_request():
     print r.status_code
 
 
-def send_test_request(tx_type, operation, data_fmt, outer_elem, inner_elem, ops_per_tx):
+def send_test_request(tx_type, operation, data_fmt, datastore, outer_elem, inner_elem, ops_per_tx):
     """
     Sends a request to the dsbenchmark app to start a data store benchmark test run.
     The dsbenchmark app will perform the requested benchmark test and return measured
     transaction times
     :param operation: PUT, MERGE, DELETE or READ
     :param data_fmt: BINDING-AWARE or BINDING-INDEPENDENT
+    :param datastore: OPERATIONAL, CONFIG or BOTH
     :param outer_elem: Number of elements in the outer list
     :param inner_elem: Number of elements in the inner list
     :param ops_per_tx: Number of operations (PUTs, MERGEs or DELETEs) on each transaction
@@ -78,12 +89,13 @@ def send_test_request(tx_type, operation, data_fmt, outer_elem, inner_elem, ops_
             "transaction-type": "%s",
             "operation": "%s",
             "data-format": "%s",
+            "data-store": "%s",
             "outerElements": %d,
             "innerElements": %d,
             "putsPerTx": %d
         }
     }'''
-    data = test_request_template % (tx_type, operation, data_fmt, outer_elem, inner_elem, ops_per_tx)
+    data = test_request_template % (tx_type, operation, data_fmt, datastore, outer_elem, inner_elem, ops_per_tx)
     r = requests.post(url, data, headers=postheaders, stream=False, auth=('admin', 'admin'))
     result = {u'http-status': r.status_code}
     if r.status_code == 200:
@@ -107,7 +119,7 @@ def print_results(run_type, idx, res):
           (run_type, idx, res[u'status'], res[u'listBuildTime'], res[u'execTime'], res[u'txOk'], res[u'txError'])
 
 
-def run_test(warmup_runs, test_runs, tx_type, operation, data_fmt, outer_elem, inner_elem, ops_per_tx):
+def run_test(warmup_runs, test_runs, tx_type, operation, data_fmt, datastore, outer_elem, inner_elem, ops_per_tx):
     """
     Execute a benchmark test. Performs the JVM 'wamrup' before the test, runs
     the specified number of dsbenchmark test runs and computes the average time
@@ -117,6 +129,7 @@ def run_test(warmup_runs, test_runs, tx_type, operation, data_fmt, outer_elem, i
     :param test_runs: # of test runs
     :param operation: PUT, MERGE or DELETE
     :param data_fmt: BINDING-AWARE or BINDING-INDEPENDENT
+    :param datastore: OPERATIONAL, CONFIG or BOTH
     :param outer_elem: Number of elements in the outer list
     :param inner_elem: Number of elements in the inner list
     :param ops_per_tx: Number of operations (PUTs, MERGEs or DELETEs) on each transaction
@@ -125,14 +138,14 @@ def run_test(warmup_runs, test_runs, tx_type, operation, data_fmt, outer_elem, i
     total_build_time = 0.0
     total_exec_time = 0.0
 
-    print 'Tx Type: {0:s}, Operation: {1:s}, Data Format: {2:s}, Outer/Inner Elements: {3:d}/{4:d}, PutsPerTx {5:d}' \
-        .format(tx_type, operation, data_fmt, outer_elem, inner_elem, ops_per_tx)
+    print "Tx Type:", tx_type, "Operation:", operation, "Data Format:", data_fmt, "Datastore:", datastore,
+    print "Outer Elements:", outer_elem, "Inner Elements:", inner_elem, "PutsPerTx:", ops_per_tx
     for idx in range(warmup_runs):
-        res = send_test_request(tx_type, operation, data_fmt, outer_elem, inner_elem, ops_per_tx)
+        res = send_test_request(tx_type, operation, data_fmt, datastore, outer_elem, inner_elem, ops_per_tx)
         print_results('WARMUP', idx, res)
 
     for idx in range(test_runs):
-        res = send_test_request(tx_type, operation, data_fmt, outer_elem, inner_elem, ops_per_tx)
+        res = send_test_request(tx_type, operation, data_fmt, datastore, outer_elem, inner_elem, ops_per_tx)
         print_results('TEST', idx, res)
         total_build_time += res['listBuildTime']
         total_exec_time += res['execTime']
@@ -140,12 +153,14 @@ def run_test(warmup_runs, test_runs, tx_type, operation, data_fmt, outer_elem, i
     return total_build_time / test_runs, total_exec_time / test_runs
 
 
-def store_result(values, tx_type, operation, data_fmt, outer_elem, inner_elem, ops_per_tx, value_name, value):
+def store_result(values, tx_type, operation, data_fmt, datastore,
+                 outer_elem, inner_elem, ops_per_tx, value_name, value):
     """
     Stores a record to the list (dictionary) of values to be written into a csv file for plotting purposes.
     :param values: The list (dictionary) to be used for storing the result
     :param operation: PUT, MERGE or DELETE
     :param data_fmt: BINDING-AWARE or BINDING-INDEPENDENT
+    :param datastore: OPERATIONAL, CONFIG or BOTH
     :param outer_elem: Number of elements in the outer list
     :param inner_elem: Number of elements in the inner list
     :param ops_per_tx: Number of operations (PUTs, MERGEs or DELETEs) on each transaction
@@ -153,7 +168,7 @@ def store_result(values, tx_type, operation, data_fmt, outer_elem, inner_elem, o
     :param value: The (measured) value
     :return: none
     """
-    plot_key = (tx_type + '-' + data_fmt + '-' + operation + '-' + str(outer_elem) + '/' +
+    plot_key = (datastore + '-' + data_fmt + '-' + tx_type + '-' + operation + '-' + str(outer_elem) + '/' +
                 str(inner_elem) + 'OUTER/INNER-' + str(ops_per_tx) + 'OP-' + value_name)
     values[plot_key] = value
 
@@ -173,10 +188,10 @@ def write_results_to_file(values, file_name, key_filter):
     try:
         for key in sorted(values):
             if (key_filter != 'none') & ((key_filter == 'all') | (re.search(key_filter, key) is not None)):
-                first_line += key + ', '
-                second_line += str(values[key]) + ', '
-        first_line = first_line[:-2]
-        second_line = second_line[:-2]
+                first_line += key + ','
+                second_line += str(values[key]) + ','
+        first_line = first_line[:-1]
+        second_line = second_line[:-1]
         f.write(first_line + '\n')
         f.write(second_line + '\n')
     finally:
@@ -191,6 +206,7 @@ if __name__ == "__main__":
     OPS_PER_TX = args.ops
     OPERATIONS = args.optype
     DATA_FORMATS = args.format
+    DATASTORES = args.datastore
     PLOT_FILTER = args.plot
     if args.units == 'miliseconds':
         TIME_DIV = 1
@@ -234,20 +250,25 @@ if __name__ == "__main__":
                 print '---------------------------------------'
                 writer.writerow(('', ('%s:' % fmt), ''))
 
-                for oper in OPERATIONS:
-                    print 'Operation: %s' % oper
-                    writer.writerow(('', '', '%s:' % oper))
-
-                    for elem in INNER_ELEMENTS:
-                        avg_build_time, avg_exec_time = \
-                            run_test(WARMUP_RUNS, TEST_RUNS, tx_type, oper, fmt, TOTAL_ELEMENTS / elem, elem, 1)
-                        e_label = '%d/%d' % (TOTAL_ELEMENTS / elem, elem)
-                        writer.writerow(('', '', '', e_label, avg_build_time, avg_exec_time,
-                                         (avg_build_time + avg_exec_time)))
-                        store_result(PLOT1, tx_type, oper, fmt, TOTAL_ELEMENTS / elem, elem, 1,
-                                     'BUILD', avg_build_time / TIME_DIV)
-                        store_result(PLOT1, tx_type, oper, fmt, TOTAL_ELEMENTS / elem, elem, 1,
-                                     'EXEC', avg_exec_time / TIME_DIV)
+                for datastore in DATASTORES:
+                    print
+                    print 'Data store: %s' % datastore
+                    print
+
+                    for oper in OPERATIONS:
+                        print 'Operation: %s' % oper
+                        writer.writerow(('', '', '%s:' % oper))
+
+                        for elem in INNER_ELEMENTS:
+                            avg_build_time, avg_exec_time = run_test(WARMUP_RUNS, TEST_RUNS, tx_type, oper, fmt,
+                                                                     datastore, TOTAL_ELEMENTS / elem, elem, 1)
+                            e_label = '%d/%d' % (TOTAL_ELEMENTS / elem, elem)
+                            writer.writerow(('', '', '', e_label, avg_build_time, avg_exec_time,
+                                             (avg_build_time + avg_exec_time)))
+                            store_result(PLOT1, tx_type, oper, fmt, datastore, TOTAL_ELEMENTS / elem, elem, 1,
+                                         'BUILD', avg_build_time / TIME_DIV)
+                            store_result(PLOT1, tx_type, oper, fmt, datastore, TOTAL_ELEMENTS / elem, elem, 1,
+                                         'EXEC', avg_exec_time / TIME_DIV)
 
         # Determine the impact of number of writes per transaction on performance.
         # Iterate over all transaction types, data formats, operation types, and
@@ -267,22 +288,27 @@ if __name__ == "__main__":
                 print '---------------------------------------'
                 writer.writerow(('', ('%s:' % fmt), ''))
 
-                for oper in OPERATIONS:
-                    print 'Operation: %s' % oper
-                    writer.writerow(('', '', '%s:' % oper))
-
-                    for wtx in OPS_PER_TX:
-                        avg_build_time, avg_exec_time = \
-                            run_test(WARMUP_RUNS, TEST_RUNS, tx_type, oper, fmt, TOTAL_ELEMENTS, 1, wtx)
-                        writer.writerow(('', '', '', wtx, avg_build_time, avg_exec_time,
-                                         (avg_build_time + avg_exec_time)))
-                        store_result(PLOT2, tx_type, oper, fmt, TOTAL_ELEMENTS / elem, 1, wtx,
-                                     'BUILD', avg_build_time / TIME_DIV)
-                        store_result(PLOT2, tx_type, oper, fmt, TOTAL_ELEMENTS / elem, 1, wtx,
-                                     'EXEC', avg_exec_time / TIME_DIV)
-
-        write_results_to_file(PLOT1, 'perf_per_struct.csv', PLOT_FILTER)
-        write_results_to_file(PLOT2, 'perf_per_ops.csv', PLOT_FILTER)
+                for datastore in DATASTORES:
+                    print
+                    print 'Data store: %s' % datastore
+                    print
+
+                    for oper in OPERATIONS:
+                        print 'Operation: %s' % oper
+                        writer.writerow(('', '', '%s:' % oper))
+
+                        for wtx in OPS_PER_TX:
+                            avg_build_time, avg_exec_time = \
+                                run_test(WARMUP_RUNS, TEST_RUNS, tx_type, oper, fmt, datastore, TOTAL_ELEMENTS, 1, wtx)
+                            writer.writerow(('', '', '', wtx, avg_build_time, avg_exec_time,
+                                             (avg_build_time + avg_exec_time)))
+                            store_result(PLOT2, tx_type, oper, fmt, datastore, TOTAL_ELEMENTS / elem, 1, wtx,
+                                         'BUILD', avg_build_time / TIME_DIV)
+                            store_result(PLOT2, tx_type, oper, fmt, datastore, TOTAL_ELEMENTS / elem, 1, wtx,
+                                         'EXEC', avg_exec_time / TIME_DIV)
+
+        write_results_to_file(PLOT1, args.outfilestruct, PLOT_FILTER)
+        write_results_to_file(PLOT2, args.outfileops, PLOT_FILTER)
 
         end_time = time.time()
         print "End time: %f " % end_time