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): 46747cd84fSPeng 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) 757362042fSPeng Liu for i in range(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: 90*a633a4b8SKuan-Ying Lee TS_FLAG_STOPPED = 1 << 1 91*a633a4b8SKuan-Ying Lee TS_FLAG_NOHZ = 1 << 4 92*a633a4b8SKuan-Ying Lee text += f" .{'nohz':15s}: {int(bool(ts['flags'] & TS_FLAG_NOHZ))}\n" 93*a633a4b8SKuan-Ying Lee text += f" .{'last_tick':15s}: {ts['last_tick']}\n" 94*a633a4b8SKuan-Ying Lee text += f" .{'tick_stopped':15s}: {int(bool(ts['flags'] & TS_FLAG_STOPPED))}\n" 95*a633a4b8SKuan-Ying Lee text += f" .{'idle_jiffies':15s}: {ts['idle_jiffies']}\n" 96*a633a4b8SKuan-Ying Lee text += f" .{'idle_calls':15s}: {ts['idle_calls']}\n" 97*a633a4b8SKuan-Ying Lee text += f" .{'idle_sleeps':15s}: {ts['idle_sleeps']}\n" 98*a633a4b8SKuan-Ying Lee text += f" .{'idle_entrytime':15s}: {ts['idle_entrytime']} nsecs\n" 99*a633a4b8SKuan-Ying Lee text += f" .{'idle_waketime':15s}: {ts['idle_waketime']} nsecs\n" 100*a633a4b8SKuan-Ying Lee text += f" .{'idle_exittime':15s}: {ts['idle_exittime']} nsecs\n" 101*a633a4b8SKuan-Ying Lee text += f" .{'idle_sleeptime':15s}: {ts['idle_sleeptime']} nsecs\n" 102*a633a4b8SKuan-Ying Lee text += f" .{'iowait_sleeptime':15s}: {ts['iowait_sleeptime']} nsecs\n" 103*a633a4b8SKuan-Ying Lee text += f" .{'last_jiffies':15s}: {ts['last_jiffies']}\n" 104*a633a4b8SKuan-Ying Lee text += f" .{'next_timer':15s}: {ts['next_timer']}\n" 105*a633a4b8SKuan-Ying Lee text += f" .{'idle_expires':15s}: {ts['idle_expires']} nsecs\n" 106442284a8SStephen Boyd text += "\njiffies: {}\n".format(jiffies) 107442284a8SStephen Boyd 108442284a8SStephen Boyd text += "\n" 109442284a8SStephen Boyd 110442284a8SStephen Boyd return text 111442284a8SStephen Boyd 112442284a8SStephen Boyd 113442284a8SStephen Boyddef print_tickdevice(td, cpu): 114442284a8SStephen Boyd dev = td['evtdev'] 115442284a8SStephen Boyd text = "Tick Device: mode: {}\n".format(td['mode']) 116442284a8SStephen Boyd if cpu < 0: 117442284a8SStephen Boyd text += "Broadcast device\n" 118442284a8SStephen Boyd else: 119442284a8SStephen Boyd text += "Per CPU device: {}\n".format(cpu) 120442284a8SStephen Boyd 121442284a8SStephen Boyd text += "Clock Event Device: " 122442284a8SStephen Boyd if dev == 0: 123442284a8SStephen Boyd text += "<NULL>\n" 124442284a8SStephen Boyd return text 125442284a8SStephen Boyd 126442284a8SStephen Boyd text += "{}\n".format(dev['name']) 127442284a8SStephen Boyd text += " max_delta_ns: {}\n".format(dev['max_delta_ns']) 128442284a8SStephen Boyd text += " min_delta_ns: {}\n".format(dev['min_delta_ns']) 129442284a8SStephen Boyd text += " mult: {}\n".format(dev['mult']) 130442284a8SStephen Boyd text += " shift: {}\n".format(dev['shift']) 131442284a8SStephen Boyd text += " mode: {}\n".format(dev['state_use_accessors']) 132442284a8SStephen Boyd text += " next_event: {} nsecs\n".format(dev['next_event']) 133442284a8SStephen Boyd 134442284a8SStephen Boyd text += " set_next_event: {}\n".format(dev['set_next_event']) 135442284a8SStephen Boyd 136442284a8SStephen Boyd members = [('set_state_shutdown', " shutdown: {}\n"), 137442284a8SStephen Boyd ('set_state_periodic', " periodic: {}\n"), 138442284a8SStephen Boyd ('set_state_oneshot', " oneshot: {}\n"), 139442284a8SStephen Boyd ('set_state_oneshot_stopped', " oneshot stopped: {}\n"), 140442284a8SStephen Boyd ('tick_resume', " resume: {}\n")] 141442284a8SStephen Boyd for member, fmt in members: 142442284a8SStephen Boyd if dev[member]: 143442284a8SStephen Boyd text += fmt.format(dev[member]) 144442284a8SStephen Boyd 145442284a8SStephen Boyd text += " event_handler: {}\n".format(dev['event_handler']) 146442284a8SStephen Boyd text += " retries: {}\n".format(dev['retries']) 147442284a8SStephen Boyd 148442284a8SStephen Boyd return text 149442284a8SStephen Boyd 150442284a8SStephen Boyd 151442284a8SStephen Boyddef pr_cpumask(mask): 152442284a8SStephen Boyd nr_cpu_ids = 1 153442284a8SStephen Boyd if constants.LX_NR_CPUS > 1: 154442284a8SStephen Boyd nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids") 155442284a8SStephen Boyd 156442284a8SStephen Boyd inf = gdb.inferiors()[0] 157442284a8SStephen Boyd bits = mask['bits'] 158442284a8SStephen Boyd num_bytes = (nr_cpu_ids + 7) / 8 159442284a8SStephen Boyd buf = utils.read_memoryview(inf, bits, num_bytes).tobytes() 160442284a8SStephen Boyd buf = binascii.b2a_hex(buf) 1617362042fSPeng Liu if type(buf) is not str: 1627362042fSPeng Liu buf=buf.decode() 163442284a8SStephen Boyd 164442284a8SStephen Boyd chunks = [] 165442284a8SStephen Boyd i = num_bytes 166442284a8SStephen Boyd while i > 0: 167442284a8SStephen Boyd i -= 1 168442284a8SStephen Boyd start = i * 2 169442284a8SStephen Boyd end = start + 2 170442284a8SStephen Boyd chunks.append(buf[start:end]) 171442284a8SStephen Boyd if i != 0 and i % 4 == 0: 172442284a8SStephen Boyd chunks.append(',') 173442284a8SStephen Boyd 174442284a8SStephen Boyd extra = nr_cpu_ids % 8 175442284a8SStephen Boyd if 0 < extra <= 4: 176442284a8SStephen Boyd chunks[0] = chunks[0][0] # Cut off the first 0 177442284a8SStephen Boyd 17829692fc9SAmjad Ouled-Ameur return "".join(str(chunks)) 179442284a8SStephen Boyd 180442284a8SStephen Boyd 181442284a8SStephen Boydclass LxTimerList(gdb.Command): 182442284a8SStephen Boyd """Print /proc/timer_list""" 183442284a8SStephen Boyd 184442284a8SStephen Boyd def __init__(self): 185442284a8SStephen Boyd super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA) 186442284a8SStephen Boyd 187442284a8SStephen Boyd def invoke(self, arg, from_tty): 188442284a8SStephen Boyd hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases") 189442284a8SStephen Boyd max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES") 190442284a8SStephen Boyd 191442284a8SStephen Boyd text = "Timer List Version: gdb scripts\n" 1928fc2a304SPeng Liu text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format( 1938fc2a304SPeng Liu max_clock_bases.type.fields()[max_clock_bases].enumval) 194442284a8SStephen Boyd text += "now at {} nsecs\n".format(ktime_get()) 195442284a8SStephen Boyd 196442284a8SStephen Boyd for cpu in cpus.each_online_cpu(): 197442284a8SStephen Boyd text += print_cpu(hrtimer_bases, cpu, max_clock_bases) 198442284a8SStephen Boyd 199442284a8SStephen Boyd if constants.LX_CONFIG_GENERIC_CLOCKEVENTS: 200442284a8SStephen Boyd if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: 201442284a8SStephen Boyd bc_dev = gdb.parse_and_eval("&tick_broadcast_device") 202442284a8SStephen Boyd text += print_tickdevice(bc_dev, -1) 203442284a8SStephen Boyd text += "\n" 204442284a8SStephen Boyd mask = gdb.parse_and_eval("tick_broadcast_mask") 205442284a8SStephen Boyd mask = pr_cpumask(mask) 206442284a8SStephen Boyd text += "tick_broadcast_mask: {}\n".format(mask) 207442284a8SStephen Boyd if constants.LX_CONFIG_TICK_ONESHOT: 208442284a8SStephen Boyd mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask") 209442284a8SStephen Boyd mask = pr_cpumask(mask) 210442284a8SStephen Boyd text += "tick_broadcast_oneshot_mask: {}\n".format(mask) 211442284a8SStephen Boyd text += "\n" 212442284a8SStephen Boyd 213442284a8SStephen Boyd tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device") 214442284a8SStephen Boyd for cpu in cpus.each_online_cpu(): 215442284a8SStephen Boyd tick_dev = cpus.per_cpu(tick_cpu_devices, cpu) 216442284a8SStephen Boyd text += print_tickdevice(tick_dev, cpu) 217442284a8SStephen Boyd text += "\n" 218442284a8SStephen Boyd 219442284a8SStephen Boyd gdb.write(text) 220442284a8SStephen Boyd 221442284a8SStephen Boyd 222442284a8SStephen BoydLxTimerList() 223