Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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']['rb_root']['rb_leftmost']
47 idx = 0
48 while curr:
49 yield print_timer(curr, idx)
50 curr = rbtree.rb_next(curr)
51 idx += 1
52
53
54def print_base(base):
55 text = " .base: {}\n".format(base.address)
56 text += " .index: {}\n".format(base['index'])
57
58 text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution)
59 if constants.LX_CONFIG_HIGH_RES_TIMERS:
60 text += " .offset: {} nsecs\n".format(base['offset'])
61 text += "active timers:\n"
62 text += "".join([x for x in print_active_timers(base)])
63 return text
64
65
66def print_cpu(hrtimer_bases, cpu, max_clock_bases):
67 cpu_base = cpus.per_cpu(hrtimer_bases, cpu)
68 jiffies = gdb.parse_and_eval("jiffies_64")
69 tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched")
70 ts = cpus.per_cpu(tick_sched_ptr, cpu)
71
72 text = "cpu: {}\n".format(cpu)
73 for i in range(max_clock_bases):
74 text += " clock {}:\n".format(i)
75 text += print_base(cpu_base['clock_base'][i])
76
77 if constants.LX_CONFIG_HIGH_RES_TIMERS:
78 fmts = [(" .{} : {} nsecs", 'expires_next'),
79 (" .{} : {}", 'hres_active'),
80 (" .{} : {}", 'nr_events'),
81 (" .{} : {}", 'nr_retries'),
82 (" .{} : {}", 'nr_hangs'),
83 (" .{} : {}", 'max_hang_time')]
84 text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts])
85 text += "\n"
86
87 if constants.LX_CONFIG_TICK_ONESHOT:
88 TS_FLAG_STOPPED = 1 << 1
89 TS_FLAG_NOHZ = 1 << 4
90 text += f" .{'nohz':15s}: {int(bool(ts['flags'] & TS_FLAG_NOHZ))}\n"
91 text += f" .{'last_tick':15s}: {ts['last_tick']}\n"
92 text += f" .{'tick_stopped':15s}: {int(bool(ts['flags'] & TS_FLAG_STOPPED))}\n"
93 text += f" .{'idle_jiffies':15s}: {ts['idle_jiffies']}\n"
94 text += f" .{'idle_calls':15s}: {ts['idle_calls']}\n"
95 text += f" .{'idle_sleeps':15s}: {ts['idle_sleeps']}\n"
96 text += f" .{'idle_entrytime':15s}: {ts['idle_entrytime']} nsecs\n"
97 text += f" .{'idle_waketime':15s}: {ts['idle_waketime']} nsecs\n"
98 text += f" .{'idle_exittime':15s}: {ts['idle_exittime']} nsecs\n"
99 text += f" .{'idle_sleeptime':15s}: {ts['idle_sleeptime']} nsecs\n"
100 text += f" .{'iowait_sleeptime':15s}: {ts['iowait_sleeptime']} nsecs\n"
101 text += f" .{'last_jiffies':15s}: {ts['last_jiffies']}\n"
102 text += f" .{'next_timer':15s}: {ts['next_timer']}\n"
103 text += f" .{'idle_expires':15s}: {ts['idle_expires']} nsecs\n"
104 text += "\njiffies: {}\n".format(jiffies)
105
106 text += "\n"
107
108 return text
109
110
111def print_tickdevice(td, cpu):
112 dev = td['evtdev']
113 text = "Tick Device: mode: {}\n".format(td['mode'])
114 if cpu < 0:
115 text += "Broadcast device\n"
116 else:
117 text += "Per CPU device: {}\n".format(cpu)
118
119 text += "Clock Event Device: "
120 if dev == 0:
121 text += "<NULL>\n"
122 return text
123
124 text += "{}\n".format(dev['name'])
125 text += " max_delta_ns: {}\n".format(dev['max_delta_ns'])
126 text += " min_delta_ns: {}\n".format(dev['min_delta_ns'])
127 text += " mult: {}\n".format(dev['mult'])
128 text += " shift: {}\n".format(dev['shift'])
129 text += " mode: {}\n".format(dev['state_use_accessors'])
130 text += " next_event: {} nsecs\n".format(dev['next_event'])
131
132 text += " set_next_event: {}\n".format(dev['set_next_event'])
133
134 members = [('set_state_shutdown', " shutdown: {}\n"),
135 ('set_state_periodic', " periodic: {}\n"),
136 ('set_state_oneshot', " oneshot: {}\n"),
137 ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
138 ('tick_resume', " resume: {}\n")]
139 for member, fmt in members:
140 if dev[member]:
141 text += fmt.format(dev[member])
142
143 text += " event_handler: {}\n".format(dev['event_handler'])
144 text += " retries: {}\n".format(dev['retries'])
145
146 return text
147
148
149def pr_cpumask(mask):
150 nr_cpu_ids = 1
151 if constants.LX_NR_CPUS > 1:
152 nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
153
154 inf = gdb.inferiors()[0]
155 bits = mask['bits']
156 num_bytes = (nr_cpu_ids + 7) / 8
157 buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
158 buf = binascii.b2a_hex(buf)
159 if type(buf) is not str:
160 buf=buf.decode()
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(str(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(
191 max_clock_bases.type.fields()[max_clock_bases].enumval)
192 text += "now at {} nsecs\n".format(ktime_get())
193
194 for cpu in cpus.each_online_cpu():
195 text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
196
197 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
198 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
199 bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
200 text += print_tickdevice(bc_dev, -1)
201 text += "\n"
202 mask = gdb.parse_and_eval("tick_broadcast_mask")
203 mask = pr_cpumask(mask)
204 text += "tick_broadcast_mask: {}\n".format(mask)
205 if constants.LX_CONFIG_TICK_ONESHOT:
206 mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
207 mask = pr_cpumask(mask)
208 text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
209 text += "\n"
210
211 tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
212 for cpu in cpus.each_online_cpu():
213 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
214 text += print_tickdevice(tick_dev, cpu)
215 text += "\n"
216
217 gdb.write(text)
218
219
220LxTimerList()