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']['next']['node'] 47 curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer()) 48 idx = 0 49 while curr: 50 yield print_timer(curr, idx) 51 curr = rbtree.rb_next(curr) 52 idx += 1 53 54 55def print_base(base): 56 text = " .base: {}\n".format(base.address) 57 text += " .index: {}\n".format(base['index']) 58 59 text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution) 60 61 text += " .get_time: {}\n".format(base['get_time']) 62 if constants.LX_CONFIG_HIGH_RES_TIMERS: 63 text += " .offset: {} nsecs\n".format(base['offset']) 64 text += "active timers:\n" 65 text += "".join([x for x in print_active_timers(base)]) 66 return text 67 68 69def print_cpu(hrtimer_bases, cpu, max_clock_bases): 70 cpu_base = cpus.per_cpu(hrtimer_bases, cpu) 71 jiffies = gdb.parse_and_eval("jiffies_64") 72 tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched") 73 ts = cpus.per_cpu(tick_sched_ptr, cpu) 74 75 text = "cpu: {}\n".format(cpu) 76 for i in range(max_clock_bases): 77 text += " clock {}:\n".format(i) 78 text += print_base(cpu_base['clock_base'][i]) 79 80 if constants.LX_CONFIG_HIGH_RES_TIMERS: 81 fmts = [(" .{} : {} nsecs", 'expires_next'), 82 (" .{} : {}", 'hres_active'), 83 (" .{} : {}", 'nr_events'), 84 (" .{} : {}", 'nr_retries'), 85 (" .{} : {}", 'nr_hangs'), 86 (" .{} : {}", 'max_hang_time')] 87 text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts]) 88 text += "\n" 89 90 if constants.LX_CONFIG_TICK_ONESHOT: 91 fmts = [(" .{} : {}", 'nohz_mode'), 92 (" .{} : {} nsecs", 'last_tick'), 93 (" .{} : {}", 'tick_stopped'), 94 (" .{} : {}", 'idle_jiffies'), 95 (" .{} : {}", 'idle_calls'), 96 (" .{} : {}", 'idle_sleeps'), 97 (" .{} : {} nsecs", 'idle_entrytime'), 98 (" .{} : {} nsecs", 'idle_waketime'), 99 (" .{} : {} nsecs", 'idle_exittime'), 100 (" .{} : {} nsecs", 'idle_sleeptime'), 101 (" .{}: {} nsecs", 'iowait_sleeptime'), 102 (" .{} : {}", 'last_jiffies'), 103 (" .{} : {}", 'next_timer'), 104 (" .{} : {} nsecs", 'idle_expires')] 105 text += "\n".join([s.format(f, ts[f]) for s, f in fmts]) 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(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(max_clock_bases) 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() 222