Add/generalize abstractions in arc_summary3

Code for interfacing with procfs for kstats and tunables is Linux-
specific. A more generic interface can be used for the abstractions of
loading kstats and various tunable parameters, allowing other platforms
to implement the functions cleanly. In a similar vein, determining the
ZFS/SPL version can be abstracted away in order for other platforms to
provide their own implementations of this function.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Matt Macy <mmacy@FreeBSD.org>
Signed-off-by: Ryan Moeller <ryan@ixsystems.com>
Closes #9279
This commit is contained in:
Ryan Moeller 2019-09-10 16:27:53 -04:00 committed by Brian Behlendorf
parent 6122948b3b
commit 562e1c0327

View File

@ -83,6 +83,60 @@ parser.add_argument('-s', '--section', dest='section', help=SECTION_HELP)
ARGS = parser.parse_args() ARGS = parser.parse_args()
def get_params(basepath):
"""Collect information on the Solaris Porting Layer (SPL) or the
tunables, depending on the PATH given. Does not check if PATH is
legal.
"""
result = {}
for name in os.listdir(basepath):
path = os.path.join(basepath, name)
with open(path) as f:
value = f.read()
result[name] = value.strip()
return result
def get_spl_params():
return get_params(SPL_PATH)
def get_tunable_params():
return get_params(TUNABLES_PATH)
def get_vdev_params():
return get_params(TUNABLES_PATH)
def get_version_impl(request):
# The original arc_summary called /sbin/modinfo/{spl,zfs} to get
# the version information. We switch to /sys/module/{spl,zfs}/version
# to make sure we get what is really loaded in the kernel
command = ["cat", "/sys/module/{0}/version".format(request)]
req = request.upper()
# The recommended way to do this is with subprocess.run(). However,
# some installed versions of Python are < 3.5, so we offer them
# the option of doing it the old way (for now)
info = ''
if 'run' in dir(subprocess):
info = subprocess.run(command, stdout=subprocess.PIPE,
universal_newlines=True)
version = info.stdout.strip()
else:
info = subprocess.check_output(command, universal_newlines=True)
version = info.strip()
return version
def load_kstats(section):
path = os.path.join(PROC_PATH, section)
with open(path) as f:
return list(f)[2:] # Get rid of header
def cleanup_line(single_line): def cleanup_line(single_line):
"""Format a raw line of data from /proc and isolate the name value """Format a raw line of data from /proc and isolate the name value
part, returning a tuple with each. Currently, this gets rid of the part, returning a tuple with each. Currently, this gets rid of the
@ -252,33 +306,10 @@ def get_kstats():
""" """
result = {} result = {}
secs = SECTION_PATHS.values()
for section in secs: for section in SECTION_PATHS.values():
if section not in result:
with open(PROC_PATH+section, 'r') as proc_location: result[section] = load_kstats(section)
lines = [line for line in proc_location]
del lines[0:2] # Get rid of header
result[section] = lines
return result
def get_spl_tunables(PATH):
"""Collect information on the Solaris Porting Layer (SPL) or the
tunables, depending on the PATH given. Does not check if PATH is
legal.
"""
result = {}
parameters = os.listdir(PATH)
for name in parameters:
with open(PATH+name, 'r') as para_file:
value = para_file.read()
result[name] = value.strip()
return result return result
@ -339,33 +370,14 @@ def get_descriptions(request):
def get_version(request): def get_version(request):
"""Get the version number of ZFS or SPL on this machine for header. """Get the version number of ZFS or SPL on this machine for header.
Returns an error string, but does not raise an error, if we can't Returns an error string, but does not raise an error, if we can't
get the ZFS/SPL version via modinfo. get the ZFS/SPL version.
""" """
if request not in ('spl', 'zfs'): if request not in ('spl', 'zfs'):
error_msg = '(ERROR: "{0}" requested)'.format(request) error_msg = '(ERROR: "{0}" requested)'.format(request)
return error_msg return error_msg
# The original arc_summary called /sbin/modinfo/{spl,zfs} to get return get_version_impl(request)
# the version information. We switch to /sys/module/{spl,zfs}/version
# to make sure we get what is really loaded in the kernel
command = ["cat", "/sys/module/{0}/version".format(request)]
req = request.upper()
version = "(Can't get {0} version)".format(req)
# The recommended way to do this is with subprocess.run(). However,
# some installed versions of Python are < 3.5, so we offer them
# the option of doing it the old way (for now)
info = ''
if 'run' in dir(subprocess):
info = subprocess.run(command, stdout=subprocess.PIPE,
universal_newlines=True)
version = info.stdout.strip()
else:
info = subprocess.check_output(command, universal_newlines=True)
version = info.strip()
return version
def print_header(): def print_header():
@ -711,7 +723,7 @@ def section_spl(*_):
and/or descriptions. This does not use kstats. and/or descriptions. This does not use kstats.
""" """
spls = get_spl_tunables(SPL_PATH) spls = get_spl_params()
keylist = sorted(spls.keys()) keylist = sorted(spls.keys())
print('Solaris Porting Layer (SPL):') print('Solaris Porting Layer (SPL):')
@ -737,7 +749,7 @@ def section_tunables(*_):
descriptions. This does not use kstasts. descriptions. This does not use kstasts.
""" """
tunables = get_spl_tunables(TUNABLES_PATH) tunables = get_tunable_params()
keylist = sorted(tunables.keys()) keylist = sorted(tunables.keys())
print('Tunables:') print('Tunables:')
@ -765,7 +777,7 @@ def section_vdev(kstats_dict):
# harmful. When this is the case, we just skip the whole entry. See # harmful. When this is the case, we just skip the whole entry. See
# https://github.com/zfsonlinux/zfs/blob/master/module/zfs/vdev_cache.c # https://github.com/zfsonlinux/zfs/blob/master/module/zfs/vdev_cache.c
# for details # for details
tunables = get_spl_tunables(TUNABLES_PATH) tunables = get_vdev_params()
if tunables['zfs_vdev_cache_size'] == '0': if tunables['zfs_vdev_cache_size'] == '0':
print('VDEV cache disabled, skipping section\n') print('VDEV cache disabled, skipping section\n')