blob: 1e4ac40ea722daecba5282d764a261f6a89f6163 [file] [log] [blame]
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Author: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
import datetime
import logging
import os
from autotest_lib.client.cros import storage as storage_mod
from autotest_lib.client.common_lib import autotemp, error
from autotest_lib.client.bin import utils
USECS_IN_SEC = 1000000.0
class hardware_Usb30Throughput(storage_mod.StorageTester):
version = 1
preserve_srcdir = True
_autosrc = None
_autodst = None
def cleanup(self):
if self._autosrc:
self._autosrc.clean()
if self._autodst:
self._autodst.clean()
self.scanner.unmount_all()
super(hardware_Usb30Throughput, self).cleanup()
def run_once(self, measurements=5, size=1, min_read_speed=300.0,
min_write_speed=300.0):
"""
@param measurements: (int) the number of measurements to do.
For the test to fail at least one measurement needs to be
below |min_speed|
@param size: (int) size of the file to be copied for testing the
transfer rate, it represent the size in megabytes.
Generally speaking, the bigger is the file used for
|measurements| the slower the test will run and the more
accurate it will be.
e.g.: 10 is 10MB, 101 is 101MB
@param min_read_speed: (float) in Mbit/sec. It's the min
throughput a USB 3.0 device should perform to be accepted while
reading from USB. Conceptually it's the max USB 3.0 throughput
minus a tolerance. Defaults to 300Mbit/sec (ie 350Mbits/sec
minus ~15% tolerance)
@param min_write_speed: (float) in Mbit/sec. It's the min throughput a
USB 3.0 device should perform to be accepted while writing to
USB. Conceptually it's the max USB 3.0 throughput minus a
tolerance. Defaults to 300Mbit/sec (ie 350Mbits/sec minus ~15%
tolerance)
"""
self.measurements = measurements
self.min_read_speed = min_read_speed
self.min_write_speed = min_write_speed
volume_filter = {'bus': 'usb'}
storage = self.wait_for_device(volume_filter, cycles=1,
mount_volume=True)[0]
# in Megabytes (power of 10, to be consistent with the throughput unit)
size *= 1000 * 1000
self._autosrc = autotemp.tempfile(unique_id='autotest.src',
dir=storage['mountpoint'])
self._autodst = autotemp.tempfile(unique_id='autotest.dst',
dir=self.tmpdir)
# Create random file
storage_mod.create_file(self._autodst.name, size)
logging.info("Checking USB writing speed")
self.transfer(self._autodst.name, self._autosrc.name, mode="write")
storage_mod.create_file(self._autosrc.name, size)
logging.info("Checking USB reading speed")
self.transfer(self._autosrc.name, self._autodst.name, mode="read")
def transfer(self, src, dst, mode):
num_failures = 0
results = {}
min_speed = self.min_read_speed if mode == "read" else self.min_write_speed
for measurement in range(self.measurements):
xfer_rate = get_xfer_rate(src, dst)
key = '%s_Mbit_per_sec_measurement_%d' % (mode, measurement)
results[key] = xfer_rate
logging.debug('%s xfer rate (measurement %d) %.2f (min=%.2f)',
mode, measurement, xfer_rate, min_speed)
if xfer_rate < min_speed:
num_failures += 1
# Apparently self.postprocess_iteration is not called on TestFail
# so we need to process data here in order to have some performance log
# even on TestFail
results[mode + '_Mbit_per_sec_average'] = (sum(results.values()) /
len(results))
self.write_perf_keyval(results)
if num_failures > 0:
msg = ('%d/%d measured transfer rates under performed '
'(min_speed=%.2fMbit/sec)' % (num_failures, self.measurements,
min_speed))
raise error.TestFail(msg)
def get_xfer_rate(src, dst):
"""Compute transfer rate from src to dst as Mbit/sec
Execute a copy from |src| to |dst| and returns the file copy transfer rate
in Mbit/sec
@param src, dst: paths for source and destination
@return trasfer rate (float) in Mbit/sec
"""
assert os.path.isfile(src)
assert os.path.isfile(dst)
utils.drop_caches()
start = datetime.datetime.now()
utils.force_copy(src, dst)
end = datetime.datetime.now()
delta = end - start
# compute seconds (as float) from microsecs
delta_secs = delta.seconds + (delta.microseconds / USECS_IN_SEC)
# compute Mbit from bytes
size_Mbit = (os.path.getsize(src) * 8.0) / (1000 * 1000)
logging.info('file trasferred: size (Mbits): %f, start: %f, end: %d,'
' delta (secs): %f',
size_Mbit,
start.second + start.microsecond / USECS_IN_SEC,
end.second + end.microsecond / USECS_IN_SEC,
delta_secs)
# return the xfer rate in Mbits/secs having bytes/microsec
return size_Mbit / delta_secs