| #!/usr/bin/env python |
| # SPDX-License-Identifier: BSD-3-Clause |
| |
| # Copyright (c) 2015 Google, Inc. |
| # Copyright (c) 2015 Linaro, Ltd. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # 1. Redistributions of source code must retain the above copyright notice, |
| # this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # 3. Neither the name of the copyright holder nor the names of its |
| # contributors may be used to endorse or promote products derived from this |
| # software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| from __future__ import print_function |
| import csv |
| import datetime |
| import sys |
| import time |
| |
| dict = {'ping': '2', 'transfer': '3', 'sink': '4'} |
| verbose = 1 |
| |
| def abort(): |
| sys.exit(1) |
| |
| def usage(): |
| print('Usage: looptest TEST SIZE ITERATIONS PATH\n\n' |
| ' Run TEST for a number of ITERATIONS with operation data SIZE bytes\n' |
| ' TEST may be \'ping\' \'transfer\' or \'sink\'\n' |
| ' SIZE indicates the size of transfer <= greybus max payload bytes\n' |
| ' ITERATIONS indicates the number of times to execute TEST at SIZE bytes\n' |
| ' Note if ITERATIONS is set to zero then this utility will\n' |
| ' initiate an infinite (non terminating) test and exit\n' |
| ' without logging any metrics data\n' |
| ' PATH indicates the sysfs path for the loopback greybus entries e.g.\n' |
| ' /sys/bus/greybus/devices/endo0:1:1:1:1/\n' |
| 'Examples:\n' |
| ' looptest transfer 128 10000\n' |
| ' looptest ping 0 128\n' |
| ' looptest sink 2030 32768\n' |
| .format(sys.argv[0]), file=sys.stderr) |
| |
| abort() |
| |
| def read_sysfs_int(path): |
| try: |
| f = open(path, "r"); |
| val = f.read(); |
| f.close() |
| return int(val) |
| except IOError as e: |
| print("I/O error({0}): {1}".format(e.errno, e.strerror)) |
| print("Invalid path %s" % path) |
| |
| def write_sysfs_val(path, val): |
| try: |
| f = open(path, "r+") |
| f.write(val) |
| f.close() |
| except IOError as e: |
| print("I/O error({0}): {1}".format(e.errno, e.strerror)) |
| print("Invalid path %s" % path) |
| |
| def log_csv(test_name, size, iteration_max, sys_pfx): |
| # file name will test_name_size_iteration_max.csv |
| # every time the same test with the same parameters is run we will then |
| # append to the same CSV with datestamp - representing each test dataset |
| fname = test_name + '_' + size + '_' + str(iteration_max) + '.csv' |
| |
| try: |
| # gather data set |
| date = str(datetime.datetime.now()) |
| error = read_sysfs_int(sys_pfx + 'error') |
| request_min = read_sysfs_int(sys_pfx + 'requests_per_second_min') |
| request_max = read_sysfs_int(sys_pfx + 'requests_per_second_max') |
| request_avg = read_sysfs_int(sys_pfx + 'requests_per_second_avg') |
| latency_min = read_sysfs_int(sys_pfx + 'latency_min') |
| latency_max = read_sysfs_int(sys_pfx + 'latency_max') |
| latency_avg = read_sysfs_int(sys_pfx + 'latency_avg') |
| throughput_min = read_sysfs_int(sys_pfx + 'throughput_min') |
| throughput_max = read_sysfs_int(sys_pfx + 'throughput_max') |
| throughput_avg = read_sysfs_int(sys_pfx + 'throughput_avg') |
| |
| # derive jitter |
| request_jitter = request_max - request_min |
| latency_jitter = latency_max - latency_min |
| throughput_jitter = throughput_max - throughput_min |
| |
| # append data set to file |
| with open(fname, 'a') as csvf: |
| row = csv.writer(csvf, delimiter=",", quotechar="'", |
| quoting=csv.QUOTE_MINIMAL) |
| row.writerow([date, test_name, size, iteration_max, error, |
| request_min, request_max, request_avg, request_jitter, |
| latency_min, latency_max, latency_avg, latency_jitter, |
| throughput_min, throughput_max, throughput_avg, throughput_jitter]) |
| except IOError as e: |
| print("I/O error({0}): {1}".format(e.errno, e.strerror)) |
| |
| def loopback_run(test_name, size, iteration_max, sys_pfx): |
| test_id = dict[test_name] |
| try: |
| # Terminate any currently running test |
| write_sysfs_val(sys_pfx + 'type', '0') |
| # Set parameter for no wait between messages |
| write_sysfs_val(sys_pfx + 'ms_wait', '0') |
| # Set operation size |
| write_sysfs_val(sys_pfx + 'size', size) |
| # Set iterations |
| write_sysfs_val(sys_pfx + 'iteration_max', str(iteration_max)) |
| # Initiate by setting loopback operation type |
| write_sysfs_val(sys_pfx + 'type', test_id) |
| time.sleep(1) |
| |
| if iteration_max == 0: |
| print ("Infinite test initiated CSV won't be logged\n") |
| return |
| |
| previous = 0 |
| err = 0 |
| while True: |
| # get current count bail out if it hasn't changed |
| iteration_count = read_sysfs_int(sys_pfx + 'iteration_count') |
| if previous == iteration_count: |
| err = 1 |
| break |
| elif iteration_count == iteration_max: |
| break |
| previous = iteration_count |
| if verbose: |
| print('%02d%% complete %d of %d ' % |
| (100 * iteration_count / iteration_max, |
| iteration_count, iteration_max)) |
| time.sleep(1) |
| if err: |
| print ('\nError executing test\n') |
| else: |
| log_csv(test_name, size, iteration_max, sys_pfx) |
| except ValueError as ve: |
| print("Error: %s " % format(e.strerror), file=sys.stderr) |
| abort() |
| |
| def main(): |
| if len(sys.argv) < 5: |
| usage() |
| |
| if sys.argv[1] in dict.keys(): |
| loopback_run(sys.argv[1], sys.argv[2], int(sys.argv[3]), sys.argv[4]) |
| else: |
| usage() |
| if __name__ == '__main__': |
| main() |