blob: 64156cfccf06ddf27a0aaa0c07cc6048b1063c23 [file] [log] [blame]
Ved-vampir5c7b6142015-04-24 19:49:59 +03001""" Analize test results for finding bottlenecks """
2
3import sys
4import argparse
5
6import texttable as TT
7
8from collections import namedtuple
9
10
11Record = namedtuple("Record", ['name', 'max_value'])
Ved-vampirfcea0722015-04-27 14:06:13 +030012MetricValue = namedtuple("MetricValue", ['value', 'time'])
13Bottleneck = namedtuple("Bottleneck", ['node', 'value', 'count'])
14
15sortRuleByValue = lambda x: x.value
16sortRuleByMaxValue = lambda x: x.max_value
17sortRuleByCount = lambda x: x.count
18sortRuleByTime = lambda x: x.time
Ved-vampir5c7b6142015-04-24 19:49:59 +030019
20critical_values = [
21 Record("io_queue", 1),
22 Record("procs_blocked", 1),
23 Record("mem_usage_percent", 0.8)
24 ]
25
Ved-vampirfcea0722015-04-27 14:06:13 +030026
27def get_name_from_sourceid(source_id):
28 """ Cut port """
29 pos = source_id.rfind(":")
30 return source_id[:pos]
31
32
33def create_table(header, rows, signs=1):
34 """ Return texttable view """
35 tab = TT.Texttable()
36 tab.set_deco(tab.VLINES)
37 tab.set_precision(signs)
38 tab.add_row(header)
39 tab.header = header
40
41 for row in rows:
42 tab.add_row(row)
43
44 return tab.draw()
45
46
47def load_results(period, rfile):
Ved-vampir5c7b6142015-04-24 19:49:59 +030048 """ Read raw results from dir and return
49 data from provided period"""
50 results = {}
Ved-vampirfcea0722015-04-27 14:06:13 +030051 if period is not None:
52 begin_time, end_time = period
Ved-vampir5c7b6142015-04-24 19:49:59 +030053 with open(rfile, "r") as f:
54 for line in f:
55
56 if len(line) <= 1:
57 continue
Ved-vampirfcea0722015-04-27 14:06:13 +030058 if " : " in line:
59 # old format
60 ttime, _, raw_data = line.partition(" : ")
61 raw_data = raw_data.strip('"\n\r')
62 itime = float(ttime)
63 else:
64 # new format without time
65 raw_data = line.strip('"\n\r')
66
67 _, data = eval(raw_data)
68 sid = get_name_from_sourceid(data.pop("source_id"))
69 itime = data.pop("time")
70
71 if period is None or (itime >= begin_time and itime <= end_time):
72 serv_data = results.setdefault(sid, {})
Ved-vampir5c7b6142015-04-24 19:49:59 +030073 for key, value in data.items():
74 # select device and metric names
75 dev, _, metric = key.partition(".")
76 # create dict for metric
77 metric_dict = serv_data.setdefault(metric, {})
78 # set value for metric on dev
79 cur_val = metric_dict.setdefault(dev, [])
Ved-vampirfcea0722015-04-27 14:06:13 +030080 cur_val.append(MetricValue(value, itime))
81
82 # sort by time
83 for ms in results.values():
84 for dev in ms.values():
85 for d in dev.keys():
86 dev[d] = sorted(dev[d], key=sortRuleByTime)
87
Ved-vampir5c7b6142015-04-24 19:49:59 +030088 return results
89
90
Ved-vampirfcea0722015-04-27 14:06:13 +030091def find_time_load_percent(data, params):
92 """ Find avg load of components by time
93 and return sorted table """
Ved-vampir5c7b6142015-04-24 19:49:59 +030094
Ved-vampirfcea0722015-04-27 14:06:13 +030095 header = ["Component", "Avg load %"]
96 name_fmt = "{0}.{1}"
97 value_fmt = "{0:.1f}"
98 loads = []
99 for node, metrics in data.items():
100 for metric, max_value in params:
101 if metric in metrics:
102 item = metrics[metric]
103 # count time it was > max_value
104 # count times it was > max_value
105 for dev, vals in item.items():
106 num_l = 0
107 times = []
108 i = 0
109 while i < len(vals):
110 if vals[i].value >= max_value:
111 num_l += 1
112 b_time = vals[i].time
113 while i < len(vals) and \
114 vals[i].value >= max_value:
115 i += 1
116 times.append(vals[i-1].time - b_time)
117 i += 1
118 if num_l > 0:
119 avg_time = sum(times) / float(num_l)
120 total_time = vals[-1].time - vals[0].time
121 avg_load = (avg_time / total_time) * 100
122 loads.append(Record(name_fmt.format(node, dev), avg_load))
123
124 rows = [[name, value_fmt.format(value)]
125 for name, value in sorted(loads, key=sortRuleByMaxValue, reverse=True)]
126 return create_table(header, rows)
127
128
129
130def print_bottlenecks(data, params, max_bottlenecks=3):
Ved-vampir5c7b6142015-04-24 19:49:59 +0300131 """ Print bottlenecks in table format,
132 search in data by fields in params"""
Ved-vampirfcea0722015-04-27 14:06:13 +0300133 # all bottlenecks
Ved-vampir5c7b6142015-04-24 19:49:59 +0300134 rows = []
135 val_format = "{0}: {1}, {2} times it was >= {3}"
Ved-vampirfcea0722015-04-27 14:06:13 +0300136
137 # max_bottlenecks most slowests places
138 # Record metric : [Bottleneck nodes (max 3)]
139 max_values = {}
140
Ved-vampir5c7b6142015-04-24 19:49:59 +0300141 for node, metrics in data.items():
142 node_rows = []
143 for metric, max_value in params:
144 if metric in metrics:
145 item = metrics[metric]
146 # find max val for dev
147 # count times it was > max_value
148 for dev, vals in item.items():
149 num_l = 0
150 max_v = -1
151 for val in vals:
152 if val >= max_value:
153 num_l += 1
154 if max_v < val:
155 max_v = val
156 if num_l > 0:
Ved-vampirfcea0722015-04-27 14:06:13 +0300157 key = Record(metric, max_value)
158 # add to most slowest
159 btnk = max_values.setdefault(key, [])
160 # just add all data at first
161 btnk.append(Bottleneck(node, max_v, num_l))
162 #add to common table
Ved-vampir5c7b6142015-04-24 19:49:59 +0300163 c_val = val_format.format(metric, max_v,
164 num_l, max_value)
165 node_rows.append([dev, c_val])
166 if len(node_rows) > 0:
167 rows.append([node, ""])
168 rows.extend(node_rows)
169
Ved-vampirfcea0722015-04-27 14:06:13 +0300170 tab = TT.Texttable()
171 #tab.set_deco(tab.VLINES)
172
173 header = ["Server, device", "Critical value"]
174 tab.add_row(header)
175 tab.header = header
176
Ved-vampir5c7b6142015-04-24 19:49:59 +0300177 for row in rows:
178 tab.add_row(row)
179
Ved-vampirfcea0722015-04-27 14:06:13 +0300180 most_slowest_header = [metric for metric, max_value in max_values.keys()]
181 most_slowest = []
182 # select most slowest
183 for metric, btnks in max_values.items():
184 m_data = []
185 worst = sorted(btnks, key=sortRuleByValue, reverse=True)[:max_bottlenecks]
186 longest = sorted(btnks, key=sortRuleByCount, reverse=True)[:max_bottlenecks]
187 m_data.append("{0} worst by value: ".format(max_bottlenecks))
188 for btnk in worst:
189 m_data.append(val_format.format(btnk.node, btnk.value,
190 btnk.count,
191 metric.max_value))
192 m_data.append("{0} worst by times it was bad: ".format(max_bottlenecks))
193 for btnk in longest:
194 m_data.append(val_format.format(btnk.node, btnk.value,
195 btnk.count,
196 metric.max_value))
197 most_slowest.append(m_data)
198
199
200 rows2 = zip(*most_slowest)
201
202 tab2 = TT.Texttable()
203 #tab2.set_deco(tab.VLINES)
204
205 tab2.add_row(most_slowest_header)
206 tab2.header = most_slowest_header
207
208 for row in rows2:
209 tab2.add_row(row)
210 return tab.draw(), tab2.draw()
Ved-vampir5c7b6142015-04-24 19:49:59 +0300211
212
213
214def parse_args(args):
215 parser = argparse.ArgumentParser()
216 parser.add_argument('-t', '--time_period', nargs=2,
Ved-vampirfcea0722015-04-27 14:06:13 +0300217 type=float, default=None,
Ved-vampir5c7b6142015-04-24 19:49:59 +0300218 help="Begin and end time for tests")
Ved-vampirfcea0722015-04-27 14:06:13 +0300219 parser.add_argument('-d', '--debug-ver', action='store_true',
220 help="Full report with original data")
221 parser.add_argument('-u', '--user-ver', action='store_true',
222 default=True,
223 help="Avg load report")
Ved-vampir5c7b6142015-04-24 19:49:59 +0300224 parser.add_argument('sensors_result', type=str,
225 default=None, nargs='?')
226 return parser.parse_args(args[1:])
227
228
229def main(argv):
230 opts = parse_args(argv)
231
Ved-vampirfcea0722015-04-27 14:06:13 +0300232 results = load_results(opts.time_period, opts.sensors_result)
Ved-vampir5c7b6142015-04-24 19:49:59 +0300233
Ved-vampirfcea0722015-04-27 14:06:13 +0300234 if opts.debug_ver:
235 tab_all, tab_max = print_bottlenecks(results, critical_values)
236 print "Maximum values on provided metrics"
237 print tab_max
238 print "All loaded values"
239 print tab_all
240
241 else:
242 print find_time_load_percent(results, critical_values)
243
Ved-vampir5c7b6142015-04-24 19:49:59 +0300244
245if __name__ == "__main__":
246 exit(main(sys.argv))