|
Packit Service |
0d30d9 |
#! /usr/libexec/platform-python
|
|
Packit Service |
0e769b |
# Note: this script is python2 and python 3 compatible.
|
|
Packit Service |
0e769b |
#
|
|
Packit Service |
0e769b |
# fiologparser.py
|
|
Packit Service |
0e769b |
#
|
|
Packit Service |
0e769b |
# This tool lets you parse multiple fio log files and look at interaval
|
|
Packit Service |
0e769b |
# statistics even when samples are non-uniform. For instance:
|
|
Packit Service |
0e769b |
#
|
|
Packit Service |
0e769b |
# fiologparser.py -s *bw*
|
|
Packit Service |
0e769b |
#
|
|
Packit Service |
0e769b |
# to see per-interval sums for all bandwidth logs or:
|
|
Packit Service |
0e769b |
#
|
|
Packit Service |
0e769b |
# fiologparser.py -a *clat*
|
|
Packit Service |
0e769b |
#
|
|
Packit Service |
0e769b |
# to see per-interval average completion latency.
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
from __future__ import absolute_import
|
|
Packit Service |
0e769b |
from __future__ import print_function
|
|
Packit Service |
0e769b |
import argparse
|
|
Packit Service |
0e769b |
import math
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def parse_args():
|
|
Packit Service |
0e769b |
parser = argparse.ArgumentParser()
|
|
Packit Service |
0e769b |
parser.add_argument('-i', '--interval', required=False, type=int, default=1000, help='interval of time in seconds.')
|
|
Packit Service |
0e769b |
parser.add_argument('-d', '--divisor', required=False, type=int, default=1, help='divide the results by this value.')
|
|
Packit Service |
0e769b |
parser.add_argument('-f', '--full', dest='full', action='store_true', default=False, help='print full output.')
|
|
Packit Service |
0e769b |
parser.add_argument('-A', '--all', dest='allstats', action='store_true', default=False,
|
|
Packit Service |
0e769b |
help='print all stats for each interval.')
|
|
Packit Service |
0e769b |
parser.add_argument('-a', '--average', dest='average', action='store_true', default=False, help='print the average for each interval.')
|
|
Packit Service |
0e769b |
parser.add_argument('-s', '--sum', dest='sum', action='store_true', default=False, help='print the sum for each interval.')
|
|
Packit Service |
0e769b |
parser.add_argument("FILE", help="collectl log output files to parse", nargs="+")
|
|
Packit Service |
0e769b |
args = parser.parse_args()
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
return args
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def get_ftime(series):
|
|
Packit Service |
0e769b |
ftime = 0
|
|
Packit Service |
0e769b |
for ts in series:
|
|
Packit Service |
0e769b |
if ftime == 0 or ts.last.end < ftime:
|
|
Packit Service |
0e769b |
ftime = ts.last.end
|
|
Packit Service |
0e769b |
return ftime
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def print_full(ctx, series):
|
|
Packit Service |
0e769b |
ftime = get_ftime(series)
|
|
Packit Service |
0e769b |
start = 0
|
|
Packit Service |
0e769b |
end = ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
while (start < ftime):
|
|
Packit Service |
0e769b |
end = ftime if ftime < end else end
|
|
Packit Service |
0e769b |
results = [ts.get_value(start, end) for ts in series]
|
|
Packit Service |
0e769b |
print("%s, %s" % (end, ', '.join(["%0.3f" % i for i in results])))
|
|
Packit Service |
0e769b |
start += ctx.interval
|
|
Packit Service |
0e769b |
end += ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def print_sums(ctx, series):
|
|
Packit Service |
0e769b |
ftime = get_ftime(series)
|
|
Packit Service |
0e769b |
start = 0
|
|
Packit Service |
0e769b |
end = ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
while (start < ftime):
|
|
Packit Service |
0e769b |
end = ftime if ftime < end else end
|
|
Packit Service |
0e769b |
results = [ts.get_value(start, end) for ts in series]
|
|
Packit Service |
0e769b |
print("%s, %0.3f" % (end, sum(results)))
|
|
Packit Service |
0e769b |
start += ctx.interval
|
|
Packit Service |
0e769b |
end += ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def print_averages(ctx, series):
|
|
Packit Service |
0e769b |
ftime = get_ftime(series)
|
|
Packit Service |
0e769b |
start = 0
|
|
Packit Service |
0e769b |
end = ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
while (start < ftime):
|
|
Packit Service |
0e769b |
end = ftime if ftime < end else end
|
|
Packit Service |
0e769b |
results = [ts.get_value(start, end) for ts in series]
|
|
Packit Service |
0e769b |
print("%s, %0.3f" % (end, float(sum(results))/len(results)))
|
|
Packit Service |
0e769b |
start += ctx.interval
|
|
Packit Service |
0e769b |
end += ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
# FIXME: this routine is computationally inefficient
|
|
Packit Service |
0e769b |
# and has O(N^2) behavior
|
|
Packit Service |
0e769b |
# it would be better to make one pass through samples
|
|
Packit Service |
0e769b |
# to segment them into a series of time intervals, and
|
|
Packit Service |
0e769b |
# then compute stats on each time interval instead.
|
|
Packit Service |
0e769b |
# to debug this routine, use
|
|
Packit Service |
0e769b |
# # sort -n -t ',' -k 2 small.log
|
|
Packit Service |
0e769b |
# on your input.
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def my_extend( vlist, val ):
|
|
Packit Service |
0e769b |
vlist.extend(val)
|
|
Packit Service |
0e769b |
return vlist
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
array_collapser = lambda vlist, val: my_extend(vlist, val)
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def print_all_stats(ctx, series):
|
|
Packit Service |
0e769b |
ftime = get_ftime(series)
|
|
Packit Service |
0e769b |
start = 0
|
|
Packit Service |
0e769b |
end = ctx.interval
|
|
Packit Service |
0e769b |
print('start-time, samples, min, avg, median, 90%, 95%, 99%, max')
|
|
Packit Service |
0e769b |
while (start < ftime): # for each time interval
|
|
Packit Service |
0e769b |
end = ftime if ftime < end else end
|
|
Packit Service |
0e769b |
sample_arrays = [ s.get_samples(start, end) for s in series ]
|
|
Packit Service |
0e769b |
samplevalue_arrays = []
|
|
Packit Service |
0e769b |
for sample_array in sample_arrays:
|
|
Packit Service |
0e769b |
samplevalue_arrays.append(
|
|
Packit Service |
0e769b |
[ sample.value for sample in sample_array ] )
|
|
Packit Service |
0e769b |
# collapse list of lists of sample values into list of sample values
|
|
Packit Service |
0e769b |
samplevalues = reduce( array_collapser, samplevalue_arrays, [] )
|
|
Packit Service |
0e769b |
# compute all stats and print them
|
|
Packit Service |
0e769b |
mymin = min(samplevalues)
|
|
Packit Service |
0e769b |
myavg = sum(samplevalues) / float(len(samplevalues))
|
|
Packit Service |
0e769b |
mymedian = median(samplevalues)
|
|
Packit Service |
0e769b |
my90th = percentile(samplevalues, 0.90)
|
|
Packit Service |
0e769b |
my95th = percentile(samplevalues, 0.95)
|
|
Packit Service |
0e769b |
my99th = percentile(samplevalues, 0.99)
|
|
Packit Service |
0e769b |
mymax = max(samplevalues)
|
|
Packit Service |
0e769b |
print( '%f, %d, %f, %f, %f, %f, %f, %f, %f' % (
|
|
Packit Service |
0e769b |
start, len(samplevalues),
|
|
Packit Service |
0e769b |
mymin, myavg, mymedian, my90th, my95th, my99th, mymax))
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
# advance to next interval
|
|
Packit Service |
0e769b |
start += ctx.interval
|
|
Packit Service |
0e769b |
end += ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def median(values):
|
|
Packit Service |
0e769b |
s=sorted(values)
|
|
Packit Service |
0e769b |
return float(s[(len(s)-1)/2]+s[(len(s)/2)])/2
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def percentile(values, p):
|
|
Packit Service |
0e769b |
s = sorted(values)
|
|
Packit Service |
0e769b |
k = (len(s)-1) * p
|
|
Packit Service |
0e769b |
f = math.floor(k)
|
|
Packit Service |
0e769b |
c = math.ceil(k)
|
|
Packit Service |
0e769b |
if f == c:
|
|
Packit Service |
0e769b |
return s[int(k)]
|
|
Packit Service |
0e769b |
return (s[int(f)] * (c-k)) + (s[int(c)] * (k-f))
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def print_default(ctx, series):
|
|
Packit Service |
0e769b |
ftime = get_ftime(series)
|
|
Packit Service |
0e769b |
start = 0
|
|
Packit Service |
0e769b |
end = ctx.interval
|
|
Packit Service |
0e769b |
averages = []
|
|
Packit Service |
0e769b |
weights = []
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
while (start < ftime):
|
|
Packit Service |
0e769b |
end = ftime if ftime < end else end
|
|
Packit Service |
0e769b |
results = [ts.get_value(start, end) for ts in series]
|
|
Packit Service |
0e769b |
averages.append(sum(results))
|
|
Packit Service |
0e769b |
weights.append(end-start)
|
|
Packit Service |
0e769b |
start += ctx.interval
|
|
Packit Service |
0e769b |
end += ctx.interval
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
total = 0
|
|
Packit Service |
0e769b |
for i in range(0, len(averages)):
|
|
Packit Service |
0e769b |
total += averages[i]*weights[i]
|
|
Packit Service |
0e769b |
print('%0.3f' % (total/sum(weights)))
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
class TimeSeries(object):
|
|
Packit Service |
0e769b |
def __init__(self, ctx, fn):
|
|
Packit Service |
0e769b |
self.ctx = ctx
|
|
Packit Service |
0e769b |
self.last = None
|
|
Packit Service |
0e769b |
self.samples = []
|
|
Packit Service |
0e769b |
self.read_data(fn)
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def read_data(self, fn):
|
|
Packit Service |
0e769b |
f = open(fn, 'r')
|
|
Packit Service |
0e769b |
p_time = 0
|
|
Packit Service |
0e769b |
for line in f:
|
|
Packit Service |
0e769b |
(time, value, foo, bar) = line.rstrip('\r\n').rsplit(', ')
|
|
Packit Service |
0e769b |
self.add_sample(p_time, int(time), int(value))
|
|
Packit Service |
0e769b |
p_time = int(time)
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def add_sample(self, start, end, value):
|
|
Packit Service |
0e769b |
sample = Sample(ctx, start, end, value)
|
|
Packit Service |
0e769b |
if not self.last or self.last.end < end:
|
|
Packit Service |
0e769b |
self.last = sample
|
|
Packit Service |
0e769b |
self.samples.append(sample)
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def get_samples(self, start, end):
|
|
Packit Service |
0e769b |
sample_list = []
|
|
Packit Service |
0e769b |
for s in self.samples:
|
|
Packit Service |
0e769b |
if s.start >= start and s.end <= end:
|
|
Packit Service |
0e769b |
sample_list.append(s)
|
|
Packit Service |
0e769b |
return sample_list
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def get_value(self, start, end):
|
|
Packit Service |
0e769b |
value = 0
|
|
Packit Service |
0e769b |
for sample in self.samples:
|
|
Packit Service |
0e769b |
value += sample.get_contribution(start, end)
|
|
Packit Service |
0e769b |
return value
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
class Sample(object):
|
|
Packit Service |
0e769b |
def __init__(self, ctx, start, end, value):
|
|
Packit Service |
0e769b |
self.ctx = ctx
|
|
Packit Service |
0e769b |
self.start = start
|
|
Packit Service |
0e769b |
self.end = end
|
|
Packit Service |
0e769b |
self.value = value
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
def get_contribution(self, start, end):
|
|
Packit Service |
0e769b |
# short circuit if not within the bound
|
|
Packit Service |
0e769b |
if (end < self.start or start > self.end):
|
|
Packit Service |
0e769b |
return 0
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
sbound = self.start if start < self.start else start
|
|
Packit Service |
0e769b |
ebound = self.end if end > self.end else end
|
|
Packit Service |
0e769b |
ratio = float(ebound-sbound) / (end-start)
|
|
Packit Service |
0e769b |
return self.value*ratio/ctx.divisor
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if __name__ == '__main__':
|
|
Packit Service |
0e769b |
ctx = parse_args()
|
|
Packit Service |
0e769b |
series = []
|
|
Packit Service |
0e769b |
for fn in ctx.FILE:
|
|
Packit Service |
0e769b |
series.append(TimeSeries(ctx, fn))
|
|
Packit Service |
0e769b |
if ctx.sum:
|
|
Packit Service |
0e769b |
print_sums(ctx, series)
|
|
Packit Service |
0e769b |
elif ctx.average:
|
|
Packit Service |
0e769b |
print_averages(ctx, series)
|
|
Packit Service |
0e769b |
elif ctx.full:
|
|
Packit Service |
0e769b |
print_full(ctx, series)
|
|
Packit Service |
0e769b |
elif ctx.allstats:
|
|
Packit Service |
0e769b |
print_all_stats(ctx, series)
|
|
Packit Service |
0e769b |
else:
|
|
Packit Service |
0e769b |
print_default(ctx, series)
|