1442284a8SStephen Boyd# SPDX-License-Identifier: GPL-2.0 2442284a8SStephen Boyd# 3442284a8SStephen Boyd# Copyright 2019 Google LLC. 4442284a8SStephen Boyd 5442284a8SStephen Boydimport binascii 6442284a8SStephen Boydimport gdb 7442284a8SStephen Boyd 8442284a8SStephen Boydfrom linux import constants 9442284a8SStephen Boydfrom linux import cpus 10442284a8SStephen Boydfrom linux import rbtree 11442284a8SStephen Boydfrom linux import utils 12442284a8SStephen Boyd 13442284a8SStephen Boydtimerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type() 14442284a8SStephen Boydhrtimer_type = utils.CachedType("struct hrtimer").get_type() 15442284a8SStephen Boyd 16442284a8SStephen Boyd 17442284a8SStephen Boyddef ktime_get(): 18442284a8SStephen Boyd """Returns the current time, but not very accurately 19442284a8SStephen Boyd 20442284a8SStephen Boyd We can't read the hardware timer itself to add any nanoseconds 21442284a8SStephen Boyd that need to be added since we last stored the time in the 22442284a8SStephen Boyd timekeeper. But this is probably good enough for debug purposes.""" 23442284a8SStephen Boyd tk_core = gdb.parse_and_eval("&tk_core") 24442284a8SStephen Boyd 25442284a8SStephen Boyd return tk_core['timekeeper']['tkr_mono']['base'] 26442284a8SStephen Boyd 27442284a8SStephen Boyd 28442284a8SStephen Boyddef print_timer(rb_node, idx): 29442284a8SStephen Boyd timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(), 30442284a8SStephen Boyd "node") 31442284a8SStephen Boyd timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node") 32442284a8SStephen Boyd 33442284a8SStephen Boyd function = str(timer['function']).split(" ")[1].strip("<>") 34442284a8SStephen Boyd softexpires = timer['_softexpires'] 35442284a8SStephen Boyd expires = timer['node']['expires'] 36442284a8SStephen Boyd now = ktime_get() 37442284a8SStephen Boyd 38442284a8SStephen Boyd text = " #{}: <{}>, {}, ".format(idx, timer, function) 39442284a8SStephen Boyd text += "S:{:02x}\n".format(int(timer['state'])) 40442284a8SStephen Boyd text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format( 41442284a8SStephen Boyd softexpires, expires, softexpires - now, expires - now) 42442284a8SStephen Boyd return text 43442284a8SStephen Boyd 44442284a8SStephen Boyd 45442284a8SStephen Boyddef print_active_timers(base): 46*747cd84fSPeng Liu curr = base['active']['rb_root']['rb_leftmost'] 47442284a8SStephen Boyd idx = 0 48442284a8SStephen Boyd while curr: 49442284a8SStephen Boyd yield print_timer(curr, idx) 50442284a8SStephen Boyd curr = rbtree.rb_next(curr) 51442284a8SStephen Boyd idx += 1 52442284a8SStephen Boyd 53442284a8SStephen Boyd 54442284a8SStephen Boyddef print_base(base): 55442284a8SStephen Boyd text = " .base: {}\n".format(base.address) 56442284a8SStephen Boyd text += " .index: {}\n".format(base['index']) 57442284a8SStephen Boyd 58442284a8SStephen Boyd text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution) 59442284a8SStephen Boyd 60442284a8SStephen Boyd text += " .get_time: {}\n".format(base['get_time']) 61442284a8SStephen Boyd if constants.LX_CONFIG_HIGH_RES_TIMERS: 62442284a8SStephen Boyd text += " .offset: {} nsecs\n".format(base['offset']) 63442284a8SStephen Boyd text += "active timers:\n" 64442284a8SStephen Boyd text += "".join([x for x in print_active_timers(base)]) 65442284a8SStephen Boyd return text 66442284a8SStephen Boyd 67442284a8SStephen Boyd 68442284a8SStephen Boyddef print_cpu(hrtimer_bases, cpu, max_clock_bases): 69442284a8SStephen Boyd cpu_base = cpus.per_cpu(hrtimer_bases, cpu) 70442284a8SStephen Boyd jiffies = gdb.parse_and_eval("jiffies_64") 71442284a8SStephen Boyd tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched") 72442284a8SStephen Boyd ts = cpus.per_cpu(tick_sched_ptr, cpu) 73442284a8SStephen Boyd 74442284a8SStephen Boyd text = "cpu: {}\n".format(cpu) 75442284a8SStephen Boyd for i in xrange(max_clock_bases): 76442284a8SStephen Boyd text += " clock {}:\n".format(i) 77442284a8SStephen Boyd text += print_base(cpu_base['clock_base'][i]) 78442284a8SStephen Boyd 79442284a8SStephen Boyd if constants.LX_CONFIG_HIGH_RES_TIMERS: 80442284a8SStephen Boyd fmts = [(" .{} : {} nsecs", 'expires_next'), 81442284a8SStephen Boyd (" .{} : {}", 'hres_active'), 82442284a8SStephen Boyd (" .{} : {}", 'nr_events'), 83442284a8SStephen Boyd (" .{} : {}", 'nr_retries'), 84442284a8SStephen Boyd (" .{} : {}", 'nr_hangs'), 85442284a8SStephen Boyd (" .{} : {}", 'max_hang_time')] 86442284a8SStephen Boyd text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts]) 87442284a8SStephen Boyd text += "\n" 88442284a8SStephen Boyd 89442284a8SStephen Boyd if constants.LX_CONFIG_TICK_ONESHOT: 90442284a8SStephen Boyd fmts = [(" .{} : {}", 'nohz_mode'), 91442284a8SStephen Boyd (" .{} : {} nsecs", 'last_tick'), 92442284a8SStephen Boyd (" .{} : {}", 'tick_stopped'), 93442284a8SStephen Boyd (" .{} : {}", 'idle_jiffies'), 94442284a8SStephen Boyd (" .{} : {}", 'idle_calls'), 95442284a8SStephen Boyd (" .{} : {}", 'idle_sleeps'), 96442284a8SStephen Boyd (" .{} : {} nsecs", 'idle_entrytime'), 97442284a8SStephen Boyd (" .{} : {} nsecs", 'idle_waketime'), 98442284a8SStephen Boyd (" .{} : {} nsecs", 'idle_exittime'), 99442284a8SStephen Boyd (" .{} : {} nsecs", 'idle_sleeptime'), 100442284a8SStephen Boyd (" .{}: {} nsecs", 'iowait_sleeptime'), 101442284a8SStephen Boyd (" .{} : {}", 'last_jiffies'), 102442284a8SStephen Boyd (" .{} : {}", 'next_timer'), 103442284a8SStephen Boyd (" .{} : {} nsecs", 'idle_expires')] 104442284a8SStephen Boyd text += "\n".join([s.format(f, ts[f]) for s, f in fmts]) 105442284a8SStephen Boyd text += "\njiffies: {}\n".format(jiffies) 106442284a8SStephen Boyd 107442284a8SStephen Boyd text += "\n" 108442284a8SStephen Boyd 109442284a8SStephen Boyd return text 110442284a8SStephen Boyd 111442284a8SStephen Boyd 112442284a8SStephen Boyddef print_tickdevice(td, cpu): 113442284a8SStephen Boyd dev = td['evtdev'] 114442284a8SStephen Boyd text = "Tick Device: mode: {}\n".format(td['mode']) 115442284a8SStephen Boyd if cpu < 0: 116442284a8SStephen Boyd text += "Broadcast device\n" 117442284a8SStephen Boyd else: 118442284a8SStephen Boyd text += "Per CPU device: {}\n".format(cpu) 119442284a8SStephen Boyd 120442284a8SStephen Boyd text += "Clock Event Device: " 121442284a8SStephen Boyd if dev == 0: 122442284a8SStephen Boyd text += "<NULL>\n" 123442284a8SStephen Boyd return text 124442284a8SStephen Boyd 125442284a8SStephen Boyd text += "{}\n".format(dev['name']) 126442284a8SStephen Boyd text += " max_delta_ns: {}\n".format(dev['max_delta_ns']) 127442284a8SStephen Boyd text += " min_delta_ns: {}\n".format(dev['min_delta_ns']) 128442284a8SStephen Boyd text += " mult: {}\n".format(dev['mult']) 129442284a8SStephen Boyd text += " shift: {}\n".format(dev['shift']) 130442284a8SStephen Boyd text += " mode: {}\n".format(dev['state_use_accessors']) 131442284a8SStephen Boyd text += " next_event: {} nsecs\n".format(dev['next_event']) 132442284a8SStephen Boyd 133442284a8SStephen Boyd text += " set_next_event: {}\n".format(dev['set_next_event']) 134442284a8SStephen Boyd 135442284a8SStephen Boyd members = [('set_state_shutdown', " shutdown: {}\n"), 136442284a8SStephen Boyd ('set_state_periodic', " periodic: {}\n"), 137442284a8SStephen Boyd ('set_state_oneshot', " oneshot: {}\n"), 138442284a8SStephen Boyd ('set_state_oneshot_stopped', " oneshot stopped: {}\n"), 139442284a8SStephen Boyd ('tick_resume', " resume: {}\n")] 140442284a8SStephen Boyd for member, fmt in members: 141442284a8SStephen Boyd if dev[member]: 142442284a8SStephen Boyd text += fmt.format(dev[member]) 143442284a8SStephen Boyd 144442284a8SStephen Boyd text += " event_handler: {}\n".format(dev['event_handler']) 145442284a8SStephen Boyd text += " retries: {}\n".format(dev['retries']) 146442284a8SStephen Boyd 147442284a8SStephen Boyd return text 148442284a8SStephen Boyd 149442284a8SStephen Boyd 150442284a8SStephen Boyddef pr_cpumask(mask): 151442284a8SStephen Boyd nr_cpu_ids = 1 152442284a8SStephen Boyd if constants.LX_NR_CPUS > 1: 153442284a8SStephen Boyd nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids") 154442284a8SStephen Boyd 155442284a8SStephen Boyd inf = gdb.inferiors()[0] 156442284a8SStephen Boyd bits = mask['bits'] 157442284a8SStephen Boyd num_bytes = (nr_cpu_ids + 7) / 8 158442284a8SStephen Boyd buf = utils.read_memoryview(inf, bits, num_bytes).tobytes() 159442284a8SStephen Boyd buf = binascii.b2a_hex(buf) 160442284a8SStephen Boyd 161442284a8SStephen Boyd chunks = [] 162442284a8SStephen Boyd i = num_bytes 163442284a8SStephen Boyd while i > 0: 164442284a8SStephen Boyd i -= 1 165442284a8SStephen Boyd start = i * 2 166442284a8SStephen Boyd end = start + 2 167442284a8SStephen Boyd chunks.append(buf[start:end]) 168442284a8SStephen Boyd if i != 0 and i % 4 == 0: 169442284a8SStephen Boyd chunks.append(',') 170442284a8SStephen Boyd 171442284a8SStephen Boyd extra = nr_cpu_ids % 8 172442284a8SStephen Boyd if 0 < extra <= 4: 173442284a8SStephen Boyd chunks[0] = chunks[0][0] # Cut off the first 0 174442284a8SStephen Boyd 175442284a8SStephen Boyd return "".join(chunks) 176442284a8SStephen Boyd 177442284a8SStephen Boyd 178442284a8SStephen Boydclass LxTimerList(gdb.Command): 179442284a8SStephen Boyd """Print /proc/timer_list""" 180442284a8SStephen Boyd 181442284a8SStephen Boyd def __init__(self): 182442284a8SStephen Boyd super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA) 183442284a8SStephen Boyd 184442284a8SStephen Boyd def invoke(self, arg, from_tty): 185442284a8SStephen Boyd hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases") 186442284a8SStephen Boyd max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES") 187442284a8SStephen Boyd 188442284a8SStephen Boyd text = "Timer List Version: gdb scripts\n" 189442284a8SStephen Boyd text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases) 190442284a8SStephen Boyd text += "now at {} nsecs\n".format(ktime_get()) 191442284a8SStephen Boyd 192442284a8SStephen Boyd for cpu in cpus.each_online_cpu(): 193442284a8SStephen Boyd text += print_cpu(hrtimer_bases, cpu, max_clock_bases) 194442284a8SStephen Boyd 195442284a8SStephen Boyd if constants.LX_CONFIG_GENERIC_CLOCKEVENTS: 196442284a8SStephen Boyd if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: 197442284a8SStephen Boyd bc_dev = gdb.parse_and_eval("&tick_broadcast_device") 198442284a8SStephen Boyd text += print_tickdevice(bc_dev, -1) 199442284a8SStephen Boyd text += "\n" 200442284a8SStephen Boyd mask = gdb.parse_and_eval("tick_broadcast_mask") 201442284a8SStephen Boyd mask = pr_cpumask(mask) 202442284a8SStephen Boyd text += "tick_broadcast_mask: {}\n".format(mask) 203442284a8SStephen Boyd if constants.LX_CONFIG_TICK_ONESHOT: 204442284a8SStephen Boyd mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask") 205442284a8SStephen Boyd mask = pr_cpumask(mask) 206442284a8SStephen Boyd text += "tick_broadcast_oneshot_mask: {}\n".format(mask) 207442284a8SStephen Boyd text += "\n" 208442284a8SStephen Boyd 209442284a8SStephen Boyd tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device") 210442284a8SStephen Boyd for cpu in cpus.each_online_cpu(): 211442284a8SStephen Boyd tick_dev = cpus.per_cpu(tick_cpu_devices, cpu) 212442284a8SStephen Boyd text += print_tickdevice(tick_dev, cpu) 213442284a8SStephen Boyd text += "\n" 214442284a8SStephen Boyd 215442284a8SStephen Boyd gdb.write(text) 216442284a8SStephen Boyd 217442284a8SStephen Boyd 218442284a8SStephen BoydLxTimerList() 219