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 xrange(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 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(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(max_clock_bases) 191 text += "now at {} nsecs\n".format(ktime_get()) 192 193 for cpu in cpus.each_online_cpu(): 194 text += print_cpu(hrtimer_bases, cpu, max_clock_bases) 195 196 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS: 197 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: 198 bc_dev = gdb.parse_and_eval("&tick_broadcast_device") 199 text += print_tickdevice(bc_dev, -1) 200 text += "\n" 201 mask = gdb.parse_and_eval("tick_broadcast_mask") 202 mask = pr_cpumask(mask) 203 text += "tick_broadcast_mask: {}\n".format(mask) 204 if constants.LX_CONFIG_TICK_ONESHOT: 205 mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask") 206 mask = pr_cpumask(mask) 207 text += "tick_broadcast_oneshot_mask: {}\n".format(mask) 208 text += "\n" 209 210 tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device") 211 for cpu in cpus.each_online_cpu(): 212 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu) 213 text += print_tickdevice(tick_dev, cpu) 214 text += "\n" 215 216 gdb.write(text) 217 218 219LxTimerList() 220