Skip to content

Commit

Permalink
python: tools: Add tool for displaying a list of PSI data
Browse files Browse the repository at this point in the history
Add a tool for displaying the PSI data for a cgroup hierarchy.

$ ./src/tools/cgpsilist.py -c cpu -d 1 -f some-avg10 -l 10 -t 0
some-avg10 PSI CGROUP
          0.00 /sys-fs-fuse-connections.mount
          0.00 /sys-kernel-config.mount
          0.00 /sys-kernel-debug.mount
          0.00 /dev-mqueue.mount
          0.00 /user.slice
          0.00 /sys-kernel-tracing.mount
          0.00 /init.scope
          0.00 /system.slice
          0.00 /proc-sys-fs-binfmt_misc.mount
          0.00 /machine.slice

$ ./src/tools/cgpsilist.py -c cpu -d 1 -f full-total -l 10 -t 0
full-total PSI CGROUP
     421304531 /user.slice
      62664636 /system.slice
        118774 /init.scope
           109 /sys-kernel-debug.mount
             7 /dev-hugepages.mount
             3 /sys-fs-fuse-connections.mount
             3 /sys-kernel-tracing.mount
             3 /proc-sys-fs-binfmt_misc.mount
             0 /sys-kernel-config.mount
             0 /dev-mqueue.mount

Signed-off-by: Tom Hromatka <[email protected]>
  • Loading branch information
drakenclimber committed Apr 25, 2024
1 parent 480eb73 commit 5e533a0
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 0 deletions.
53 changes: 53 additions & 0 deletions src/python/libcgroup.pyx.m4
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,59 @@ class LibcgroupList(LibcgroupTree):
cgpid.pidstats['Command'], cgpid.pidstats[self.metric],
cgpid.cgroup))

class LibcgroupPsiList(LibcgroupTree):
def __init__(self, name, controller='cpu', depth=None, psi_field='some-avg10',
threshold=None, limit=None):
super().__init__(name, version=Version.CGROUP_V2, controller=controller,
depth=depth)

self.controller = controller
self.psi_field = psi_field
self.cglist = list()
self.threshold = threshold
self.limit = limit

def walk_action(self, cg):
cg.get_psi(self.controller)

if not self.threshold:
self.cglist.append(cg)
elif cg.psi[self.psi_field] >= self.threshold:
self.cglist.append(cg)

def sort(self):
self.cglist = sorted(self.cglist, reverse=True,
key=lambda cg: cg.psi[self.psi_field])

def _show_float(self):
print('{0: >10} {1: >3} {2: <16}'.`format'(self.psi_field, 'PSI', 'CGROUP'))

for i, cg in enumerate(self.cglist):
if self.limit and i >= self.limit:
break

print(' {0: 6.2f} {1: <16}'.`format'(cg.psi[self.psi_field],
cg.path[`len'(self.start_path):]))

def _show_int(self):
print('{0: >10} {1: >3} {2: <16}'.`format'(self.psi_field, 'PSI', 'CGROUP'))

for i, cg in enumerate(self.cglist):
if self.limit and i >= self.limit:
break

print(' {0: 11d} {1: <16}'.`format'(cg.psi[self.psi_field],
cg.path[`len'(self.start_path):]))

def show(self, sort=True):
if sort:
self.sort()

if 'total' in self.psi_field:
self._show_int()
else:
self._show_float()

class LibcgroupPid(object):
def __init__(self, pid, command=None):
self.pid = pid
Expand Down
1 change: 1 addition & 0 deletions src/tools/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ cgsnapshot_CFLAGS = $(CODE_COVERAGE_CFLAGS) $(EXTRA_CFLAGS)

if ENABLE_PYTHON
EXTRA_DIST = \
cgpsilist.py \
cgpsitree.py
endif

Expand Down
42 changes: 42 additions & 0 deletions src/tools/cgpsilist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1-only
#
# Display a list of cgroups and their specified PSI metrics
#
# Copyright (c) 2021-2024 Oracle and/or its affiliates.
# Author: Tom Hromatka <[email protected]>
#

from libcgroup import LibcgroupPsiList
import argparse
import os

def parse_args():
parser = argparse.ArgumentParser('Libcgroup PSI List')
parser.add_argument('-C', '--cgroup', type=str, required=False, default=None,
help='Relative path to the cgroup of interest, e.g. machine.slice/foo.scope')
parser.add_argument('-c', '--controller', required=True,
help='PSI controller data to display. cpu, io, or memory')
parser.add_argument('-f', '--field', required=False, default='some-avg10',
help='Which PSI field to display, e.g. some-avg10, full-avg60, ...')
parser.add_argument('-d', '--depth', type=int, required=False, default=None,
help='Depth to recurse into the cgroup path. 0 == only this cgroup, 1 == this cgroup and its children, ...')
parser.add_argument('-t', '--threshold', type=float, required=False, default=1.0,
help='Only list cgroups whose PSI exceeds this percentage')
parser.add_argument('-l', '--limit', type=int, required=False, default=None,
help='Only display the first N cgroups. If not provided, all cgroups that match are displayed')

args = parser.parse_args()

return args

def main(args):
cglist = LibcgroupPsiList(args.cgroup, controller=args.controller, depth=args.depth,
psi_field=args.field, threshold=args.threshold, limit=args.limit)

cglist.walk()
cglist.show()

if __name__ == '__main__':
args = parse_args()
main(args)

0 comments on commit 5e533a0

Please sign in to comment.