New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ceph: perfcounter priorities and daemonperf updates to use them #14793
Changes from all commits
3a634ec
fd30646
25dcc96
5b6e791
6216f21
2b1410b
9db636c
cc441b4
fe109b4
5b743f3
334f175
cecdadd
814aae9
fc1bd7e
9d9cd5d
51809cc
583e6f6
b297e72
3fa8bb1
a734e34
dada2c5
0aa0975
94cf1b0
714bd6d
00cb8f2
9e3d7d9
5e8bdb2
8b0bdb0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,7 @@ Build-Depends: bc, | |
python (>= 2.7), | ||
python-all-dev, | ||
python-nose, | ||
python-prettytable, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. debian packaging does not run "make check", so we can remove There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing is, if it's not in build-depends, make check fails, because the target host doesn't have the package to run the tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed. we debated about "make check" dependencies machinery before, iirc. but no acceptable result back then. i should learn to live with it. |
||
python-setuptools, | ||
python-sphinx, | ||
python3-all-dev, | ||
|
@@ -363,7 +364,8 @@ Depends: librbd1 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, | |
python-rbd (= ${binary:Version}), | ||
python-rgw (= ${binary:Version}), | ||
${python:Depends}, | ||
python-requests | ||
python-requests, | ||
python-prettytable | ||
Conflicts: ceph-client-tools | ||
Replaces: ceph-client-tools, | ||
ceph (<< 10), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,15 @@ FLAG_NOFORWARD = (1 << 0) | |
FLAG_OBSOLETE = (1 << 1) | ||
FLAG_DEPRECATED = (1 << 2) | ||
|
||
# priorities from src/common/perf_counters.h | ||
PRIO_CRITICAL = 10 | ||
PRIO_INTERESTING = 8 | ||
PRIO_USEFUL = 5 | ||
PRIO_UNINTERESTING = 2 | ||
PRIO_DEBUGONLY = 0 | ||
|
||
PRIO_DEFAULT = PRIO_USEFUL | ||
|
||
# Make life easier on developers: | ||
# If in src/, and .libs and pybind exist here, assume we're running | ||
# from a Ceph source dir and tweak PYTHONPATH and LD_LIBRARY_PATH | ||
|
@@ -266,10 +275,15 @@ ping <mon.id> Send simple presence/life test to a mon | |
<mon.id> may be 'mon.*' for all mons | ||
daemon {type.id|path} <cmd> | ||
Same as --admin-daemon, but auto-find admin socket | ||
daemonperf {type.id | path} [<interval>] [<count>] | ||
daemonperf {type.id | path} [stat-pats] [priority] [<interval>] [<count>] | ||
daemonperf {type.id | path} list|ls [stat-pats] [priority] | ||
Get selected perf stats from daemon/admin socket | ||
Optional shell-glob comma-delim match string stat-pats | ||
Optional selection priority (can abbreviate name): | ||
critical, interesting, useful, noninteresting, debug | ||
List shows a table of all available stats | ||
Run <count> times (default forever), | ||
once per <interval> seconds (default 1) | ||
once per <interval> seconds (default 1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why added an extra space here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to show that it's part of the preceding line more clearly |
||
""", file=sys.stdout) | ||
|
||
|
||
|
@@ -565,6 +579,134 @@ def ping_monitor(cluster_handle, name, timeout): | |
print(s) | ||
return 0 | ||
|
||
|
||
def maybe_daemon_command(parsed_args, childargs): | ||
""" | ||
Check if --admin-socket, daemon, or daemonperf command | ||
if it is, returns (boolean handled, return code if handled == True) | ||
""" | ||
|
||
daemon_perf = False | ||
sockpath = None | ||
if parsed_args.admin_socket: | ||
sockpath = parsed_args.admin_socket | ||
elif len(childargs) > 0 and childargs[0] in ["daemon", "daemonperf"]: | ||
daemon_perf = (childargs[0] == "daemonperf") | ||
# Treat "daemon <path>" or "daemon <name>" like --admin_daemon <path> | ||
# Handle "daemonperf <path>" the same but requires no trailing args | ||
require_args = 2 if daemon_perf else 3 | ||
if len(childargs) >= require_args: | ||
if childargs[1].find('/') >= 0: | ||
sockpath = childargs[1] | ||
else: | ||
# try resolve daemon name | ||
try: | ||
sockpath = ceph_conf(parsed_args, 'admin_socket', | ||
childargs[1]) | ||
except Exception as e: | ||
print('Can\'t get admin socket path: ' + str(e), file=sys.stderr) | ||
return True, errno.EINVAL | ||
# for both: | ||
childargs = childargs[2:] | ||
else: | ||
print('{0} requires at least {1} arguments'.format(childargs[0], require_args), | ||
file=sys.stderr) | ||
return True, errno.EINVAL | ||
|
||
if sockpath and daemon_perf: | ||
return True, daemonperf(childargs, sockpath) | ||
elif sockpath: | ||
try: | ||
raw_write(admin_socket(sockpath, childargs, parsed_args.output_format)) | ||
except Exception as e: | ||
print('admin_socket: {0}'.format(e), file=sys.stderr) | ||
return True, errno.EINVAL | ||
return True, 0 | ||
|
||
return False, 0 | ||
|
||
|
||
def isnum(s): | ||
try: | ||
float(s) | ||
return True | ||
except ValueError: | ||
return False | ||
|
||
def daemonperf(childargs, sockpath): | ||
""" | ||
Handle daemonperf command; returns errno or 0 | ||
|
||
daemonperf <daemon> [priority string] [statpats] [interval] [count] | ||
daemonperf <daemon> list|ls [statpats] | ||
""" | ||
|
||
interval = 1 | ||
count = None | ||
statpats = None | ||
priority = None | ||
do_list = False | ||
|
||
def prio_from_name(arg): | ||
|
||
PRIOMAP = { | ||
'critical': PRIO_CRITICAL, | ||
'interesting': PRIO_INTERESTING, | ||
'useful': PRIO_USEFUL, | ||
'uninteresting': PRIO_UNINTERESTING, | ||
'debugonly': PRIO_DEBUGONLY, | ||
} | ||
|
||
if arg in PRIOMAP: | ||
return PRIOMAP[arg] | ||
# allow abbreviation | ||
for name, val in PRIOMAP.items(): | ||
if name.startswith(arg): | ||
return val | ||
return None | ||
|
||
# consume and analyze non-numeric args | ||
while len(childargs) and not isnum(childargs[0]): | ||
arg = childargs.pop(0) | ||
# 'list'? | ||
if arg in ['list', 'ls']: | ||
do_list = True; | ||
continue | ||
# prio? | ||
prio = prio_from_name(arg) | ||
if prio is not None: | ||
priority = prio | ||
continue | ||
# statpats | ||
statpats = arg.split(',') | ||
|
||
if priority is None: | ||
priority = PRIO_DEFAULT | ||
|
||
if len(childargs) > 0: | ||
try: | ||
interval = float(childargs.pop(0)) | ||
if interval < 0: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, why not just print the error message and return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because the exception can also come from float() (bad format), and this way both errors exit the same way There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oic. |
||
raise ValueError | ||
except ValueError: | ||
print('daemonperf: interval should be a positive number', file=sys.stderr) | ||
return errno.EINVAL | ||
|
||
if len(childargs) > 0: | ||
arg = childargs.pop(0) | ||
if (not isnum(arg)) or (int(arg) < 0): | ||
print('daemonperf: count should be a positive integer', file=sys.stderr) | ||
return errno.EINVAL | ||
count = int(arg) | ||
|
||
watcher = DaemonWatcher(sockpath, statpats, priority) | ||
if do_list: | ||
watcher.list() | ||
else: | ||
watcher.run(interval, count) | ||
|
||
return 0 | ||
|
||
### | ||
# main | ||
### | ||
|
@@ -610,58 +752,9 @@ def main(): | |
|
||
format = parsed_args.output_format | ||
|
||
daemon_perf = False | ||
sockpath = None | ||
if parsed_args.admin_socket: | ||
sockpath = parsed_args.admin_socket | ||
elif len(childargs) > 0 and childargs[0] in ["daemon", "daemonperf"]: | ||
daemon_perf = (childargs[0] == "daemonperf") | ||
# Treat "daemon <path>" or "daemon <name>" like --admin_daemon <path> | ||
# Handle "daemonperf <path>" the same but requires no trailing args | ||
require_args = 2 if daemon_perf else 3 | ||
if len(childargs) >= require_args: | ||
if childargs[1].find('/') >= 0: | ||
sockpath = childargs[1] | ||
else: | ||
# try resolve daemon name | ||
try: | ||
sockpath = ceph_conf(parsed_args, 'admin_socket', | ||
childargs[1]) | ||
except Exception as e: | ||
print('Can\'t get admin socket path: ' + str(e), file=sys.stderr) | ||
return errno.EINVAL | ||
# for both: | ||
childargs = childargs[2:] | ||
else: | ||
print('{0} requires at least {1} arguments'.format(childargs[0], require_args), | ||
file=sys.stderr) | ||
return errno.EINVAL | ||
|
||
if sockpath and daemon_perf: | ||
interval = 1 | ||
count = None | ||
if len(childargs) > 0: | ||
try: | ||
interval = float(childargs[0]) | ||
if interval < 0: | ||
raise ValueError | ||
except ValueError: | ||
print('daemonperf: interval should be a positive number', file=sys.stderr) | ||
return errno.EINVAL | ||
if len(childargs) > 1: | ||
if not childargs[1].isdigit(): | ||
print('daemonperf: count should be a positive integer', file=sys.stderr) | ||
return errno.EINVAL | ||
count = int(childargs[1]) | ||
DaemonWatcher(sockpath).run(interval, count) | ||
return 0 | ||
elif sockpath: | ||
try: | ||
raw_write(admin_socket(sockpath, childargs, format)) | ||
except Exception as e: | ||
print('admin_socket: {0}'.format(e), file=sys.stderr) | ||
return errno.EINVAL | ||
return 0 | ||
done, ret = maybe_daemon_command(parsed_args, childargs) | ||
if done: | ||
return ret | ||
|
||
timeout = None | ||
if parsed_args.cluster_timeout: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we run
ceph
at build-time? "make_check" is disabled by default. maybe we can guard this line like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I assume the same thing applies as for Debian, in that the package needs to be installed for make check to work. Since the make check builds don't install the built packages to pull in prettytable via Requires, there's nothing else to do it that I know of. (if there is some sort of "make check dependencies" mechanism I'm happy to learn about it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so the consumer of this line is install-deps.sh actually. i am far from an expert of
dnf
or its builddep plugin. so guess this is the best way to document the "make check" dependencies at this moment.