aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/gdb/linux/timerlist.py
diff options
context:
space:
mode:
authorStephen Boyd <swboyd@chromium.org>2019-05-14 18:45:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-14 22:52:52 -0400
commit442284a89a65965b044df00345c193fcc3c53ad2 (patch)
tree73973f3645aa0dda36beb8da39d82bcdacd2c733 /scripts/gdb/linux/timerlist.py
parent449ca0c95ea261f27b7efd4ca3970a5b4e0fd30d (diff)
scripts/gdb: add a timer list command
Implement a command to print the timer list, much like how /proc/timer_list is implemented. This can be used to look at the pending timers on a crashed system. [swboyd@chromium.org: v2] Link: http://lkml.kernel.org/r/20190329220844.38234-5-swboyd@chromium.org Link: http://lkml.kernel.org/r/20190325184522.260535-5-swboyd@chromium.org Signed-off-by: Stephen Boyd <swboyd@chromium.org> Cc: Douglas Anderson <dianders@chromium.org> Cc: Nikolay Borisov <n.borisov.lkml@gmail.com> Cc: Kieran Bingham <kbingham@kernel.org> Cc: Jan Kiszka <jan.kiszka@siemens.com> Cc: Jackie Liu <liuyun01@kylinos.cn> Cc: Jason Wessel <jason.wessel@windriver.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'scripts/gdb/linux/timerlist.py')
-rw-r--r--scripts/gdb/linux/timerlist.py219
1 files changed, 219 insertions, 0 deletions
diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py
new file mode 100644
index 000000000000..071d0dd5a634
--- /dev/null
+++ b/scripts/gdb/linux/timerlist.py
@@ -0,0 +1,219 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright 2019 Google LLC.
4
5import binascii
6import gdb
7
8from linux import constants
9from linux import cpus
10from linux import rbtree
11from linux import utils
12
13timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type()
14hrtimer_type = utils.CachedType("struct hrtimer").get_type()
15
16
17def 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
28def 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
45def 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
55def 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
69def 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
113def 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
151def 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
179class 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
219LxTimerList()