Motr  M0
io_req.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 sys
21 from addb2db import *
22 from typing import List, Dict
23 from graphviz import Digraph
24 from req_utils import *
25 
26 
27 def graph_build(relations, ext_graph: Digraph=None, is_cob: bool=False):
28  if is_cob:
29  t = "cob"
30  else:
31  t = "ioo"
32 
33  graph = ext_graph if ext_graph is not None else Digraph(
34  strict=True, format='png', node_attr = {'shape': 'plaintext'})
35 
36  # relation | from | to | table or direct | flags
37  # |table/mapping|table/mapping| mapping |
38  schema = [("client_id", "client_id", f"{t}_id" , f"client_to_{t}", "C"),
39  (f"{t}_id" , f"{t}_id" , "rpc_id" , f"{t}_to_rpc" , "C"),
40  ("crpc_id" , "crpc_id" , "srpc_id" , "" , "C1"),
41  ("crpc_id" , "rpc_id" , "bulk_id" , "bulk_to_rpc" , "Cs"),
42  ("srpc_id" , "srpc_id" , "fom_id" , "" , "S1"),
43  ("fom_id" , "fom_id" , "stio_id" , "fom_to_stio" , "S"),
44  ("stio_id" , "" , "" , "" , "Sl"),
45  ("fom_id" , "fom_id" , "tx_id" , "" , "S1"),
46  ("tx_id" , "" , "" , "" , "Sl")]
47  # flags: '1' - one to one mapping, 's' - stash samples, 'l' - leaf element
48 
49  graph_add_relations(graph, relations, schema)
50 
51  if ext_graph is None:
52  graph.render(filename="{}_graph_{}".format(t, relations[0]['client_id']))
53 
54  return graph
55 
56 # ================================================================================
57 # obtain some samples
58 
59 query_template="""
60 SELECT
61 
62 DISTINCT({io_req_type}_to_rpc.rpc_id),
63 client_to_{io_req_type}.client_id,
64 client_to_{io_req_type}.{io_req_type}_id,
65 rpc_to_sxid.opcode,
66 rpc_to_sxid.xid, rpc_to_sxid.session_id,
67 sxid_to_rpc.xid, sxid_to_rpc.session_id,
68 fom_desc.rpc_sm_id, fom_desc.fom_sm_id, fom_desc.fom_state_sm_id,
69 fom_to_tx.tx_id,
70 fom_to_stio.stio_id,
71 tx_to_gr.gr_id,
72 client_to_{io_req_type}.pid,
73 fom_desc.pid
74 
75 FROM client_to_{io_req_type}
76 JOIN {io_req_type}_to_rpc on client_to_{io_req_type}.{io_req_type}_id={io_req_type}_to_rpc.{io_req_type}_id
77 JOIN rpc_to_sxid on rpc_to_sxid.id={io_req_type}_to_rpc.rpc_id
78 JOIN sxid_to_rpc on rpc_to_sxid.xid=sxid_to_rpc.xid AND rpc_to_sxid.session_id=sxid_to_rpc.session_id
79 JOIN fom_desc on sxid_to_rpc.id=fom_desc.rpc_sm_id
80 LEFT JOIN fom_to_tx on fom_desc.fom_sm_id=fom_to_tx.fom_id
81 LEFT JOIN fom_to_stio on fom_desc.fom_sm_id=fom_to_stio.fom_id
82 LEFT JOIN tx_to_gr on fom_to_tx.tx_id=tx_to_gr.tx_id
83 
84 WHERE sxid_to_rpc.opcode in {opcodes} and rpc_to_sxid.opcode in {opcodes}
85 AND rpc_to_sxid.xid > 0
86 AND rpc_to_sxid.session_id > 0
87 {pid_filter}
88 AND client_to_{io_req_type}.pid={io_req_type}_to_rpc.pid AND client_to_{io_req_type}.pid=rpc_to_sxid.pid
89 
90 AND sxid_to_rpc.pid=fom_desc.pid
91 AND (fom_to_stio.stio_id is NULL OR fom_desc.pid=fom_to_stio.pid)
92 AND (fom_to_tx.tx_id is NULL OR fom_desc.pid=fom_to_tx.pid)
93 AND (tx_to_gr.gr_id is NULL OR fom_desc.pid=tx_to_gr.pid)
94 
95 AND client_to_{io_req_type}.client_id={client_id};
96 """
97 
98 def get_timelines(client_id: str, grange: int, client_pid: int=None, create_attr_graph: bool=False,
99  export_only: bool=False, ext_graph: Digraph=None, is_cob: bool=False):
100  time_table = []
101  queue_table = []
102  queue_start_time = []
103  client_start_time = 0
104  attr_graph = None
105 
106  if is_cob:
107  io_req_type = "cob"
108  opcodes = "(45,46,47,128,130)"
109  io_req_table = cob_req
110  else:
111  io_req_type = "ioo"
112  opcodes = "(41,42,45,46,47)"
113  io_req_table = ioo_req
114 
115  pid_filter = f"AND client_to_{io_req_type}.pid={client_pid}" if client_pid is not None else ""
116  query = query_template.format(io_req_type=io_req_type, opcodes=opcodes,
117  client_id=client_id, pid_filter=pid_filter)
118 
119  with DB.atomic():
120  cursor = DB.execute_sql(query)
121  fields = list(cursor.fetchall())
122  labels = ("crpc_id", "client_id", f"{io_req_type}_id", "opcode", "cxid",
123  "csess", "sxid", "ssess", "srpc_id", "fom_id",
124  "fom_state_id", "tx_id", "stio_id", "gr_id",
125  "cli_pid", "srv_pid")
126  relations = [dict(zip(labels, f)) for f in fields]
127 
128  #print(relations)
129 
130  client_id = set([o['client_id'] for o in relations]).pop()
131  io_req_id = set([o[f'{io_req_type}_id'] for o in relations]).pop()
132  rpc_fom_s = set([(o['opcode'],
133  o['cli_pid'],
134  o['srv_pid'],
135  o['crpc_id'],
136  o['srpc_id'],
137  o['fom_id'],
138  o['fom_state_id'],
139  o['tx_id'],
140  o['stio_id'],
141  o['gr_id']) for o in relations])
142  # 1
143  client_req_d = query2dlist(
144  client_req.select().where(client_req.id==client_id) if client_pid is None else
145  client_req.select().where((client_req.id==client_id)&(client_req.pid==client_pid)))
146  times_tag_append(client_req_d, 'op', f"client {client_id}")
147  time_table.append(client_req_d)
148  client_start_time=min([t['time'] for t in client_req_d])
149 
150  #2
151  io_req_d = query2dlist(
152  io_req_table.select().where(io_req_table.id==io_req_id) if client_pid is None else
153  io_req_table.select().where((io_req_table.id==io_req_id)&(io_req_table.pid==client_pid)))
154  times_tag_append(io_req_d, 'op', f"{io_req_type} {io_req_id}")
155  time_table.append(io_req_d)
156 
157  #3, 4, 5, 6
158  for opcode, cli_pid, srv_pid, crpc_id, srpc_id, fom_id, fom_state_id, tx_id, stio_id, gr_id in rpc_fom_s:
159  for tag,(rpc_id,pid) in {"c": (crpc_id, cli_pid),
160  "s": (srpc_id, srv_pid)}.items():
161  rpc_req_d = query2dlist(rpc_req.select().where((rpc_req.id==rpc_id)&
162  (rpc_req.pid==pid)))
163  times_tag_append(rpc_req_d, 'op', f"{tag}rpc[{opcode}] {rpc_id}")
164  time_table.append(rpc_req_d)
165 
166  fom_req_st_d = query2dlist(fom_req_state.select().where((fom_req_state.id==fom_state_id)&
167  (fom_req_state.pid==srv_pid)))
168  times_tag_append(fom_req_st_d, 'op', f"fom-state {fom_state_id}")
169  time_table.append(fom_req_st_d)
170 
171  fom_req_d = query2dlist(fom_req.select().where((fom_req.id==fom_id)&
172  (fom_req.pid==srv_pid)))
173  times_tag_append(fom_req_d, 'op', f"fom-phase {fom_id}")
174  time_table.append(fom_req_d)
175 
176  if stio_id:
177  stio_d = query2dlist(stio_req.select().where((stio_req.id==stio_id)&
178  (stio_req.pid==srv_pid)))
179  times_tag_append(stio_d, 'op', f"stob-io {stio_id}")
180  time_table.append(stio_d)
181 
182  if tx_id:
183  be_tx_d = query2dlist(be_tx.select().where((be_tx.id==tx_id)&
184  (be_tx.pid==srv_pid)))
185  times_tag_append(be_tx_d, 'op', f"be_tx {tx_id}")
186  time_table.append(be_tx_d)
187 
188  left=[]
189  right=[]
190  if grange[0]>0:
191  left = query2dlist(fom_req.select().where((fom_req.id==gr_id)&
192  (fom_req.pid==srv_pid)&
193  (fom_req.time<client_start_time)).limit(grange[0]))
194  if grange[1]>0:
195  right = query2dlist(fom_req.select().where((fom_req.id==gr_id)&
196  (fom_req.pid==srv_pid)&
197  (fom_req.time>=client_start_time)).limit(grange[1]))
198  if grange[0]>0 or grange[1]>0:
199  gr_d = [*left, *right]
200  times_tag_append(gr_d, 'op', f"tx-gr-phase {gr_id}")
201  time_table.append(gr_d)
202 
203  # process client requests and subrequests
204  # time_table=[t for t in time_table if t != []] ### XXX: filter non-exsitent txs!
205 
206  if not export_only:
207  prepare_time_table(time_table)
208 
209  # attr
210  if create_attr_graph:
211  print("Building attributes graph...")
212  attr_graph = graph_build(relations, ext_graph, is_cob)
213 
214  return time_table, queue_table, queue_start_time, client_start_time, attr_graph
215 
216 
218  parser = argparse.ArgumentParser(prog=sys.argv[0], description="""
219  io_req.py: Display significant performance counters for Motr stack.
220  """)
221  parser.add_argument("-p", "--pid", type=int, default=None,
222  help="Client pid to get requests for")
223  parser.add_argument("-c", "--cob", action='store_true',
224  help="Whether client request relates to COB")
225  parser.add_argument("-m", "--maximize", action='store_true', help="Display in maximised window")
226  parser.add_argument("-q", "--queues", action='store_true', help="Display queues also")
227  parser.add_argument("-r", "--qrange", type=int, default=10,
228  help="Limit quantity of queue-related samples")
229  parser.add_argument("-g", "--grange", default=[0, 0],
230  nargs=2, metavar=('left', 'right'), type=int,
231  help="Limit quantity of tx group-related samples")
232  parser.add_argument("-a", "--attr", action='store_true', help="Create attributes graph")
233  parser.add_argument("-v", "--verbose", action='count', default=0)
234  parser.add_argument("-u", "--time-unit", choices=['ms','us'], default='us',
235  help="Default time unit")
236  parser.add_argument("-d", "--db", type=str, default="m0play.db",
237  help="Performance database (m0play.db)")
238  parser.add_argument("client_id", type=str, help="Client request id")
239 
240  return parser.parse_args()
241 
242 if __name__ == '__main__':
243  args=parse_args()
244 
245  db_init(args.db)
246  db_connect()
247 
248  print("Getting timelines...")
249 
250  time_table, queue_table, queue_start_time, client_start_time, _ = \
251  get_timelines(args.client_id, args.grange, args.pid, args.attr, False, None, args.cob)
252 
253  if args.queues:
254  fill_queue_table(queue_table, queue_start_time)
255 
256  db_close()
257 
258  print("Plotting timelines...")
259 
260  draw_timelines(time_table, queue_table, client_start_time, queue_start_time,
261  args.time_unit, args.queues, args.maximize)
262 
263 # ================================================================================
static struct m0_list list
Definition: list.c:144
def get_timelines
Definition: io_req.py:98
def prepare_time_table(time_table)
Definition: req_utils.py:51
def query2dlist(model)
Definition: req_utils.py:68
def graph_build
Definition: io_req.py:27
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
def times_tag_append
Definition: req_utils.py:74
def parse_args()
Definition: io_req.py:217
def fill_queue_table
Definition: req_utils.py:174
format
Definition: hist.py:128
static long long min(long long a, long long b)
Definition: crate.c:191
def db_close()
Definition: addb2db.py:324
def graph_add_relations
Definition: req_utils.py:227
def draw_timelines
Definition: req_utils.py:105