changed for new data format
diff --git a/scripts/postprocessing/bottleneck.py b/scripts/postprocessing/bottleneck.py
index 8b94f2f..64156cf 100644
--- a/scripts/postprocessing/bottleneck.py
+++ b/scripts/postprocessing/bottleneck.py
@@ -9,6 +9,13 @@
Record = namedtuple("Record", ['name', 'max_value'])
+MetricValue = namedtuple("MetricValue", ['value', 'time'])
+Bottleneck = namedtuple("Bottleneck", ['node', 'value', 'count'])
+
+sortRuleByValue = lambda x: x.value
+sortRuleByMaxValue = lambda x: x.max_value
+sortRuleByCount = lambda x: x.count
+sortRuleByTime = lambda x: x.time
critical_values = [
Record("io_queue", 1),
@@ -16,25 +23,53 @@
Record("mem_usage_percent", 0.8)
]
-def load_results(begin_time, end_time, rfile):
+
+def get_name_from_sourceid(source_id):
+ """ Cut port """
+ pos = source_id.rfind(":")
+ return source_id[:pos]
+
+
+def create_table(header, rows, signs=1):
+ """ Return texttable view """
+ tab = TT.Texttable()
+ tab.set_deco(tab.VLINES)
+ tab.set_precision(signs)
+ tab.add_row(header)
+ tab.header = header
+
+ for row in rows:
+ tab.add_row(row)
+
+ return tab.draw()
+
+
+def load_results(period, rfile):
""" Read raw results from dir and return
data from provided period"""
results = {}
-
+ if period is not None:
+ begin_time, end_time = period
with open(rfile, "r") as f:
for line in f:
if len(line) <= 1:
continue
- ttime, _, raw_data = line.partition(" : ")
- raw_data = raw_data.strip('"\n\r')
- itime = float(ttime)
- if itime >= begin_time and itime <= end_time:
- addr, data = eval(raw_data)
- sid = data.pop("source_id")
- data.pop("time")
- serv = "{0}({1})".format(addr[0], sid)
- serv_data = results.setdefault(serv, {})
+ if " : " in line:
+ # old format
+ ttime, _, raw_data = line.partition(" : ")
+ raw_data = raw_data.strip('"\n\r')
+ itime = float(ttime)
+ else:
+ # new format without time
+ raw_data = line.strip('"\n\r')
+
+ _, data = eval(raw_data)
+ sid = get_name_from_sourceid(data.pop("source_id"))
+ itime = data.pop("time")
+
+ if period is None or (itime >= begin_time and itime <= end_time):
+ serv_data = results.setdefault(sid, {})
for key, value in data.items():
# select device and metric names
dev, _, metric = key.partition(".")
@@ -42,24 +77,67 @@
metric_dict = serv_data.setdefault(metric, {})
# set value for metric on dev
cur_val = metric_dict.setdefault(dev, [])
- cur_val.append(value)
- print results
+ cur_val.append(MetricValue(value, itime))
+
+ # sort by time
+ for ms in results.values():
+ for dev in ms.values():
+ for d in dev.keys():
+ dev[d] = sorted(dev[d], key=sortRuleByTime)
+
return results
+def find_time_load_percent(data, params):
+ """ Find avg load of components by time
+ and return sorted table """
-def print_bottlenecks(data, params):
+ header = ["Component", "Avg load %"]
+ name_fmt = "{0}.{1}"
+ value_fmt = "{0:.1f}"
+ loads = []
+ for node, metrics in data.items():
+ for metric, max_value in params:
+ if metric in metrics:
+ item = metrics[metric]
+ # count time it was > max_value
+ # count times it was > max_value
+ for dev, vals in item.items():
+ num_l = 0
+ times = []
+ i = 0
+ while i < len(vals):
+ if vals[i].value >= max_value:
+ num_l += 1
+ b_time = vals[i].time
+ while i < len(vals) and \
+ vals[i].value >= max_value:
+ i += 1
+ times.append(vals[i-1].time - b_time)
+ i += 1
+ if num_l > 0:
+ avg_time = sum(times) / float(num_l)
+ total_time = vals[-1].time - vals[0].time
+ avg_load = (avg_time / total_time) * 100
+ loads.append(Record(name_fmt.format(node, dev), avg_load))
+
+ rows = [[name, value_fmt.format(value)]
+ for name, value in sorted(loads, key=sortRuleByMaxValue, reverse=True)]
+ return create_table(header, rows)
+
+
+
+def print_bottlenecks(data, params, max_bottlenecks=3):
""" Print bottlenecks in table format,
search in data by fields in params"""
- tab = TT.Texttable()
- tab.set_deco(tab.VLINES)
-
- header = ["Server, device", "Critical value"]
- tab.add_row(header)
- tab.header = header
-
+ # all bottlenecks
rows = []
val_format = "{0}: {1}, {2} times it was >= {3}"
+
+ # max_bottlenecks most slowests places
+ # Record metric : [Bottleneck nodes (max 3)]
+ max_values = {}
+
for node, metrics in data.items():
node_rows = []
for metric, max_value in params:
@@ -76,6 +154,12 @@
if max_v < val:
max_v = val
if num_l > 0:
+ key = Record(metric, max_value)
+ # add to most slowest
+ btnk = max_values.setdefault(key, [])
+ # just add all data at first
+ btnk.append(Bottleneck(node, max_v, num_l))
+ #add to common table
c_val = val_format.format(metric, max_v,
num_l, max_value)
node_rows.append([dev, c_val])
@@ -83,18 +167,60 @@
rows.append([node, ""])
rows.extend(node_rows)
+ tab = TT.Texttable()
+ #tab.set_deco(tab.VLINES)
+
+ header = ["Server, device", "Critical value"]
+ tab.add_row(header)
+ tab.header = header
+
for row in rows:
tab.add_row(row)
- print tab.draw()
+ most_slowest_header = [metric for metric, max_value in max_values.keys()]
+ most_slowest = []
+ # select most slowest
+ for metric, btnks in max_values.items():
+ m_data = []
+ worst = sorted(btnks, key=sortRuleByValue, reverse=True)[:max_bottlenecks]
+ longest = sorted(btnks, key=sortRuleByCount, reverse=True)[:max_bottlenecks]
+ m_data.append("{0} worst by value: ".format(max_bottlenecks))
+ for btnk in worst:
+ m_data.append(val_format.format(btnk.node, btnk.value,
+ btnk.count,
+ metric.max_value))
+ m_data.append("{0} worst by times it was bad: ".format(max_bottlenecks))
+ for btnk in longest:
+ m_data.append(val_format.format(btnk.node, btnk.value,
+ btnk.count,
+ metric.max_value))
+ most_slowest.append(m_data)
+
+
+ rows2 = zip(*most_slowest)
+
+ tab2 = TT.Texttable()
+ #tab2.set_deco(tab.VLINES)
+
+ tab2.add_row(most_slowest_header)
+ tab2.header = most_slowest_header
+
+ for row in rows2:
+ tab2.add_row(row)
+ return tab.draw(), tab2.draw()
def parse_args(args):
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--time_period', nargs=2,
- type=float,
+ type=float, default=None,
help="Begin and end time for tests")
+ parser.add_argument('-d', '--debug-ver', action='store_true',
+ help="Full report with original data")
+ parser.add_argument('-u', '--user-ver', action='store_true',
+ default=True,
+ help="Avg load report")
parser.add_argument('sensors_result', type=str,
default=None, nargs='?')
return parser.parse_args(args[1:])
@@ -103,9 +229,18 @@
def main(argv):
opts = parse_args(argv)
- results = load_results(opts.time_period[0], opts.time_period[1], opts.sensors_result)
+ results = load_results(opts.time_period, opts.sensors_result)
- print_bottlenecks(results, critical_values)
+ if opts.debug_ver:
+ tab_all, tab_max = print_bottlenecks(results, critical_values)
+ print "Maximum values on provided metrics"
+ print tab_max
+ print "All loaded values"
+ print tab_all
+
+ else:
+ print find_time_load_percent(results, critical_values)
+
if __name__ == "__main__":
exit(main(sys.argv))