xref: /linux-6.15/scripts/gdb/linux/timerlist.py (revision a633a4b8)
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):
46747cd84fSPeng 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)
757362042fSPeng Liu    for i in range(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:
90*a633a4b8SKuan-Ying Lee            TS_FLAG_STOPPED = 1 << 1
91*a633a4b8SKuan-Ying Lee            TS_FLAG_NOHZ = 1 << 4
92*a633a4b8SKuan-Ying Lee            text += f"  .{'nohz':15s}: {int(bool(ts['flags'] & TS_FLAG_NOHZ))}\n"
93*a633a4b8SKuan-Ying Lee            text += f"  .{'last_tick':15s}: {ts['last_tick']}\n"
94*a633a4b8SKuan-Ying Lee            text += f"  .{'tick_stopped':15s}: {int(bool(ts['flags'] & TS_FLAG_STOPPED))}\n"
95*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_jiffies':15s}: {ts['idle_jiffies']}\n"
96*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_calls':15s}: {ts['idle_calls']}\n"
97*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_sleeps':15s}: {ts['idle_sleeps']}\n"
98*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_entrytime':15s}: {ts['idle_entrytime']} nsecs\n"
99*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_waketime':15s}: {ts['idle_waketime']} nsecs\n"
100*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_exittime':15s}: {ts['idle_exittime']} nsecs\n"
101*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_sleeptime':15s}: {ts['idle_sleeptime']} nsecs\n"
102*a633a4b8SKuan-Ying Lee            text += f"  .{'iowait_sleeptime':15s}: {ts['iowait_sleeptime']} nsecs\n"
103*a633a4b8SKuan-Ying Lee            text += f"  .{'last_jiffies':15s}: {ts['last_jiffies']}\n"
104*a633a4b8SKuan-Ying Lee            text += f"  .{'next_timer':15s}: {ts['next_timer']}\n"
105*a633a4b8SKuan-Ying Lee            text += f"  .{'idle_expires':15s}: {ts['idle_expires']} nsecs\n"
106442284a8SStephen Boyd            text += "\njiffies: {}\n".format(jiffies)
107442284a8SStephen Boyd
108442284a8SStephen Boyd        text += "\n"
109442284a8SStephen Boyd
110442284a8SStephen Boyd    return text
111442284a8SStephen Boyd
112442284a8SStephen Boyd
113442284a8SStephen Boyddef print_tickdevice(td, cpu):
114442284a8SStephen Boyd    dev = td['evtdev']
115442284a8SStephen Boyd    text = "Tick Device: mode:     {}\n".format(td['mode'])
116442284a8SStephen Boyd    if cpu < 0:
117442284a8SStephen Boyd            text += "Broadcast device\n"
118442284a8SStephen Boyd    else:
119442284a8SStephen Boyd            text += "Per CPU device: {}\n".format(cpu)
120442284a8SStephen Boyd
121442284a8SStephen Boyd    text += "Clock Event Device: "
122442284a8SStephen Boyd    if dev == 0:
123442284a8SStephen Boyd            text += "<NULL>\n"
124442284a8SStephen Boyd            return text
125442284a8SStephen Boyd
126442284a8SStephen Boyd    text += "{}\n".format(dev['name'])
127442284a8SStephen Boyd    text += " max_delta_ns:   {}\n".format(dev['max_delta_ns'])
128442284a8SStephen Boyd    text += " min_delta_ns:   {}\n".format(dev['min_delta_ns'])
129442284a8SStephen Boyd    text += " mult:           {}\n".format(dev['mult'])
130442284a8SStephen Boyd    text += " shift:          {}\n".format(dev['shift'])
131442284a8SStephen Boyd    text += " mode:           {}\n".format(dev['state_use_accessors'])
132442284a8SStephen Boyd    text += " next_event:     {} nsecs\n".format(dev['next_event'])
133442284a8SStephen Boyd
134442284a8SStephen Boyd    text += " set_next_event: {}\n".format(dev['set_next_event'])
135442284a8SStephen Boyd
136442284a8SStephen Boyd    members = [('set_state_shutdown', " shutdown: {}\n"),
137442284a8SStephen Boyd               ('set_state_periodic', " periodic: {}\n"),
138442284a8SStephen Boyd               ('set_state_oneshot', " oneshot:  {}\n"),
139442284a8SStephen Boyd               ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
140442284a8SStephen Boyd               ('tick_resume', " resume:   {}\n")]
141442284a8SStephen Boyd    for member, fmt in members:
142442284a8SStephen Boyd        if dev[member]:
143442284a8SStephen Boyd            text += fmt.format(dev[member])
144442284a8SStephen Boyd
145442284a8SStephen Boyd    text += " event_handler:  {}\n".format(dev['event_handler'])
146442284a8SStephen Boyd    text += " retries:        {}\n".format(dev['retries'])
147442284a8SStephen Boyd
148442284a8SStephen Boyd    return text
149442284a8SStephen Boyd
150442284a8SStephen Boyd
151442284a8SStephen Boyddef pr_cpumask(mask):
152442284a8SStephen Boyd    nr_cpu_ids = 1
153442284a8SStephen Boyd    if constants.LX_NR_CPUS > 1:
154442284a8SStephen Boyd        nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
155442284a8SStephen Boyd
156442284a8SStephen Boyd    inf = gdb.inferiors()[0]
157442284a8SStephen Boyd    bits = mask['bits']
158442284a8SStephen Boyd    num_bytes = (nr_cpu_ids + 7) / 8
159442284a8SStephen Boyd    buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
160442284a8SStephen Boyd    buf = binascii.b2a_hex(buf)
1617362042fSPeng Liu    if type(buf) is not str:
1627362042fSPeng Liu        buf=buf.decode()
163442284a8SStephen Boyd
164442284a8SStephen Boyd    chunks = []
165442284a8SStephen Boyd    i = num_bytes
166442284a8SStephen Boyd    while i > 0:
167442284a8SStephen Boyd        i -= 1
168442284a8SStephen Boyd        start = i * 2
169442284a8SStephen Boyd        end = start + 2
170442284a8SStephen Boyd        chunks.append(buf[start:end])
171442284a8SStephen Boyd        if i != 0 and i % 4 == 0:
172442284a8SStephen Boyd            chunks.append(',')
173442284a8SStephen Boyd
174442284a8SStephen Boyd    extra = nr_cpu_ids % 8
175442284a8SStephen Boyd    if 0 < extra <= 4:
176442284a8SStephen Boyd        chunks[0] = chunks[0][0]  # Cut off the first 0
177442284a8SStephen Boyd
17829692fc9SAmjad Ouled-Ameur    return "".join(str(chunks))
179442284a8SStephen Boyd
180442284a8SStephen Boyd
181442284a8SStephen Boydclass LxTimerList(gdb.Command):
182442284a8SStephen Boyd    """Print /proc/timer_list"""
183442284a8SStephen Boyd
184442284a8SStephen Boyd    def __init__(self):
185442284a8SStephen Boyd        super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
186442284a8SStephen Boyd
187442284a8SStephen Boyd    def invoke(self, arg, from_tty):
188442284a8SStephen Boyd        hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
189442284a8SStephen Boyd        max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
190442284a8SStephen Boyd
191442284a8SStephen Boyd        text = "Timer List Version: gdb scripts\n"
1928fc2a304SPeng Liu        text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(
1938fc2a304SPeng Liu            max_clock_bases.type.fields()[max_clock_bases].enumval)
194442284a8SStephen Boyd        text += "now at {} nsecs\n".format(ktime_get())
195442284a8SStephen Boyd
196442284a8SStephen Boyd        for cpu in cpus.each_online_cpu():
197442284a8SStephen Boyd            text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
198442284a8SStephen Boyd
199442284a8SStephen Boyd        if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
200442284a8SStephen Boyd            if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
201442284a8SStephen Boyd                bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
202442284a8SStephen Boyd                text += print_tickdevice(bc_dev, -1)
203442284a8SStephen Boyd                text += "\n"
204442284a8SStephen Boyd                mask = gdb.parse_and_eval("tick_broadcast_mask")
205442284a8SStephen Boyd                mask = pr_cpumask(mask)
206442284a8SStephen Boyd                text += "tick_broadcast_mask: {}\n".format(mask)
207442284a8SStephen Boyd                if constants.LX_CONFIG_TICK_ONESHOT:
208442284a8SStephen Boyd                    mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
209442284a8SStephen Boyd                    mask = pr_cpumask(mask)
210442284a8SStephen Boyd                    text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
211442284a8SStephen Boyd                text += "\n"
212442284a8SStephen Boyd
213442284a8SStephen Boyd            tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
214442284a8SStephen Boyd            for cpu in cpus.each_online_cpu():
215442284a8SStephen Boyd                tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
216442284a8SStephen Boyd                text += print_tickdevice(tick_dev, cpu)
217442284a8SStephen Boyd                text += "\n"
218442284a8SStephen Boyd
219442284a8SStephen Boyd        gdb.write(text)
220442284a8SStephen Boyd
221442284a8SStephen Boyd
222442284a8SStephen BoydLxTimerList()
223