diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-15 13:39:12 +0530 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-15 13:39:12 +0530 |
| commit | a60ce761d99ff2d9eefe33374c5f20726465a140 (patch) | |
| tree | a7883dcce89453fe59d7cf614620e0b20bea3895 /scripts | |
| parent | f20e2fdaaeb74330a6c5d65af22a8c47409a7a91 (diff) | |
| parent | 87bd2ad568e15b90d5f7d4bcd70342d05dad649c (diff) | |
Merge tag 'timers-core-2026-06-13' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip
Pull timer core updates from Thomas Gleixner:
"Updates for the time/timer core subsystem:
- Harden the user space controllable hrtimer interfaces further to
protect against unpriviledged DoS attempts by arming timers in the
past.
- Add per-capacity hierarchies to the timer migration code to prevent
timer migration accross different capacity domains. This code has
been disabled last minute as there is a pathological problem with
SoCs which advertise a larger number of capacity domains. The
problem is under investigation and the code won't be active before
v7.3, but that turned out to be less intrusive than a full revert
as it preserves the preparatory steps and allows people to work on
the final resolution
- Export time namespace functionality as a recent user can be built
as a module.
- Initialize the jiffies clocksource before using it. The recent
hardening against time moving backward requires that the related
members of struct clocksource have been initialized, otherwise it
clamps the readout to 0, which makes time stand sill and causes
boot delays.
- Fix a more than twenty year old PID reference count leak in an
error path of the POSIX CPU timer code.
- The usual small fixes, improvements and cleanups all over the
place"
* tag 'timers-core-2026-06-13' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip: (31 commits)
posix-cpu-timers: Fix pid refcount leak in do_cpu_nanosleep() error path
time/jiffies: Register jiffies clocksource before usage
timers/migration: Temporarily disable per capacity hierarchies
timers/migration: Turn tmigr_hierarchy level_list into a flexible array
timers/migration: Deactivate per-capacity hierarchies under nohz_full
timers/migration: Fix hotplug migrator selection target on asymetric capacity machines
ntsync: Honour caller's time namespace for absolute MONOTONIC timeouts
time/namespace: Export init_time_ns and do_timens_ktime_to_host()
timers/migration: Update stale @online doc to @available
timers: Fix flseep() typo in kernel-doc comment
hrtimer: Fix the bogus return type of __hrtimer_start_range_ns()
hrtimer: Return ktime_t from hrtimer_get_next_event()/hrtimer_next_event_without()
clocksource: Clean up clocksource_update_freq() functions
alarmtimer: Remove stale return description from alarm_handle_timer()
selftests/posix_timers: Use CLOCK_THREAD_CPUTIME_ID for ITIMER_PROF measurements
scripts/timers: Add timer_migration_tree.py
timers/migration: Handle capacity in connect tracepoints
timers/migration: Split per-capacity hierarchies
timers/migration: Track CPUs in a hierarchy
timers/migration: Abstract out hierarchy to prepare for CPU capacity awareness
...
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/timer_migration_tree.py | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/scripts/timer_migration_tree.py b/scripts/timer_migration_tree.py new file mode 100755 index 000000000000..faac9de854bd --- /dev/null +++ b/scripts/timer_migration_tree.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +""" +Draw the timer migration tree. + +1) Boot with trace_event==tmigr_connect_cpu_parent,tmigr_connect_child_parent +2) ./timer_migration_tree.py < /sys/kernel/tracing/trace +""" + +import re, sys +from ete3 import Tree + +class Node: + def __init__(self, group): + self.group = group + self.children = [] + self.parent = None + self.num_children = 0 + self.groupmask = 0 + self.lvl = -1 + + def set_groupmask(self, groupmask): + self.groupmask = groupmask + + def set_parent(self, parent): + self.parent = parent + + def add_child(self, child): + self.children.append(child) + + def set_lvl(self, lvl): + self.lvl = lvl + + def set_numa(self, numa): + self.numa = numa + + def set_num_children(self, num_children): + self.num_children = num_children + + def __repr__(self): + if self.parent: + parent_grp = self.parent.group + else: + parent_grp = "-" + return "Group: %s mask: %s parent: %s lvl: %d numa: %d num_children: %d" % (self.group, self.groupmask, parent_grp, self.lvl, self.numa, self.num_children) + +hierarchies = { } + +def get_hierarchy(capacity): + if capacity not in hierarchies: + hierarchies[capacity] = {} + return hierarchies[capacity] + +def get_node(capacity, group): + hier = get_hierarchy(capacity) + if group in hier: + return hier[group] + else: + n = Node(group) + hier[group] = n + return n + +def tmigr_connect_cpu_parent(ts, line): + s = re.search("tmigr_connect_cpu_parent: cpu=([0-9]+) groupmask=([0-9a-zA-Z]+) parent=([0-9a-zA-Z]+) lvl=([0-9]+) numa=([-]?[0-9]+) capacity=([-]?[0-9]+) num_children=([0-9]+)", line) + if s is None: + return False + (cpu, groupmask, parent, lvl, numa, capacity, num_children) = (int(s.group(1)), s.group(2), s.group(3), int(s.group(4)), int(s.group(5)), int(s.group(6)), int(s.group(7))) + n = get_node(capacity, cpu) + p = get_node(capacity, parent) + n.set_parent(p) + n.set_groupmask(groupmask) + n.set_lvl(-1) + p.set_lvl(lvl) + p.set_numa(numa) + n.set_numa(numa) + p.set_num_children(num_children) + p.add_child(n) + +def tmigr_connect_child_parent(ts, line): + s = re.search("tmigr_connect_child_parent: group=([0-9a-zA-Z]+) groupmask=([0-9a-zA-Z]+) parent=([0-9a-zA-Z]+) lvl=([0-9]+) numa=([-]?[0-9]+) capacity=([-]?[0-9]+) num_children=([0-9]+)", line) + if s is None: + return False + (group, groupmask, parent, lvl, numa, capacity, num_children) = (s.group(1), s.group(2), s.group(3), int(s.group(4)), int(s.group(5)), int(s.group(6)), int(s.group(7))) + n = get_node(capacity, group) + p = get_node(capacity, parent) + n.set_parent(p) + n.set_groupmask(groupmask) + p.set_lvl(lvl) + p.set_numa(numa) + p.set_num_children(num_children) + p.add_child(n) + +def populate(enode, node): + enode = enode.add_child(name = node.group) + enode.add_feature("groupmask", "m:%s" % node.groupmask) + enode.add_feature("lvl", "lvl:%d" % node.lvl) + enode.add_feature("numa", "node %d" % node.numa) + enode.add_feature("num_children", "c=%d" % node.num_children) + for child in node.children: + populate(enode, child) + +if __name__ == "__main__": + for line in sys.stdin: + s = re.search("([0-9]+[.][0-9]{6}): (.+?)$", line, re.S) + if s is not None: + if tmigr_connect_cpu_parent(float(s.group(1)), s.group(2)): + continue + if tmigr_connect_child_parent(float(s.group(1)), s.group(2)): + continue + + for cap in hierarchies: + h = hierarchies[cap] + print("Tree for capacity %d" % cap) + for k in h: + n = h[k] + while n.parent != None: + n = n.parent + root = Tree() + populate(root, n) + print(root.get_ascii(show_internal=True, attributes=["name", "numa", "lvl"])) + break |
