1# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4# Author: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk> 5 6import datetime 7import logging 8import os 9 10from autotest_lib.client.cros import storage as storage_mod 11from autotest_lib.client.common_lib import autotemp, error 12from autotest_lib.client.bin import utils 13 14USECS_IN_SEC = 1000000.0 15 16class hardware_Usb30Throughput(storage_mod.StorageTester): 17 version = 1 18 preserve_srcdir = True 19 _autosrc = None 20 _autodst = None 21 results = {} 22 23 24 def cleanup(self): 25 if self._autosrc: 26 self._autosrc.clean() 27 if self._autodst: 28 self._autodst.clean() 29 30 self.scanner.unmount_all() 31 32 super(hardware_Usb30Throughput, self).cleanup() 33 34 35 def run_once(self, measurements=5, size=1, min_speed=300.0): 36 """ 37 @param measurements: (int) the number of measurements to do. 38 For the test to fail at least one measurement needs to be 39 below |min_speed| 40 @param size: (int) size of the file to be copied for testing the 41 transfer rate, it represent the size in megabytes. 42 Generally speaking, the bigger is the file used for 43 |measurements| the slower the test will run and the more 44 accurate it will be. 45 e.g.: 10 is 10MB, 101 is 101MB 46 @param min_speed: (float) in Mbit/sec. It's the min throughput a USB 3.0 47 device should perform to be accepted. Conceptually it's the max 48 USB 3.0 throughput minus a tollerance. 49 Defaults to 300Mbit/sec (ie 350Mbits/sec minus ~15% tollerance) 50 """ 51 volume_filter = {'bus': 'usb'} 52 storage = self.wait_for_device(volume_filter, cycles=1, 53 mount_volume=True)[0] 54 55 # in Megabytes (power of 10, to be consistent with the throughput unit) 56 size *= 1000*1000 57 58 self._autosrc = autotemp.tempfile(unique_id='autotest.src', 59 dir=storage['mountpoint']) 60 self._autodst = autotemp.tempfile(unique_id='autotest.dst', 61 dir=self.tmpdir) 62 63 # Create random file 64 storage_mod.create_file(self._autosrc.name, size) 65 66 num_failures = 0 67 for measurement in range(measurements): 68 xfer_rate = get_xfer_rate(self._autosrc.name, self._autodst.name) 69 key = 'Mbit_per_sec_measurement_%d' % measurement 70 self.results[key] = xfer_rate 71 logging.debug('xfer rate (measurement %d) %.2f (min=%.2f)', 72 measurement, xfer_rate, min_speed) 73 74 if xfer_rate < min_speed: 75 num_failures += 1 76 77 # Apparently self.postprocess_iteration is not called on TestFail 78 # so we need to process data here in order to have some performance log 79 # even on TestFail 80 self.results['Mbit_per_sec_average'] = (sum(self.results.values()) / 81 len(self.results)) 82 self.write_perf_keyval(self.results) 83 84 if num_failures > 0: 85 msg = ('%d/%d measured transfer rates under performed ' 86 '(min_speed=%.2fMbit/sec)' % (num_failures, measurements, 87 min_speed)) 88 raise error.TestFail(msg) 89 90 91def get_xfer_rate(src, dst): 92 """Compute transfer rate from src to dst as Mbit/sec 93 94 Execute a copy from |src| to |dst| and returns the file copy transfer rate 95 in Mbit/sec 96 97 @param src, dst: paths for source and destination 98 99 @return trasfer rate (float) in Mbit/sec 100 """ 101 assert os.path.isfile(src) 102 assert os.path.isfile(dst) 103 104 utils.drop_caches() 105 start = datetime.datetime.now() 106 utils.force_copy(src, dst) 107 end = datetime.datetime.now() 108 delta = end - start 109 110 # compute seconds (as float) from microsecs 111 delta_secs = delta.seconds + (delta.microseconds/USECS_IN_SEC) 112 # compute Mbit from bytes 113 size_Mbit = (os.path.getsize(src)*8.0)/(1000*1000) 114 115 logging.info('file trasferred: size (Mbits): %f, start: %f, end: %d,' 116 ' delta (secs): %f', 117 size_Mbit, 118 start.second+start.microsecond/USECS_IN_SEC, 119 end.second+end.microsecond/USECS_IN_SEC, 120 delta_secs) 121 122 # return the xfer rate in Mbits/secs having bytes/microsec 123 return size_Mbit / delta_secs 124