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
60 text += " .get_time: {}\n".format(base['get_time'])
61 if constants.LX_CONFIG_HIGH_RES_TIMERS:
62 text += " .offset: {} nsecs\n".format(base['offset'])
63 text += "active timers:\n"
64 text += "".join([x for x in print_active_timers(base)])
65 return text
66
67
68def print_cpu(hrtimer_bases, cpu, max_clock_bases):
69 cpu_base = cpus.per_cpu(hrtimer_bases, cpu)
70 jiffies = gdb.parse_and_eval("jiffies_64")
71 tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched")
72 ts = cpus.per_cpu(tick_sched_ptr, cpu)
73
74 text = "cpu: {}\n".format(cpu)
75 for i in range(max_clock_bases):
76 text += " clock {}:\n".format(i)
77 text += print_base(cpu_base['clock_base'][i])
78
79 if constants.LX_CONFIG_HIGH_RES_TIMERS:
80 fmts = [(" .{} : {} nsecs", 'expires_next'),
81 (" .{} : {}", 'hres_active'),
82 (" .{} : {}", 'nr_events'),
83 (" .{} : {}", 'nr_retries'),
84 (" .{} : {}", 'nr_hangs'),
85 (" .{} : {}", 'max_hang_time')]
86 text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts])
87 text += "\n"
88
89 if constants.LX_CONFIG_TICK_ONESHOT:
90 TS_FLAG_STOPPED = 1 << 1
91 TS_FLAG_NOHZ = 1 << 4
92 text += f" .{'nohz':15s}: {int(bool(ts['flags'] & TS_FLAG_NOHZ))}\n"
93 text += f" .{'last_tick':15s}: {ts['last_tick']}\n"
94 text += f" .{'tick_stopped':15s}: {int(bool(ts['flags'] & TS_FLAG_STOPPED))}\n"
95 text += f" .{'idle_jiffies':15s}: {ts['idle_jiffies']}\n"
96 text += f" .{'idle_calls':15s}: {ts['idle_calls']}\n"
97 text += f" .{'idle_sleeps':15s}: {ts['idle_sleeps']}\n"
98 text += f" .{'idle_entrytime':15s}: {ts['idle_entrytime']} nsecs\n"
99 text += f" .{'idle_waketime':15s}: {ts['idle_waketime']} nsecs\n"
100 text += f" .{'idle_exittime':15s}: {ts['idle_exittime']} nsecs\n"
101 text += f" .{'idle_sleeptime':15s}: {ts['idle_sleeptime']} nsecs\n"
102 text += f" .{'iowait_sleeptime':15s}: {ts['iowait_sleeptime']} nsecs\n"
103 text += f" .{'last_jiffies':15s}: {ts['last_jiffies']}\n"
104 text += f" .{'next_timer':15s}: {ts['next_timer']}\n"
105 text += f" .{'idle_expires':15s}: {ts['idle_expires']} nsecs\n"
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 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(str(chunks))
179
180
181class 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(
193 max_clock_bases.type.fields()[max_clock_bases].enumval)
194 text += "now at {} nsecs\n".format(ktime_get())
195
196 for cpu in cpus.each_online_cpu():
197 text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
198
199 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
200 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
201 bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
202 text += print_tickdevice(bc_dev, -1)
203 text += "\n"
204 mask = gdb.parse_and_eval("tick_broadcast_mask")
205 mask = pr_cpumask(mask)
206 text += "tick_broadcast_mask: {}\n".format(mask)
207 if constants.LX_CONFIG_TICK_ONESHOT:
208 mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
209 mask = pr_cpumask(mask)
210 text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
211 text += "\n"
212
213 tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
214 for cpu in cpus.each_online_cpu():
215 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
216 text += print_tickdevice(tick_dev, cpu)
217 text += "\n"
218
219 gdb.write(text)
220
221
222LxTimerList()