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() 221