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