Motr  M0
hist.py
Go to the documentation of this file.
1 #
2 # Copyright (c) 2020 Seagate Technology LLC and/or its Affiliates
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 # For any questions about this software or licensing,
17 # please email opensource@seagate.com or cortx-questions@seagate.com.
18 #
19 
20 import os
21 import sys
22 import yaml
23 import peewee
24 import logging
25 import importlib
26 from addb2db import *
27 import matplotlib.pyplot as plt
28 from itertools import zip_longest as zipl
29 
30 # time convertor
31 CONV={"us": 1000, "ms": 1000*1000}
32 # list of plugins
33 PLUG={}
34 
35 def parse_args():
36  parser = argparse.ArgumentParser(prog=sys.argv[0],
37  formatter_class=argparse.RawDescriptionHelpFormatter,
38  description="""hist.py: creates timings histograms from performance samples.""",
39  epilog="""Examples:
40  1. list of the plugins
41  # python3 hist.py -l
42 
43  2. histogram of fom_req plugin
44  # python3 hist.py -f png -o write.png -v -u ms -p fom_req
45  "[[auth, zero-copy-initiate], [zero-copy-initiate, tx_open],
46  [tx_open, stobio-launch], [stobio-launch, network-buffer-release],
47  [tx_commit, finish]]"
48  """)
49  parser.add_argument('--db', type=str, required=False, default="m0play.db")
50  group0 = parser.add_mutually_exclusive_group(required=True)
51  group0.add_argument("-p", "--plugin", type=str, help="plugin name")
52  group0.add_argument("-l", "--list", action='store_true', help="prints plugin list")
53  parser.add_argument("-v", "--verbose", action='count', default=0)
54  parser.add_argument("-u", "--time-unit", choices=['ms','us'], default='us')
55  parser.add_argument("-o", "--out", type=str, default="img.svg")
56  parser.add_argument("-f", "--fmt", type=str, default="svg")
57  parser.add_argument("-r", "--rows", type=int, default=1)
58  parser.add_argument("-s", "--size", nargs=2, type=int, default=[12,4])
59  parser.add_argument("range", nargs='?', help="""
60  "[[from1, to1, [rend]], ... [from_n, to_n, [rend_n]]]"
61  """)
62 
63  return parser.parse_args()
64 
65 def query(from_, to_, range_end, plug_name, time_unit):
66  q = PLUG[plug_name](from_, to_)
67  logging.info(f"plug={plug_name} query={q}")
68 
69  DIV = CONV[time_unit]
70  fields = []
71  with DB.atomic():
72  cursor = DB.execute_sql(q)
73  fields = [f[0]/DIV for f in cursor.fetchall()]
74 
75  max_f = round(max(fields), 2)
76  min_f = round(min(fields), 2)
77  avg_f = round(sum(fields) / len(fields), 2)
78  ag_stat = f"total max/avg/min {max_f}/{avg_f}/{min_f}"
79 
80  in_range = [f for f in fields if range_end is None or f < range_end]
81  plt.hist(in_range, 50)
82 
83  plt.title(f"{from_} \n {to_}")
84 
85  fs = len(fields)
86  ir = len(in_range)
87  stat = f"total/range/%: {fs}/{ir}/{round(ir/fs,2)}"
88  logging.info(stat)
89  plt.xlabel(f"time({time_unit}) \n {stat} \n {ag_stat}")
90  plt.ylabel(f"frequency \n")
91 
92  plt.tight_layout()
93 
94 
95 def hist(db_name, plug, range, fmt="svg", out="img.svg", time_unit="us", rows=1, size=(12,4)):
96  stages = yaml.safe_load(range)
97  db_init(db_name)
98  db_connect()
99 
100  plt.figure(figsize=size)
101  nr_stages = len(stages)
102  columns = nr_stages // rows + (1 if nr_stages % rows > 0 else 0)
103  for nr,s in enumerate(stages, 1):
104  r = dict(zipl(["from", "to", "end"], s, fillvalue=None))
105  plt.subplot(rows, columns, nr)
106  plt.grid(True)
107  query(r["from"], r["to"], r["end"], plug, time_unit)
108 
109  db_close()
110  plt.savefig(fname=out, format=fmt)
111 
112 def load():
113  for _,_,file in os.walk("."):
114  for f in file:
115  if f.endswith(".py") and f.startswith("hist__"):
116  try:
117  plug = importlib.import_module(os.path.splitext(f)[0])
118  PLUG[plug.attr['name']] = plug.query
119  logging.info(f"Plugin loaded: file={f}, " \
120  f"plugin={plug.attr['name']}")
121  except:
122  logging.debug(f"File {f} is not a plugin")
123 
124 if __name__ == "__main__":
125  args=parse_args()
126 
127  verbosity = { 0: logging.WARN, 1: logging.INFO, 2: logging.DEBUG }
128  logging.basicConfig(format='%(asctime)s - %(levelname)-8s %(message)s',
129  level=verbosity[args.verbose if args.verbose < max(verbosity)
130  else max(verbosity)])
131  load()
132  if args.list:
133  print("Loaded plugins:")
134  for k in PLUG.keys():
135  print(k)
136 
137  if args.plugin:
138  hist(args.db, args.plugin, args.range, args.fmt, args.out, args.time_unit, args.rows, args.size)
def load()
Definition: hist.py:112
def query(from_, to_, range_end, plug_name, time_unit)
Definition: hist.py:65
def hist(db_name, plug, range, fmt="svg", out="img.svg", time_unit="us", rows=1, size=(12, 4))
Definition: hist.py:95
static int sum
Definition: rwlock.c:53
def db_init(path)
Definition: addb2db.py:314
def db_connect()
Definition: addb2db.py:321
static M0_UNUSED void print(struct m0_be_list *list)
Definition: list.c:186
static long long max(long long a, long long b)
Definition: crate.c:196
def parse_args()
Definition: hist.py:35
static long long min(long long a, long long b)
Definition: crate.c:191
def db_close()
Definition: addb2db.py:324
Definition: hist.py:1