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 fmts = [(" .{} : {}", 'nohz_mode'),
91 (" .{} : {} nsecs", 'last_tick'),
92 (" .{} : {}", 'tick_stopped'),
93 (" .{} : {}", 'idle_jiffies'),
94 (" .{} : {}", 'idle_calls'),
95 (" .{} : {}", 'idle_sleeps'),
96 (" .{} : {} nsecs", 'idle_entrytime'),
97 (" .{} : {} nsecs", 'idle_waketime'),
98 (" .{} : {} nsecs", 'idle_exittime'),
99 (" .{} : {} nsecs", 'idle_sleeptime'),
100 (" .{}: {} nsecs", 'iowait_sleeptime'),
101 (" .{} : {}", 'last_jiffies'),
102 (" .{} : {}", 'next_timer'),
103 (" .{} : {} nsecs", 'idle_expires')]
104 text += "\n".join([s.format(f, ts[f]) for s, f in fmts])
105 text += "\njiffies: {}\n".format(jiffies)
106
107 text += "\n"
108
109 return text
110
111
112def print_tickdevice(td, cpu):
113 dev = td['evtdev']
114 text = "Tick Device: mode: {}\n".format(td['mode'])
115 if cpu < 0:
116 text += "Broadcast device\n"
117 else:
118 text += "Per CPU device: {}\n".format(cpu)
119
120 text += "Clock Event Device: "
121 if dev == 0:
122 text += "<NULL>\n"
123 return text
124
125 text += "{}\n".format(dev['name'])
126 text += " max_delta_ns: {}\n".format(dev['max_delta_ns'])
127 text += " min_delta_ns: {}\n".format(dev['min_delta_ns'])
128 text += " mult: {}\n".format(dev['mult'])
129 text += " shift: {}\n".format(dev['shift'])
130 text += " mode: {}\n".format(dev['state_use_accessors'])
131 text += " next_event: {} nsecs\n".format(dev['next_event'])
132
133 text += " set_next_event: {}\n".format(dev['set_next_event'])
134
135 members = [('set_state_shutdown', " shutdown: {}\n"),
136 ('set_state_periodic', " periodic: {}\n"),
137 ('set_state_oneshot', " oneshot: {}\n"),
138 ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
139 ('tick_resume', " resume: {}\n")]
140 for member, fmt in members:
141 if dev[member]:
142 text += fmt.format(dev[member])
143
144 text += " event_handler: {}\n".format(dev['event_handler'])
145 text += " retries: {}\n".format(dev['retries'])
146
147 return text
148
149
150def pr_cpumask(mask):
151 nr_cpu_ids = 1
152 if constants.LX_NR_CPUS > 1:
153 nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
154
155 inf = gdb.inferiors()[0]
156 bits = mask['bits']
157 num_bytes = (nr_cpu_ids + 7) / 8
158 buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
159 buf = binascii.b2a_hex(buf)
160 if type(buf) is not str:
161 buf=buf.decode()
162
163 chunks = []
164 i = num_bytes
165 while i > 0:
166 i -= 1
167 start = i * 2
168 end = start + 2
169 chunks.append(buf[start:end])
170 if i != 0 and i % 4 == 0:
171 chunks.append(',')
172
173 extra = nr_cpu_ids % 8
174 if 0 < extra <= 4:
175 chunks[0] = chunks[0][0] # Cut off the first 0
176
177 return "".join(str(chunks))
178
179
180class LxTimerList(gdb.Command):
181 """Print /proc/timer_list"""
182
183 def __init__(self):
184 super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
185
186 def invoke(self, arg, from_tty):
187 hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
188 max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
189
190 text = "Timer List Version: gdb scripts\n"
191 text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(
192 max_clock_bases.type.fields()[max_clock_bases].enumval)
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
221LxTimerList()