GNU Linux-libre 5.15.137-gnu
[releases.git] / scripts / gdb / linux / timerlist.py
1 # SPDX-License-Identifier: GPL-2.0
2 #
3 # Copyright 2019 Google LLC.
4
5 import binascii
6 import gdb
7
8 from linux import constants
9 from linux import cpus
10 from linux import rbtree
11 from linux import utils
12
13 timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type()
14 hrtimer_type = utils.CachedType("struct hrtimer").get_type()
15
16
17 def ktime_get():
18     """Returns the current time, but not very accurately
19
20     We can't read the hardware timer itself to add any nanoseconds
21     that need to be added since we last stored the time in the
22     timekeeper. But this is probably good enough for debug purposes."""
23     tk_core = gdb.parse_and_eval("&tk_core")
24
25     return tk_core['timekeeper']['tkr_mono']['base']
26
27
28 def print_timer(rb_node, idx):
29     timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(),
30                                     "node")
31     timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node")
32
33     function = str(timer['function']).split(" ")[1].strip("<>")
34     softexpires = timer['_softexpires']
35     expires = timer['node']['expires']
36     now = ktime_get()
37
38     text = " #{}: <{}>, {}, ".format(idx, timer, function)
39     text += "S:{:02x}\n".format(int(timer['state']))
40     text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format(
41             softexpires, expires, softexpires - now, expires - now)
42     return text
43
44
45 def print_active_timers(base):
46     curr = base['active']['next']['node']
47     curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer())
48     idx = 0
49     while curr:
50         yield print_timer(curr, idx)
51         curr = rbtree.rb_next(curr)
52         idx += 1
53
54
55 def print_base(base):
56     text = " .base:       {}\n".format(base.address)
57     text += " .index:      {}\n".format(base['index'])
58
59     text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution)
60
61     text += " .get_time:   {}\n".format(base['get_time'])
62     if constants.LX_CONFIG_HIGH_RES_TIMERS:
63         text += "  .offset:     {} nsecs\n".format(base['offset'])
64     text += "active timers:\n"
65     text += "".join([x for x in print_active_timers(base)])
66     return text
67
68
69 def print_cpu(hrtimer_bases, cpu, max_clock_bases):
70     cpu_base = cpus.per_cpu(hrtimer_bases, cpu)
71     jiffies = gdb.parse_and_eval("jiffies_64")
72     tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched")
73     ts = cpus.per_cpu(tick_sched_ptr, cpu)
74
75     text = "cpu: {}\n".format(cpu)
76     for i in range(max_clock_bases):
77         text += " clock {}:\n".format(i)
78         text += print_base(cpu_base['clock_base'][i])
79
80         if constants.LX_CONFIG_HIGH_RES_TIMERS:
81             fmts = [("  .{}   : {} nsecs", 'expires_next'),
82                     ("  .{}    : {}", 'hres_active'),
83                     ("  .{}      : {}", 'nr_events'),
84                     ("  .{}     : {}", 'nr_retries'),
85                     ("  .{}       : {}", 'nr_hangs'),
86                     ("  .{}  : {}", 'max_hang_time')]
87             text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts])
88             text += "\n"
89
90         if constants.LX_CONFIG_TICK_ONESHOT:
91             fmts = [("  .{}      : {}", 'nohz_mode'),
92                     ("  .{}      : {} nsecs", 'last_tick'),
93                     ("  .{}   : {}", 'tick_stopped'),
94                     ("  .{}   : {}", 'idle_jiffies'),
95                     ("  .{}     : {}", 'idle_calls'),
96                     ("  .{}    : {}", 'idle_sleeps'),
97                     ("  .{} : {} nsecs", 'idle_entrytime'),
98                     ("  .{}  : {} nsecs", 'idle_waketime'),
99                     ("  .{}  : {} nsecs", 'idle_exittime'),
100                     ("  .{} : {} nsecs", 'idle_sleeptime'),
101                     ("  .{}: {} nsecs", 'iowait_sleeptime'),
102                     ("  .{}   : {}", 'last_jiffies'),
103                     ("  .{}     : {}", 'next_timer'),
104                     ("  .{}   : {} nsecs", 'idle_expires')]
105             text += "\n".join([s.format(f, ts[f]) for s, f in fmts])
106             text += "\njiffies: {}\n".format(jiffies)
107
108         text += "\n"
109
110     return text
111
112
113 def print_tickdevice(td, cpu):
114     dev = td['evtdev']
115     text = "Tick Device: mode:     {}\n".format(td['mode'])
116     if cpu < 0:
117             text += "Broadcast device\n"
118     else:
119             text += "Per CPU device: {}\n".format(cpu)
120
121     text += "Clock Event Device: "
122     if dev == 0:
123             text += "<NULL>\n"
124             return text
125
126     text += "{}\n".format(dev['name'])
127     text += " max_delta_ns:   {}\n".format(dev['max_delta_ns'])
128     text += " min_delta_ns:   {}\n".format(dev['min_delta_ns'])
129     text += " mult:           {}\n".format(dev['mult'])
130     text += " shift:          {}\n".format(dev['shift'])
131     text += " mode:           {}\n".format(dev['state_use_accessors'])
132     text += " next_event:     {} nsecs\n".format(dev['next_event'])
133
134     text += " set_next_event: {}\n".format(dev['set_next_event'])
135
136     members = [('set_state_shutdown', " shutdown: {}\n"),
137                ('set_state_periodic', " periodic: {}\n"),
138                ('set_state_oneshot', " oneshot:  {}\n"),
139                ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
140                ('tick_resume', " resume:   {}\n")]
141     for member, fmt in members:
142         if dev[member]:
143             text += fmt.format(dev[member])
144
145     text += " event_handler:  {}\n".format(dev['event_handler'])
146     text += " retries:        {}\n".format(dev['retries'])
147
148     return text
149
150
151 def pr_cpumask(mask):
152     nr_cpu_ids = 1
153     if constants.LX_NR_CPUS > 1:
154         nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
155
156     inf = gdb.inferiors()[0]
157     bits = mask['bits']
158     num_bytes = (nr_cpu_ids + 7) / 8
159     buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
160     buf = binascii.b2a_hex(buf)
161     if type(buf) is not str:
162         buf=buf.decode()
163
164     chunks = []
165     i = num_bytes
166     while i > 0:
167         i -= 1
168         start = i * 2
169         end = start + 2
170         chunks.append(buf[start:end])
171         if i != 0 and i % 4 == 0:
172             chunks.append(',')
173
174     extra = nr_cpu_ids % 8
175     if 0 < extra <= 4:
176         chunks[0] = chunks[0][0]  # Cut off the first 0
177
178     return "".join(chunks)
179
180
181 class LxTimerList(gdb.Command):
182     """Print /proc/timer_list"""
183
184     def __init__(self):
185         super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
186
187     def invoke(self, arg, from_tty):
188         hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
189         max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
190
191         text = "Timer List Version: gdb scripts\n"
192         text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
193         text += "now at {} nsecs\n".format(ktime_get())
194
195         for cpu in cpus.each_online_cpu():
196             text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
197
198         if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
199             if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
200                 bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
201                 text += print_tickdevice(bc_dev, -1)
202                 text += "\n"
203                 mask = gdb.parse_and_eval("tick_broadcast_mask")
204                 mask = pr_cpumask(mask)
205                 text += "tick_broadcast_mask: {}\n".format(mask)
206                 if constants.LX_CONFIG_TICK_ONESHOT:
207                     mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
208                     mask = pr_cpumask(mask)
209                     text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
210                 text += "\n"
211
212             tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
213             for cpu in cpus.each_online_cpu():
214                 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
215                 text += print_tickdevice(tick_dev, cpu)
216                 text += "\n"
217
218         gdb.write(text)
219
220
221 LxTimerList()