1"""
2Copyright 2019 Ettus Research, A National Instrument Brand
3
4SPDX-License-Identifier: GPL-3.0-or-later
5
6Helper script that parses the results of benchmark_rate and extracts numeric
7values printed at the end of execution.
8"""
9
10import collections
11import re
12import csv
13
14Results = collections.namedtuple(
15    'Results',
16    """
17    num_rx_channels
18    num_tx_channels
19    rx_rate
20    tx_rate
21    received_samps
22    dropped_samps
23    overruns
24    transmitted_samps
25    tx_seq_errs
26    rx_seq_errs
27    underruns
28    late_cmds
29    tx_timeouts
30    rx_timeouts
31    """
32)
33
34def average(results):
35    """
36    Returns the average of a list of results.
37    """
38    results_as_lists = [list(r) for r in results]
39    avg_vals = [sum(x)/len(results) for x in zip(*results_as_lists)]
40    return Results(*avg_vals)
41
42def min_vals(results):
43    """
44    Returns the minimum values of a list of results.
45    """
46    results_as_lists = [list(r) for r in results]
47    min_vals = [min(x) for x in zip(*results_as_lists)]
48    return Results(*min_vals)
49
50def max_vals(results):
51    """
52    Returns the maximum values of a list of results.
53    """
54    results_as_lists = [list(r) for r in results]
55    max_vals = [max(x) for x in zip(*results_as_lists)]
56    return Results(*max_vals)
57
58def non_zero_vals(results):
59    """
60    Returns the number of non-zero values from a list of results.
61    """
62    results_as_lists = [list(r) for r in results]
63    results_as_lists = [[1 if x > 0 else 0 for x in y] for y in results_as_lists]
64    non_zero_vals = [sum(x) for x in zip(*results_as_lists)]
65    return Results(*non_zero_vals)
66
67def parse(result_str):
68    """
69    Parses benchmark results and returns numerical values.
70    """
71    # Parse rx rate
72    rx_rate = 0.0
73    num_rx_channels = 0
74    expr = "Testing receive rate ([0-9]+\.[0-9]+) Msps on (\d+) channels"
75    match = re.search(expr, result_str)
76    if match is not None:
77        rx_rate = float(match.group(1)) * 1.0e6
78        num_rx_channels = int(match.group(2))
79
80    tx_rate = 0.0
81    num_tx_channels = 0
82    expr = "Testing transmit rate ([0-9]+\.[0-9]+) Msps on (\d+) channels"
83    match = re.search(expr, result_str)
84    if match is not None:
85        tx_rate = float(match.group(1)) * 1.0e6
86        num_tx_channels = int(match.group(2))
87
88    # Parse results
89    expr = "Benchmark rate summary:"
90    expr += r"\s*Num received samples:\s*(\d+)"
91    expr += r"\s*Num dropped samples:\s*(\d+)"
92    expr += r"\s*Num overruns detected:\s*(\d+)"
93    expr += r"\s*Num transmitted samples:\s*(\d+)"
94    expr += r"\s*Num sequence errors \(Tx\):\s*(\d+)"
95    expr += r"\s*Num sequence errors \(Rx\):\s*(\d+)"
96    expr += r"\s*Num underruns detected:\s*(\d+)"
97    expr += r"\s*Num late commands:\s*(\d+)"
98    expr += r"\s*Num timeouts \(Tx\):\s*(\d+)"
99    expr += r"\s*Num timeouts \(Rx\):\s*(\d+)"
100    match = re.search(expr, result_str)
101    if match:
102        return Results(
103            num_rx_channels   = num_rx_channels,
104            num_tx_channels   = num_tx_channels,
105            rx_rate           = rx_rate,
106            tx_rate           = tx_rate,
107            received_samps    = int(match.group(1)),
108            dropped_samps     = int(match.group(2)),
109            overruns          = int(match.group(3)),
110            transmitted_samps = int(match.group(4)),
111            tx_seq_errs       = int(match.group(5)),
112            rx_seq_errs       = int(match.group(6)),
113            underruns         = int(match.group(7)),
114            late_cmds         = int(match.group(8)),
115            tx_timeouts       = int(match.group(9)),
116            rx_timeouts       = int(match.group(10))
117        )
118    else:
119        return None
120
121def write_benchmark_rate_csv(results, file_name):
122    with open(file_name, 'w', newline='') as f:
123        w = csv.writer(f)
124        w.writerow(results[0]._fields)
125        w.writerows(results)
126
127if __name__ == "__main__":
128    result_str = """
129    [00:00:00.000376] Creating the usrp device with: addr=192.168.30.2, second_addr=192.168.40.2...
130    [00:00:05.63100253] Testing receive rate 200.000000 Msps on 2 channels
131    [00:00:05.73100253] Testing transmit rate 100.000000 Msps on 1 channels
132    [00:00:15.113339078] Benchmark complete.
133
134    Benchmark rate summary:
135    Num received samples:     10000
136    Num dropped samples:      200
137    Num overruns detected:    10
138    Num transmitted samples:  20000
139    Num sequence errors (Tx): 5
140    Num sequence errors (Rx): 6
141    Num underruns detected:   20
142    Num late commands:        2
143    Num timeouts (Tx):        0
144    Num timeouts (Rx):        100
145
146    Done!
147    """
148    print("Parsing hardcoded string for testing only")
149    print(parse(result_str))
150