xref: /linux-6.15/scripts/gdb/linux/timerlist.py (revision 747cd84f)
1442284a8SStephen Boyd# SPDX-License-Identifier: GPL-2.0
2442284a8SStephen Boyd#
3442284a8SStephen Boyd# Copyright 2019 Google LLC.
4442284a8SStephen Boyd
5442284a8SStephen Boydimport binascii
6442284a8SStephen Boydimport gdb
7442284a8SStephen Boyd
8442284a8SStephen Boydfrom linux import constants
9442284a8SStephen Boydfrom linux import cpus
10442284a8SStephen Boydfrom linux import rbtree
11442284a8SStephen Boydfrom linux import utils
12442284a8SStephen Boyd
13442284a8SStephen Boydtimerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type()
14442284a8SStephen Boydhrtimer_type = utils.CachedType("struct hrtimer").get_type()
15442284a8SStephen Boyd
16442284a8SStephen Boyd
17442284a8SStephen Boyddef ktime_get():
18442284a8SStephen Boyd    """Returns the current time, but not very accurately
19442284a8SStephen Boyd
20442284a8SStephen Boyd    We can't read the hardware timer itself to add any nanoseconds
21442284a8SStephen Boyd    that need to be added since we last stored the time in the
22442284a8SStephen Boyd    timekeeper. But this is probably good enough for debug purposes."""
23442284a8SStephen Boyd    tk_core = gdb.parse_and_eval("&tk_core")
24442284a8SStephen Boyd
25442284a8SStephen Boyd    return tk_core['timekeeper']['tkr_mono']['base']
26442284a8SStephen Boyd
27442284a8SStephen Boyd
28442284a8SStephen Boyddef print_timer(rb_node, idx):
29442284a8SStephen Boyd    timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(),
30442284a8SStephen Boyd                                    "node")
31442284a8SStephen Boyd    timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node")
32442284a8SStephen Boyd
33442284a8SStephen Boyd    function = str(timer['function']).split(" ")[1].strip("<>")
34442284a8SStephen Boyd    softexpires = timer['_softexpires']
35442284a8SStephen Boyd    expires = timer['node']['expires']
36442284a8SStephen Boyd    now = ktime_get()
37442284a8SStephen Boyd
38442284a8SStephen Boyd    text = " #{}: <{}>, {}, ".format(idx, timer, function)
39442284a8SStephen Boyd    text += "S:{:02x}\n".format(int(timer['state']))
40442284a8SStephen Boyd    text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format(
41442284a8SStephen Boyd            softexpires, expires, softexpires - now, expires - now)
42442284a8SStephen Boyd    return text
43442284a8SStephen Boyd
44442284a8SStephen Boyd
45442284a8SStephen Boyddef print_active_timers(base):
46*747cd84fSPeng Liu    curr = base['active']['rb_root']['rb_leftmost']
47442284a8SStephen Boyd    idx = 0
48442284a8SStephen Boyd    while curr:
49442284a8SStephen Boyd        yield print_timer(curr, idx)
50442284a8SStephen Boyd        curr = rbtree.rb_next(curr)
51442284a8SStephen Boyd        idx += 1
52442284a8SStephen Boyd
53442284a8SStephen Boyd
54442284a8SStephen Boyddef print_base(base):
55442284a8SStephen Boyd    text = " .base:       {}\n".format(base.address)
56442284a8SStephen Boyd    text += " .index:      {}\n".format(base['index'])
57442284a8SStephen Boyd
58442284a8SStephen Boyd    text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution)
59442284a8SStephen Boyd
60442284a8SStephen Boyd    text += " .get_time:   {}\n".format(base['get_time'])
61442284a8SStephen Boyd    if constants.LX_CONFIG_HIGH_RES_TIMERS:
62442284a8SStephen Boyd        text += "  .offset:     {} nsecs\n".format(base['offset'])
63442284a8SStephen Boyd    text += "active timers:\n"
64442284a8SStephen Boyd    text += "".join([x for x in print_active_timers(base)])
65442284a8SStephen Boyd    return text
66442284a8SStephen Boyd
67442284a8SStephen Boyd
68442284a8SStephen Boyddef print_cpu(hrtimer_bases, cpu, max_clock_bases):
69442284a8SStephen Boyd    cpu_base = cpus.per_cpu(hrtimer_bases, cpu)
70442284a8SStephen Boyd    jiffies = gdb.parse_and_eval("jiffies_64")
71442284a8SStephen Boyd    tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched")
72442284a8SStephen Boyd    ts = cpus.per_cpu(tick_sched_ptr, cpu)
73442284a8SStephen Boyd
74442284a8SStephen Boyd    text = "cpu: {}\n".format(cpu)
75442284a8SStephen Boyd    for i in xrange(max_clock_bases):
76442284a8SStephen Boyd        text += " clock {}:\n".format(i)
77442284a8SStephen Boyd        text += print_base(cpu_base['clock_base'][i])
78442284a8SStephen Boyd
79442284a8SStephen Boyd        if constants.LX_CONFIG_HIGH_RES_TIMERS:
80442284a8SStephen Boyd            fmts = [("  .{}   : {} nsecs", 'expires_next'),
81442284a8SStephen Boyd                    ("  .{}    : {}", 'hres_active'),
82442284a8SStephen Boyd                    ("  .{}      : {}", 'nr_events'),
83442284a8SStephen Boyd                    ("  .{}     : {}", 'nr_retries'),
84442284a8SStephen Boyd                    ("  .{}       : {}", 'nr_hangs'),
85442284a8SStephen Boyd                    ("  .{}  : {}", 'max_hang_time')]
86442284a8SStephen Boyd            text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts])
87442284a8SStephen Boyd            text += "\n"
88442284a8SStephen Boyd
89442284a8SStephen Boyd        if constants.LX_CONFIG_TICK_ONESHOT:
90442284a8SStephen Boyd            fmts = [("  .{}      : {}", 'nohz_mode'),
91442284a8SStephen Boyd                    ("  .{}      : {} nsecs", 'last_tick'),
92442284a8SStephen Boyd                    ("  .{}   : {}", 'tick_stopped'),
93442284a8SStephen Boyd                    ("  .{}   : {}", 'idle_jiffies'),
94442284a8SStephen Boyd                    ("  .{}     : {}", 'idle_calls'),
95442284a8SStephen Boyd                    ("  .{}    : {}", 'idle_sleeps'),
96442284a8SStephen Boyd                    ("  .{} : {} nsecs", 'idle_entrytime'),
97442284a8SStephen Boyd                    ("  .{}  : {} nsecs", 'idle_waketime'),
98442284a8SStephen Boyd                    ("  .{}  : {} nsecs", 'idle_exittime'),
99442284a8SStephen Boyd                    ("  .{} : {} nsecs", 'idle_sleeptime'),
100442284a8SStephen Boyd                    ("  .{}: {} nsecs", 'iowait_sleeptime'),
101442284a8SStephen Boyd                    ("  .{}   : {}", 'last_jiffies'),
102442284a8SStephen Boyd                    ("  .{}     : {}", 'next_timer'),
103442284a8SStephen Boyd                    ("  .{}   : {} nsecs", 'idle_expires')]
104442284a8SStephen Boyd            text += "\n".join([s.format(f, ts[f]) for s, f in fmts])
105442284a8SStephen Boyd            text += "\njiffies: {}\n".format(jiffies)
106442284a8SStephen Boyd
107442284a8SStephen Boyd        text += "\n"
108442284a8SStephen Boyd
109442284a8SStephen Boyd    return text
110442284a8SStephen Boyd
111442284a8SStephen Boyd
112442284a8SStephen Boyddef print_tickdevice(td, cpu):
113442284a8SStephen Boyd    dev = td['evtdev']
114442284a8SStephen Boyd    text = "Tick Device: mode:     {}\n".format(td['mode'])
115442284a8SStephen Boyd    if cpu < 0:
116442284a8SStephen Boyd            text += "Broadcast device\n"
117442284a8SStephen Boyd    else:
118442284a8SStephen Boyd            text += "Per CPU device: {}\n".format(cpu)
119442284a8SStephen Boyd
120442284a8SStephen Boyd    text += "Clock Event Device: "
121442284a8SStephen Boyd    if dev == 0:
122442284a8SStephen Boyd            text += "<NULL>\n"
123442284a8SStephen Boyd            return text
124442284a8SStephen Boyd
125442284a8SStephen Boyd    text += "{}\n".format(dev['name'])
126442284a8SStephen Boyd    text += " max_delta_ns:   {}\n".format(dev['max_delta_ns'])
127442284a8SStephen Boyd    text += " min_delta_ns:   {}\n".format(dev['min_delta_ns'])
128442284a8SStephen Boyd    text += " mult:           {}\n".format(dev['mult'])
129442284a8SStephen Boyd    text += " shift:          {}\n".format(dev['shift'])
130442284a8SStephen Boyd    text += " mode:           {}\n".format(dev['state_use_accessors'])
131442284a8SStephen Boyd    text += " next_event:     {} nsecs\n".format(dev['next_event'])
132442284a8SStephen Boyd
133442284a8SStephen Boyd    text += " set_next_event: {}\n".format(dev['set_next_event'])
134442284a8SStephen Boyd
135442284a8SStephen Boyd    members = [('set_state_shutdown', " shutdown: {}\n"),
136442284a8SStephen Boyd               ('set_state_periodic', " periodic: {}\n"),
137442284a8SStephen Boyd               ('set_state_oneshot', " oneshot:  {}\n"),
138442284a8SStephen Boyd               ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
139442284a8SStephen Boyd               ('tick_resume', " resume:   {}\n")]
140442284a8SStephen Boyd    for member, fmt in members:
141442284a8SStephen Boyd        if dev[member]:
142442284a8SStephen Boyd            text += fmt.format(dev[member])
143442284a8SStephen Boyd
144442284a8SStephen Boyd    text += " event_handler:  {}\n".format(dev['event_handler'])
145442284a8SStephen Boyd    text += " retries:        {}\n".format(dev['retries'])
146442284a8SStephen Boyd
147442284a8SStephen Boyd    return text
148442284a8SStephen Boyd
149442284a8SStephen Boyd
150442284a8SStephen Boyddef pr_cpumask(mask):
151442284a8SStephen Boyd    nr_cpu_ids = 1
152442284a8SStephen Boyd    if constants.LX_NR_CPUS > 1:
153442284a8SStephen Boyd        nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
154442284a8SStephen Boyd
155442284a8SStephen Boyd    inf = gdb.inferiors()[0]
156442284a8SStephen Boyd    bits = mask['bits']
157442284a8SStephen Boyd    num_bytes = (nr_cpu_ids + 7) / 8
158442284a8SStephen Boyd    buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
159442284a8SStephen Boyd    buf = binascii.b2a_hex(buf)
160442284a8SStephen Boyd
161442284a8SStephen Boyd    chunks = []
162442284a8SStephen Boyd    i = num_bytes
163442284a8SStephen Boyd    while i > 0:
164442284a8SStephen Boyd        i -= 1
165442284a8SStephen Boyd        start = i * 2
166442284a8SStephen Boyd        end = start + 2
167442284a8SStephen Boyd        chunks.append(buf[start:end])
168442284a8SStephen Boyd        if i != 0 and i % 4 == 0:
169442284a8SStephen Boyd            chunks.append(',')
170442284a8SStephen Boyd
171442284a8SStephen Boyd    extra = nr_cpu_ids % 8
172442284a8SStephen Boyd    if 0 < extra <= 4:
173442284a8SStephen Boyd        chunks[0] = chunks[0][0]  # Cut off the first 0
174442284a8SStephen Boyd
175442284a8SStephen Boyd    return "".join(chunks)
176442284a8SStephen Boyd
177442284a8SStephen Boyd
178442284a8SStephen Boydclass LxTimerList(gdb.Command):
179442284a8SStephen Boyd    """Print /proc/timer_list"""
180442284a8SStephen Boyd
181442284a8SStephen Boyd    def __init__(self):
182442284a8SStephen Boyd        super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
183442284a8SStephen Boyd
184442284a8SStephen Boyd    def invoke(self, arg, from_tty):
185442284a8SStephen Boyd        hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
186442284a8SStephen Boyd        max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
187442284a8SStephen Boyd
188442284a8SStephen Boyd        text = "Timer List Version: gdb scripts\n"
189442284a8SStephen Boyd        text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
190442284a8SStephen Boyd        text += "now at {} nsecs\n".format(ktime_get())
191442284a8SStephen Boyd
192442284a8SStephen Boyd        for cpu in cpus.each_online_cpu():
193442284a8SStephen Boyd            text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
194442284a8SStephen Boyd
195442284a8SStephen Boyd        if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
196442284a8SStephen Boyd            if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
197442284a8SStephen Boyd                bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
198442284a8SStephen Boyd                text += print_tickdevice(bc_dev, -1)
199442284a8SStephen Boyd                text += "\n"
200442284a8SStephen Boyd                mask = gdb.parse_and_eval("tick_broadcast_mask")
201442284a8SStephen Boyd                mask = pr_cpumask(mask)
202442284a8SStephen Boyd                text += "tick_broadcast_mask: {}\n".format(mask)
203442284a8SStephen Boyd                if constants.LX_CONFIG_TICK_ONESHOT:
204442284a8SStephen Boyd                    mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
205442284a8SStephen Boyd                    mask = pr_cpumask(mask)
206442284a8SStephen Boyd                    text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
207442284a8SStephen Boyd                text += "\n"
208442284a8SStephen Boyd
209442284a8SStephen Boyd            tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
210442284a8SStephen Boyd            for cpu in cpus.each_online_cpu():
211442284a8SStephen Boyd                tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
212442284a8SStephen Boyd                text += print_tickdevice(tick_dev, cpu)
213442284a8SStephen Boyd                text += "\n"
214442284a8SStephen Boyd
215442284a8SStephen Boyd        gdb.write(text)
216442284a8SStephen Boyd
217442284a8SStephen Boyd
218442284a8SStephen BoydLxTimerList()
219