Motr  M0
queues.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 from addb2db import *
21 import matplotlib.pyplot as plt
22 import matplotlib.gridspec as gridspec
23 import sys
24 
25 def get_queue(query, sfrom: List[str], sto: List[str], filter_key_fields):
26  qlength = []
27  qtime = []
28  ql = 0
29  active = set()
30 
31  item_d = [q for q in query.dicts()]
32  for item in item_d:
33  update = False
34  key = list()
35  for f in filter_key_fields:
36  key.append(item[f])
37  key = tuple(key)
38  if item['state'] in sfrom and key not in active:
39  active.add(key)
40  ql+=1
41  update = True
42  elif item['state'] in sto and key in active:
43  active.remove(key)
44  ql-=1
45  update = True
46  if update:
47  qlength.append(ql)
48  qtime.append(item['time'])
49 
50  return qlength, qtime
51 
52 def plot(query, axs, subplot:int, title: str, sfrom: List[str], sto: List[str], extra: str, extra2, filter_key_fields):
53  qextra = []
54  SEC = 10**9
55 
56  qlength, qtime = get_queue(query, sfrom, sto, filter_key_fields)
57  axs[subplot][extra].plot(qtime, qlength)
58  axs[subplot][extra].set_ylabel(f"{title}")
59 
60  if extra2:
61  item_d2 = [q for q in extra2.dicts()]
62  q1time = [ i['time'] for i in item_d2]
63  q1nr = [ i['NR'] for i in item_d2]
64  axs[subplot][extra].plot(q1time, q1nr)
65 
66 def qs_cli(cli_pids):
67  qs_cli = []
68  for cli_pid in cli_pids:
69  qs_cli.append([
70  { "query": client_req.select().where(client_req.pid==cli_pid).order_by(client_req.time),
71  "title": "Client", "from": ["launched"], "to": ["stable"]},
72  { "query": rpc_req.select(rpc_req, rpc_to_sxid.xid, rpc_to_sxid.session_id).\
73  join(rpc_to_sxid, on=((rpc_req.id == rpc_to_sxid.id)&\
74  (rpc_req.pid == rpc_to_sxid.pid))).\
75  order_by(rpc_req.time).where(rpc_req.pid==cli_pid),
76  "title": "rpc-cli", "from": ["INITIALISED"], "to": ["REPLIED"]}
77  ]
78  )
79  return qs_cli
80 
81 def qs_srv(srv_pids):
82  qs_srv = []
83  for srv_pid in srv_pids:
84  qs_srv.append([
85  { "query": rpc_req.select(rpc_req, sxid_to_rpc.xid, sxid_to_rpc.session_id).\
86  join(sxid_to_rpc, on=((sxid_to_rpc.id==rpc_req.id)&\
87  (sxid_to_rpc.pid==rpc_req.pid))).\
88  order_by(rpc_req.time).where(rpc_req.pid==srv_pid),
89  "title": "rpc-srv", "from": "ACCEPTED", "to": "REPLIED"},
90  { "query": stio_req.select().order_by(stio_req.time).where(stio_req.pid==srv_pid),
91  "title": f"stob-io", "from": ["M0_AVI_AD_PREPARE"], "to": ["M0_AVI_AD_ENDIO"]},
92  { "query": be_tx.select().order_by(be_tx.time).where(be_tx.pid==srv_pid),
93  "title": "TXs", "from": ["prepare"], "to": ["done"]},
94  { "query": be_tx.select().order_by(be_tx.time).where(be_tx.pid==srv_pid),
95  "title": "TXs:active", "from": ["active"], "to": ["closed"]},
96  { "query": fom_req_state.select().order_by(fom_req_state.time).where(fom_req_state.pid==srv_pid),
97  "title": "FOMs", "from": ["Init"], "to": ["Finished"]},
98  { "query": fom_req_state.select().order_by(fom_req_state.time).where(fom_req_state.pid==1010101),
99  "title": "FOMs-act", "from": ["Init"], "to": ["Finished"],
100  "extra2": queues.select(queues.time, queues.avg.alias('NR')).order_by(queues.time).where((queues.pid==srv_pid)&(queues.type=="fom-active")),
101  },
102  { "query": fom_req_state.select().order_by(fom_req_state.time).where(fom_req_state.pid==1010101),
103  "title": "FOMs-runq", "from": ["Init"], "to": ["Finished"],
104  "extra2": queues.select(queues.time, queues.avg.alias('NR')).order_by(queues.time).where((queues.pid==srv_pid)&(queues.type=="runq")),
105  },
106  { "query": fom_req_state.select().order_by(fom_req_state.time).where(fom_req_state.pid==1010101),
107  "title": "FOMs-wail", "from": ["Init"], "to": ["Finished"],
108  "extra2": queues.select(queues.time, queues.avg.alias('NR')).order_by(queues.time).where((queues.pid==srv_pid)&(queues.type=="wail")),
109  },
110  ]
111  )
112 
113  return qs_srv
114 
115 def main(cli_pids, srv_pids):
116  # time convertor
117  CONV={"us": 1000, "ms": 1000*1000}
118  time_unit="ms"
119 
120  cursor={"x0":0, "y0":0, "x1": 0, "y1": 0, "on": False}
121  undo=[]
122  def onpress(event):
123  if event.key == 'a':
124  cursor.update({ "on": True })
125  elif event.key == 'd':
126  if undo:
127  for an in undo.pop():
128  an.remove()
129  event.canvas.draw()
130 
131  def onrelease(event):
132  if not cursor["on"]:
133  return
134  cursor.update({ "x1": event.xdata, "y1": event.ydata })
135  cursor.update({ "on": False })
136 
137  an1=event.inaxes.axvspan(cursor["x0"], cursor["x1"], facecolor='0.9', alpha=.5)
138  an2=event.inaxes.annotate('', xy=(cursor["x0"], cursor["y0"]),
139  xytext=(cursor["x1"], cursor["y0"]),
140  xycoords='data', textcoords='data',
141  arrowprops={'arrowstyle': '|-|'})
142  an3=event.inaxes.annotate(str(round((cursor["x1"]-cursor["x0"])/CONV[time_unit],2))+f" {time_unit}",
143  xy=(min(cursor["x1"], cursor["x0"])+
144  abs(cursor["x1"]-cursor["x0"])/2, 0.5+cursor["y0"]),
145  ha='center', va='center')
146  undo.append([an1, an2, an3])
147  event.canvas.draw()
148 
149  def onclick(event):
150  if not cursor["on"]:
151  return
152  cursor.update({ "x0": event.xdata, "y0": event.ydata })
153 
154  q_cli = qs_cli(cli_pids)
155  q_srv = qs_srv(srv_pids)
156  cli_nrows = len(q_cli) * len(q_cli[0]) if len(q_cli) > 0 else 0
157  srv_nrows = len(q_srv[0]) if len(q_srv) > 0 else 0
158 
159  ncols = 1 if cli_nrows > 0 else 0
160  ncols += len(q_srv)
161 
162  fig, axs = plt.subplots(ncols=ncols, nrows=max(cli_nrows, srv_nrows), sharex=True)
163 
164  fig.canvas.mpl_connect('key_press_event', onpress)
165  fig.canvas.mpl_connect('button_press_event', onclick)
166  fig.canvas.mpl_connect('button_release_event', onrelease)
167 
168  sub = 0
169  if len(q_cli) > 0:
170  for qs in q_cli:
171  for q in qs:
172  filter_fields = ('id', 'pid')
173  if q['title'] == "rpc-cli":
174  filter_fields = ('xid', 'session_id', 'pid')
175  plot(q['query'], axs, sub, q['title'], q['from'], q['to'], 0, q.get("extra2"), filter_fields)
176  sub += 1
177 
178  row = 1 if len(q_cli) > 0 else 0
179  for qs in q_srv:
180  sub = 0
181  for q in qs:
182  filter_fields = ('id', 'pid')
183  if q['title'] == "rpc-srv":
184  filter_fields = ('xid', 'session_id', 'pid')
185  plot(q['query'], axs, sub, q['title'], q['from'], q['to'], row, q.get("extra2"), filter_fields)
186  sub += 1
187 
188  row += 1
189 
190  plt.show()
191 
193  parser = argparse.ArgumentParser(prog=sys.argv[0], description="""
194  queues.py: Display queues.
195  """)
196  parser.add_argument("--cpids", required=False,
197  help="Comma separated list of client PIDs, example: --cpids 42642,43132")
198  parser.add_argument("--spids", required=False,
199  help="Comma separated list of server PIDs, example: --spids 29,78")
200  parser.add_argument("-d", "--db", type=str, default="m0play.db",
201  help="Performance database (m0play.db)")
202 
203  return parser, parser.parse_args()
204 
205 if __name__ == '__main__':
206  parser, args = parse_args()
207 
208  cli_pids = []
209  srv_pids = []
210 
211  if args.cpids:
212  cli_pids = args.cpids.split(",")
213  if args.spids:
214  srv_pids = args.spids.split(",")
215 
216  if len(cli_pids) == 0 and len(srv_pids) == 0:
217  print("At least one PID must be specified")
218  parser.print_help(sys.stderr)
219  exit(1)
220 
221  db_init(args.db)
222  db_connect()
223 
224  main(cli_pids, srv_pids)
225 
226  db_close()
static struct m0_list list
Definition: list.c:144
def qs_cli(cli_pids)
Definition: queues.py:66
def get_queue
Definition: queues.py:25
def db_init(path)
Definition: addb2db.py:314
def plot
Definition: queues.py:52
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 main(cli_pids, srv_pids)
Definition: queues.py:115
def parse_args()
Definition: queues.py:192
def qs_srv(srv_pids)
Definition: queues.py:81
static long long min(long long a, long long b)
Definition: crate.c:191
def db_close()
Definition: addb2db.py:324
Definition: main.py:1