Skip to content

Commit

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

ADD EXAMPLES HERE

Signed-off-by: Tom Hromatka <[email protected]>
  • Loading branch information
drakenclimber committed Apr 25, 2024
1 parent 5589542 commit d19cd9e
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 0 deletions.
75 changes: 75 additions & 0 deletions src/python/libcgroup.pyx.m4
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,81 @@ class LibcgroupPsiList(LibcgroupTree):
else:
self._show_float()

class LibcgroupRealtimeList(LibcgroupTree):
def __init__(self, name, depth=None, limit=None):
super().__init__(name, version=Version.CGROUP_V1, controller='cpu',
depth=depth)

self.rootcg.get_realtime()
self.cglist = list()
self.limit = limit

def walk_action(self, cg):
cg.get_realtime()

if cg.settings['cpu.rt_runtime_us']:
self.cglist.append(cg)

def sort(self):
self.cglist = sorted(self.cglist, reverse=True,
key=lambda cg: cg.realtime_pct)

def show(self, sort=True, verbose=True):
total_pct = 0.0

if sort:
self.sort()

print('{0: >7} {1: >7} {2: >7} {3: <20}'.`format'('RUNTIME', 'PERIOD', 'PERCENT', 'CGROUP'))

for i, cg in enumerate(self.cglist):
# Only add the realtime of the direct children of the root cgroup.
# Grandchildren realtime allocations are accounted for in their
# parents' realtime allocations.
if cg.path[`len'(self.rootcg.path):].count('/') == 1:
total_pct += cg.realtime_pct

if self.limit and i >= self.limit:
continue

print('{0: >7} {1: >7} {2: >5.2f}% {3: <20}'.`format'(
cg.settings['cpu.rt_runtime_us'],
cg.settings['cpu.rt_period_us'],
cg.realtime_pct,
cg.path[`len'(self.start_path):]))

if verbose:
print('\n{0:,} / {1:,} microseconds ({2: >5.2f}%) of the CPU '
'cycles have been allocated to realtime in the root '
'cgroup.'.`format'(
self.rootcg.settings['cpu.rt_runtime_us'],
self.rootcg.settings['cpu.rt_period_us'],
self.rootcg.realtime_pct))

if self.mount == self.start_path:
alloc_path = 'the root cgroup'
tmpcg = self.rootcg
else:
alloc_path = self.rootcg.path[`len'(self.mount):]
tmpcg = self.rootcg

percent_consumed = 100 * total_pct / tmpcg.realtime_pct
print('\n{0:,} of the {1:,} realtime cycles ({2: >5.2f}%) for {3:} '
'have been assigned to children cgroups'.`format'(
int(percent_consumed * tmpcg.settings['cpu.rt_runtime_us'] / 100),
tmpcg.settings['cpu.rt_runtime_us'],
percent_consumed,
alloc_path))

print('\n{0:,} (cpu.rt_runtime_us) / {1:,} (cpu.rt_period_us) '
'microseconds can still be assigned to a child of {2:}'.`format'(
max(int((tmpcg.realtime_pct - total_pct) * 10000), 0),
1000000,
alloc_path))

print('\nNote that the remaining cpu.rt_runtime_us is estimated '
'and could be off by 1 or 2 in either direction.\n')

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 @@ -73,6 +73,7 @@ if ENABLE_PYTHON
EXTRA_DIST = \
cgpsilist.py \
cgpsitree.py \
cgrealtimelist.py \
cgrealtimetree.py
endif

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

from libcgroup import LibcgroupRealtimeList
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('-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('-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 = LibcgroupRealtimeList(args.cgroup, depth=args.depth, limit=args.limit)

cglist.walk()
cglist.show()

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

0 comments on commit d19cd9e

Please sign in to comment.