Linux-libre 5.4.48-gnu
[librecmc/linux-libre.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 xrange(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
162     chunks = []
163     i = num_bytes
164     while i > 0:
165         i -= 1
166         start = i * 2
167         end = start + 2
168         chunks.append(buf[start:end])
169         if i != 0 and i % 4 == 0:
170             chunks.append(',')
171
172     extra = nr_cpu_ids % 8
173     if 0 < extra <= 4:
174         chunks[0] = chunks[0][0]  # Cut off the first 0
175
176     return "".join(chunks)
177
178
179 class LxTimerList(gdb.Command):
180     """Print /proc/timer_list"""
181
182     def __init__(self):
183         super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
184
185     def invoke(self, arg, from_tty):
186         hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
187         max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
188
189         text = "Timer List Version: gdb scripts\n"
190         text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
191         text += "now at {} nsecs\n".format(ktime_get())
192
193         for cpu in cpus.each_online_cpu():
194             text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
195
196         if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
197             if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
198                 bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
199                 text += print_tickdevice(bc_dev, -1)
200                 text += "\n"
201                 mask = gdb.parse_and_eval("tick_broadcast_mask")
202                 mask = pr_cpumask(mask)
203                 text += "tick_broadcast_mask: {}\n".format(mask)
204                 if constants.LX_CONFIG_TICK_ONESHOT:
205                     mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
206                     mask = pr_cpumask(mask)
207                     text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
208                 text += "\n"
209
210             tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
211             for cpu in cpus.each_online_cpu():
212                 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
213                 text += print_tickdevice(tick_dev, cpu)
214                 text += "\n"
215
216         gdb.write(text)
217
218
219 LxTimerList()