]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/osd_perf_query/module.py
6 from itertools
import groupby
11 from mgr_module
import MgrModule
13 def get_human_readable(bytes
, precision
=2):
14 suffixes
= ['', 'Ki', 'Mi', 'Gi', 'Ti']
16 while bytes
> 1024 and suffix_index
< 4:
17 # increment the index of the suffix
20 bytes
= bytes
/ 1024.0
21 return '%.*f%s' % (precision
, bytes
, suffixes
[suffix_index
])
23 class OSDPerfQuery(MgrModule
):
26 "cmd": "osd perf query add "
27 "name=query,type=CephChoices,"
28 "strings=client_id|rbd_image_id|all_subkeys",
29 "desc": "add osd perf query",
33 "cmd": "osd perf query remove "
34 "name=query_id,type=CephInt,req=true",
35 "desc": "remove osd perf query",
39 "cmd": "osd perf counters get "
40 "name=query_id,type=CephInt,req=true",
41 "desc": "fetch osd perf counters",
48 {'type': 'client_id', 'regex': '^(.+)$'},
50 'performance_counter_descriptors': [
51 'bytes', 'write_ops', 'read_ops', 'write_bytes', 'read_bytes',
52 'write_latency', 'read_latency',
54 'limit': {'order_by': 'bytes', 'max_count': 10},
57 RBD_IMAGE_ID_QUERY
= {
59 {'type': 'pool_id', 'regex': '^(.+)$'},
60 {'type': 'object_name',
61 'regex': '^(?:rbd|journal)_data\.(?:([0-9]+)\.)?([^.]+)\.'},
63 'performance_counter_descriptors': [
64 'bytes', 'write_ops', 'read_ops', 'write_bytes', 'read_bytes',
65 'write_latency', 'read_latency',
67 'limit': {'order_by': 'bytes', 'max_count': 10},
72 {'type': 'client_id', 'regex': '^(.*)$'},
73 {'type': 'client_address', 'regex': '^(.*)$'},
74 {'type': 'pool_id', 'regex': '^(.*)$'},
75 {'type': 'namespace', 'regex': '^(.*)$'},
76 {'type': 'osd_id', 'regex': '^(.*)$'},
77 {'type': 'pg_id', 'regex': '^(.*)$'},
78 {'type': 'object_name', 'regex': '^(.*)$'},
79 {'type': 'snap_id', 'regex': '^(.*)$'},
81 'performance_counter_descriptors': [
82 'write_ops', 'read_ops',
88 def handle_command(self
, inbuf
, cmd
):
89 if cmd
['prefix'] == "osd perf query add":
90 if cmd
['query'] == 'rbd_image_id':
91 query
= self
.RBD_IMAGE_ID_QUERY
92 elif cmd
['query'] == 'client_id':
93 query
= self
.CLIENT_ID_QUERY
95 query
= self
.ALL_SUBKEYS_QUERY
96 query_id
= self
.add_osd_perf_query(query
)
98 return -errno
.EINVAL
, "", "Invalid query"
99 self
.queries
[query_id
] = [query
, time()]
100 return 0, str(query_id
), "added query " + cmd
['query'] + " with id " + str(query_id
)
101 elif cmd
['prefix'] == "osd perf query remove":
102 if cmd
['query_id'] not in self
.queries
:
103 return -errno
.ENOENT
, "", "unknown query id " + str(cmd
['query_id'])
104 self
.remove_osd_perf_query(cmd
['query_id'])
105 del self
.queries
[cmd
['query_id']]
106 return 0, "", "removed query with id " + str(cmd
['query_id'])
107 elif cmd
['prefix'] == "osd perf counters get":
108 if cmd
['query_id'] not in self
.queries
:
109 return -errno
.ENOENT
, "", "unknown query id " + str(cmd
['query_id'])
111 query
= self
.queries
[cmd
['query_id']][0]
112 res
= self
.get_osd_perf_counters(cmd
['query_id'])
114 last_update
= self
.queries
[cmd
['query_id']][1]
115 descriptors
= query
['performance_counter_descriptors']
117 if query
== self
.RBD_IMAGE_ID_QUERY
:
118 column_names
= ["POOL_ID", "RBD IMAGE ID"]
120 column_names
= [sk
['type'].upper() for sk
in query
['key_descriptor']]
121 for d
in descriptors
:
125 elif d
in ['write_bytes', 'read_bytes']:
127 elif d
in ['write_latency', 'read_latency']:
129 column_names
.append(desc
.upper())
131 table
= prettytable
.PrettyTable(tuple(column_names
),
132 hrules
=prettytable
.FRAME
)
133 table
.left_padding_width
= 0
134 table
.right_padding_width
= 2
136 if query
== self
.RBD_IMAGE_ID_QUERY
:
138 # {'k': [['3'], ['', '16fe5b5a8435e']],
139 # 'c': [[1024, 0], [1, 0], ...]}
140 # pool id fixup: if the object_name regex has matched pool id
141 # use it as the image pool id
142 for c
in res
['counters']:
144 c
['k'][0][0] = c
['k'][1][0]
145 # group by (pool_id, image_id)
147 res
['counters'].sort(key
=lambda c
: [c
['k'][0][0], c
['k'][1][1]])
148 for key
, group
in groupby(res
['counters'],
149 lambda c
: [c
['k'][0][0], c
['k'][1][1]]):
150 counters
= [[0, 0] for x
in descriptors
]
152 for i
in range(len(counters
)):
153 counters
[i
][0] += c
['c'][i
][0]
154 counters
[i
][1] += c
['c'][i
][1]
155 processed
.append({'k' : key
, 'c' : counters
})
158 # {'k': [['client.94348']], 'c': [[1024, 0], [1, 0], ...]}
159 processed
= res
['counters']
161 max_count
= len(processed
)
163 if 'max_count' in query
['limit']:
164 max_count
= query
['limit']['max_count']
165 if 'order_by' in query
['limit']:
166 i
= descriptors
.index(query
['limit']['order_by'])
167 processed
.sort(key
=lambda x
: x
['c'][i
][0], reverse
=True)
168 for c
in processed
[:max_count
]:
169 if query
== self
.RBD_IMAGE_ID_QUERY
:
172 row
= [sk
[0] for sk
in c
['k']]
174 for i
in range(len(descriptors
)):
175 if descriptors
[i
] in ['bytes']:
177 elif descriptors
[i
] in ['write_bytes', 'read_bytes']:
178 bps
= counters
[i
][0] / (now
- last_update
)
179 row
.append(get_human_readable(bps
))
180 elif descriptors
[i
] in ['write_latency', 'read_latency']:
182 if counters
[i
][1] > 0:
183 lat
= 1.0 * counters
[i
][0] / counters
[i
][1] / 1000000
184 row
.append("%.2f" % lat
)
186 row
.append("%d" % counters
[i
][0])
189 msg
= "counters for the query id %d for the last %d sec" % \
190 (cmd
['query_id'], now
- last_update
)
191 self
.queries
[cmd
['query_id']][1] = now
193 return 0, table
.get_string() + "\n", msg
195 raise NotImplementedError(cmd
['prefix'])