1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3 4""" 5Draw the timer migration tree. 6 71) Boot with trace_event==tmigr_connect_cpu_parent,tmigr_connect_child_parent 82) ./timer_migration_tree.py < /sys/kernel/tracing/trace 9""" 10 11import re, sys 12from ete3 import Tree 13 14class Node: 15 def __init__(self, group): 16 self.group = group 17 self.children = [] 18 self.parent = None 19 self.num_children = 0 20 self.groupmask = 0 21 self.lvl = -1 22 23 def set_groupmask(self, groupmask): 24 self.groupmask = groupmask 25 26 def set_parent(self, parent): 27 self.parent = parent 28 29 def add_child(self, child): 30 self.children.append(child) 31 32 def set_lvl(self, lvl): 33 self.lvl = lvl 34 35 def set_numa(self, numa): 36 self.numa = numa 37 38 def set_num_children(self, num_children): 39 self.num_children = num_children 40 41 def __repr__(self): 42 if self.parent: 43 parent_grp = self.parent.group 44 else: 45 parent_grp = "-" 46 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) 47 48hierarchies = { } 49 50def get_hierarchy(capacity): 51 if capacity not in hierarchies: 52 hierarchies[capacity] = {} 53 return hierarchies[capacity] 54 55def get_node(capacity, group): 56 hier = get_hierarchy(capacity) 57 if group in hier: 58 return hier[group] 59 else: 60 n = Node(group) 61 hier[group] = n 62 return n 63 64def tmigr_connect_cpu_parent(ts, line): 65 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) 66 if s is None: 67 return False 68 (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))) 69 n = get_node(capacity, cpu) 70 p = get_node(capacity, parent) 71 n.set_parent(p) 72 n.set_groupmask(groupmask) 73 n.set_lvl(-1) 74 p.set_lvl(lvl) 75 p.set_numa(numa) 76 n.set_numa(numa) 77 p.set_num_children(num_children) 78 p.add_child(n) 79 80def tmigr_connect_child_parent(ts, line): 81 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) 82 if s is None: 83 return False 84 (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))) 85 n = get_node(capacity, group) 86 p = get_node(capacity, parent) 87 n.set_parent(p) 88 n.set_groupmask(groupmask) 89 p.set_lvl(lvl) 90 p.set_numa(numa) 91 p.set_num_children(num_children) 92 p.add_child(n) 93 94def populate(enode, node): 95 enode = enode.add_child(name = node.group) 96 enode.add_feature("groupmask", "m:%s" % node.groupmask) 97 enode.add_feature("lvl", "lvl:%d" % node.lvl) 98 enode.add_feature("numa", "node %d" % node.numa) 99 enode.add_feature("num_children", "c=%d" % node.num_children) 100 for child in node.children: 101 populate(enode, child) 102 103if __name__ == "__main__": 104 for line in sys.stdin: 105 s = re.search("([0-9]+[.][0-9]{6}): (.+?)$", line, re.S) 106 if s is not None: 107 if tmigr_connect_cpu_parent(float(s.group(1)), s.group(2)): 108 continue 109 if tmigr_connect_child_parent(float(s.group(1)), s.group(2)): 110 continue 111 112 for cap in hierarchies: 113 h = hierarchies[cap] 114 print("Tree for capacity %d" % cap) 115 for k in h: 116 n = h[k] 117 while n.parent != None: 118 n = n.parent 119 root = Tree() 120 populate(root, n) 121 print(root.get_ascii(show_internal=True, attributes=["name", "numa", "lvl"])) 122 break 123