class FioJob(object): def __init__(self, name): self.name = name self.read_status = RWStatus() self.write_status = RWStatus() CpuUsage = namedtuple( "CpuUsage", "user system context_switches major_faults minor_faults") self.cpu_usage = CpuUsage( ValuesList(unit="%"), ValuesList(unit="%"), ValuesList(), ValuesList(), ValuesList(), ) self.io_depths = ValuesList() self.io_lat_us = ValuesList() self.io_lat_ms = ValuesList() self.disk_utilization = DiskUtilization() """ Accept list of strings, each string represents one field from fio. """ def add(self, fields): i = Iter(2) i.set(5) self.read_status.add(fields[int(i):int(i + 41)]) self.write_status.add(fields[int(i):int(i + 41)]) self.cpu_usage.user.add(fields[int(i.inc())][:-1]) self.cpu_usage.system.add(fields[int(i.inc())][:-1]) self.cpu_usage.context_switches.add(fields[int(i.inc())]) self.cpu_usage.major_faults.add(fields[int(i.inc())]) self.cpu_usage.minor_faults.add(fields[int(i.inc())]) self.io_depths.add( { '1': fields[int(i.inc())], '2': fields[int(i.inc())], '4': fields[int(i.inc())], '8': fields[int(i.inc())], '16': fields[int(i.inc())], '32': fields[int(i.inc())], '64+': fields[int(i.inc())], }, False) self.io_lat_us.add( { '2': fields[int(i.inc())], '4': fields[int(i.inc())], '10': fields[int(i.inc())], '20': fields[int(i.inc())], '50': fields[int(i.inc())], '100': fields[int(i.inc())], '250': fields[int(i.inc())], '500': fields[int(i.inc())], '750': fields[int(i.inc())], '1000': fields[int(i.inc())], }, False) self.io_lat_ms.add( { '2': fields[int(i.inc())], '4': fields[int(i.inc())], '10': fields[int(i.inc())], '20': fields[int(i.inc())], '50': fields[int(i.inc())], '100': fields[int(i.inc())], '250': fields[int(i.inc())], '500': fields[int(i.inc())], '750': fields[int(i.inc())], '1000': fields[int(i.inc())], '2000': fields[int(i.inc())], '2000+': fields[int(i.inc())], }, False) self.disk_utilization.add(fields[int(i):int(i + 9)]) def __str__(self): return "%s\n"%(self.name)+\ "READ status:\n"+\ str(self.read_status)+\ "\nWRITE status:\n"+\ str(self.write_status)+\ "\n"+\ str(self.cpu_usage)+\ ""
class RWStatus(object): def __init__(self, fields = None): self.total_io = ValuesList(unit="B") self.bandwidth = ValuesList(unit="B") self.iops = ValuesList() self.runtime = ValuesList(unit="ms") Latency = namedtuple("Latency", "min max mean deviation") LatencyBW = namedtuple("Latency", "min max mean percentage deviation") self.submission_latency = Latency( ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="ms") ) self.completion_latency = Latency( ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="ms") ) self.completion_latency_percentiles = ValuesList(unit="%") self.total_latency = Latency( ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="ms") ) self.bw = LatencyBW( ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="ms"), ValuesList(unit="%"), ValuesList(unit="ms"), ) if (fields is not None): self.add(fields) def add(self, fields): i = Iter(0) self.total_io.add(int( fields[int(i.inc())])*1024) self.bandwidth.add(int( fields[int(i.inc())])*1024) self.iops.add( fields[int(i.inc())]) self.runtime.add( fields[int(i.inc())]) self.submission_latency.min.add(fields[int(i.inc())]) self.submission_latency.max.add(fields[int(i.inc())]) self.submission_latency.mean.add(fields[int(i.inc())]) self.submission_latency.deviation.add(fields[int(i.inc())]) self.completion_latency.min.add(fields[int(i.inc())]) self.completion_latency.max.add(fields[int(i.inc())]) self.completion_latency.mean.add(fields[int(i.inc())]) self.completion_latency.deviation.add(fields[int(i.inc())]) self.completion_latency_percentiles.add(fields[int(i):int(i+20)], False) self.total_latency.min.add(fields[int(i.inc())]) self.total_latency.max.add(fields[int(i.inc())]) self.total_latency.mean.add(fields[int(i.inc())]) self.total_latency.deviation.add(fields[int(i.inc())]) self.bw.min.add(fields[int(i.inc())]) self.bw.max.add(fields[int(i.inc())]) self.bw.percentage.add(fields[int(i.inc())][:-1]) self.bw.mean.add(fields[int(i.inc())]) self.bw.deviation.add(fields[int(i.inc())]) def __str__(self): return "Total IO: %sB, bandwidth: %sB/sec, IOPS: %d, runtime: %d msec" % (size(self.total_io,system=iec), size(self.bandwidth,system=iec), self.iops, self.runtime)
class DiskUtilization(object): def __init__(self, fields = None): self.disk_name = ValuesList() self.read_ios = ValuesList() self.write_ios = ValuesList() self.read_merges = ValuesList() self.write_merges = ValuesList() self.read_ticks = ValuesList() self.write_ticks = ValuesList() self.time_in_queue = ValuesList() self.utilization = ValuesList(unit="%") if (fields is not None): self.add(fields) def add(self, fields): i = Iter() self.disk_name.add(fields[int(i.inc())],False) self.read_ios.add(fields[int(i.inc())]) self.write_ios.add(fields[int(i.inc())]) self.read_merges.add(fields[int(i.inc())]) self.write_merges.add(fields[int(i.inc())]) self.read_ticks.add(fields[int(i.inc())]) self.write_ticks.add(fields[int(i.inc())]) self.time_in_queue.add(fields[int(i.inc())]) self.utilization.add(fields[int(i.inc())][:-2]) # last item on line
class FioJob(object): def __init__(self, name): self.name = name self.read_status = RWStatus() self.write_status = RWStatus() CpuUsage = namedtuple("CpuUsage", "user system context_switches major_faults minor_faults") self.cpu_usage = CpuUsage( ValuesList(unit="%"), ValuesList(unit="%"), ValuesList(), ValuesList(), ValuesList(), ) self.io_depths=ValuesList() self.io_lat_us=ValuesList() self.io_lat_ms=ValuesList() self.disk_utilization = DiskUtilization() """ Accept list of strings, each string represents one field from fio. """ def add(self, fields): i = Iter(2) i.set(5) self.read_status.add(fields[int(i):int(i+41)]) self.write_status.add(fields[int(i):int(i+41)]) self.cpu_usage.user.add(fields[int(i.inc())][:-1]) self.cpu_usage.system.add( fields[int(i.inc())][:-1]) self.cpu_usage.context_switches.add(fields[int(i.inc())]) self.cpu_usage.major_faults.add(fields[int(i.inc())]) self.cpu_usage.minor_faults.add(fields[int(i.inc())]) self.io_depths.add({ '1':fields[int(i.inc())], '2':fields[int(i.inc())], '4':fields[int(i.inc())], '8':fields[int(i.inc())], '16':fields[int(i.inc())], '32':fields[int(i.inc())], '64+':fields[int(i.inc())], }, False) self.io_lat_us.add({ '2':fields[int(i.inc())], '4':fields[int(i.inc())], '10':fields[int(i.inc())], '20':fields[int(i.inc())], '50':fields[int(i.inc())], '100':fields[int(i.inc())], '250':fields[int(i.inc())], '500':fields[int(i.inc())], '750':fields[int(i.inc())], '1000':fields[int(i.inc())], }, False) self.io_lat_ms.add({ '2':fields[int(i.inc())], '4':fields[int(i.inc())], '10':fields[int(i.inc())], '20':fields[int(i.inc())], '50':fields[int(i.inc())], '100':fields[int(i.inc())], '250':fields[int(i.inc())], '500':fields[int(i.inc())], '750':fields[int(i.inc())], '1000':fields[int(i.inc())], '2000':fields[int(i.inc())], '2000+':fields[int(i.inc())], },False) self.disk_utilization.add(fields[int(i):int(i+9)]) def __str__(self): return "%s\n"%(self.name)+\ "READ status:\n"+\ str(self.read_status)+\ "\nWRITE status:\n"+\ str(self.write_status)+\ "\n"+\ str(self.cpu_usage)+\ ""
class DiskUtilization(object): def __init__(self, fields=None): self.disk_name = ValuesList() self.read_ios = ValuesList() self.write_ios = ValuesList() self.read_merges = ValuesList() self.write_merges = ValuesList() self.read_ticks = ValuesList() self.write_ticks = ValuesList() self.time_in_queue = ValuesList() self.utilization = ValuesList(unit="%") if (fields is not None): self.add(fields) def add(self, fields): i = Iter() self.disk_name.add(fields[int(i.inc())], False) self.read_ios.add(fields[int(i.inc())]) self.write_ios.add(fields[int(i.inc())]) self.read_merges.add(fields[int(i.inc())]) self.write_merges.add(fields[int(i.inc())]) self.read_ticks.add(fields[int(i.inc())]) self.write_ticks.add(fields[int(i.inc())]) self.time_in_queue.add(fields[int(i.inc())]) self.utilization.add(fields[int(i.inc())][:-2]) # last item on line