Back to home page

OSCL-LXR

 
 

    


0001 # SPDX-License-Identifier: GPL-2.0
0002 #
0003 # Copyright 2019 Google LLC.
0004 
0005 import binascii
0006 import gdb
0007 
0008 from linux import constants
0009 from linux import cpus
0010 from linux import rbtree
0011 from linux import utils
0012 
0013 timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type()
0014 hrtimer_type = utils.CachedType("struct hrtimer").get_type()
0015 
0016 
0017 def ktime_get():
0018     """Returns the current time, but not very accurately
0019 
0020     We can't read the hardware timer itself to add any nanoseconds
0021     that need to be added since we last stored the time in the
0022     timekeeper. But this is probably good enough for debug purposes."""
0023     tk_core = gdb.parse_and_eval("&tk_core")
0024 
0025     return tk_core['timekeeper']['tkr_mono']['base']
0026 
0027 
0028 def print_timer(rb_node, idx):
0029     timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(),
0030                                     "node")
0031     timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node")
0032 
0033     function = str(timer['function']).split(" ")[1].strip("<>")
0034     softexpires = timer['_softexpires']
0035     expires = timer['node']['expires']
0036     now = ktime_get()
0037 
0038     text = " #{}: <{}>, {}, ".format(idx, timer, function)
0039     text += "S:{:02x}\n".format(int(timer['state']))
0040     text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format(
0041             softexpires, expires, softexpires - now, expires - now)
0042     return text
0043 
0044 
0045 def print_active_timers(base):
0046     curr = base['active']['next']['node']
0047     curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer())
0048     idx = 0
0049     while curr:
0050         yield print_timer(curr, idx)
0051         curr = rbtree.rb_next(curr)
0052         idx += 1
0053 
0054 
0055 def print_base(base):
0056     text = " .base:       {}\n".format(base.address)
0057     text += " .index:      {}\n".format(base['index'])
0058 
0059     text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution)
0060 
0061     text += " .get_time:   {}\n".format(base['get_time'])
0062     if constants.LX_CONFIG_HIGH_RES_TIMERS:
0063         text += "  .offset:     {} nsecs\n".format(base['offset'])
0064     text += "active timers:\n"
0065     text += "".join([x for x in print_active_timers(base)])
0066     return text
0067 
0068 
0069 def print_cpu(hrtimer_bases, cpu, max_clock_bases):
0070     cpu_base = cpus.per_cpu(hrtimer_bases, cpu)
0071     jiffies = gdb.parse_and_eval("jiffies_64")
0072     tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched")
0073     ts = cpus.per_cpu(tick_sched_ptr, cpu)
0074 
0075     text = "cpu: {}\n".format(cpu)
0076     for i in xrange(max_clock_bases):
0077         text += " clock {}:\n".format(i)
0078         text += print_base(cpu_base['clock_base'][i])
0079 
0080         if constants.LX_CONFIG_HIGH_RES_TIMERS:
0081             fmts = [("  .{}   : {} nsecs", 'expires_next'),
0082                     ("  .{}    : {}", 'hres_active'),
0083                     ("  .{}      : {}", 'nr_events'),
0084                     ("  .{}     : {}", 'nr_retries'),
0085                     ("  .{}       : {}", 'nr_hangs'),
0086                     ("  .{}  : {}", 'max_hang_time')]
0087             text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts])
0088             text += "\n"
0089 
0090         if constants.LX_CONFIG_TICK_ONESHOT:
0091             fmts = [("  .{}      : {}", 'nohz_mode'),
0092                     ("  .{}      : {} nsecs", 'last_tick'),
0093                     ("  .{}   : {}", 'tick_stopped'),
0094                     ("  .{}   : {}", 'idle_jiffies'),
0095                     ("  .{}     : {}", 'idle_calls'),
0096                     ("  .{}    : {}", 'idle_sleeps'),
0097                     ("  .{} : {} nsecs", 'idle_entrytime'),
0098                     ("  .{}  : {} nsecs", 'idle_waketime'),
0099                     ("  .{}  : {} nsecs", 'idle_exittime'),
0100                     ("  .{} : {} nsecs", 'idle_sleeptime'),
0101                     ("  .{}: {} nsecs", 'iowait_sleeptime'),
0102                     ("  .{}   : {}", 'last_jiffies'),
0103                     ("  .{}     : {}", 'next_timer'),
0104                     ("  .{}   : {} nsecs", 'idle_expires')]
0105             text += "\n".join([s.format(f, ts[f]) for s, f in fmts])
0106             text += "\njiffies: {}\n".format(jiffies)
0107 
0108         text += "\n"
0109 
0110     return text
0111 
0112 
0113 def print_tickdevice(td, cpu):
0114     dev = td['evtdev']
0115     text = "Tick Device: mode:     {}\n".format(td['mode'])
0116     if cpu < 0:
0117             text += "Broadcast device\n"
0118     else:
0119             text += "Per CPU device: {}\n".format(cpu)
0120 
0121     text += "Clock Event Device: "
0122     if dev == 0:
0123             text += "<NULL>\n"
0124             return text
0125 
0126     text += "{}\n".format(dev['name'])
0127     text += " max_delta_ns:   {}\n".format(dev['max_delta_ns'])
0128     text += " min_delta_ns:   {}\n".format(dev['min_delta_ns'])
0129     text += " mult:           {}\n".format(dev['mult'])
0130     text += " shift:          {}\n".format(dev['shift'])
0131     text += " mode:           {}\n".format(dev['state_use_accessors'])
0132     text += " next_event:     {} nsecs\n".format(dev['next_event'])
0133 
0134     text += " set_next_event: {}\n".format(dev['set_next_event'])
0135 
0136     members = [('set_state_shutdown', " shutdown: {}\n"),
0137                ('set_state_periodic', " periodic: {}\n"),
0138                ('set_state_oneshot', " oneshot:  {}\n"),
0139                ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
0140                ('tick_resume', " resume:   {}\n")]
0141     for member, fmt in members:
0142         if dev[member]:
0143             text += fmt.format(dev[member])
0144 
0145     text += " event_handler:  {}\n".format(dev['event_handler'])
0146     text += " retries:        {}\n".format(dev['retries'])
0147 
0148     return text
0149 
0150 
0151 def pr_cpumask(mask):
0152     nr_cpu_ids = 1
0153     if constants.LX_NR_CPUS > 1:
0154         nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
0155 
0156     inf = gdb.inferiors()[0]
0157     bits = mask['bits']
0158     num_bytes = (nr_cpu_ids + 7) / 8
0159     buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
0160     buf = binascii.b2a_hex(buf)
0161 
0162     chunks = []
0163     i = num_bytes
0164     while i > 0:
0165         i -= 1
0166         start = i * 2
0167         end = start + 2
0168         chunks.append(buf[start:end])
0169         if i != 0 and i % 4 == 0:
0170             chunks.append(',')
0171 
0172     extra = nr_cpu_ids % 8
0173     if 0 < extra <= 4:
0174         chunks[0] = chunks[0][0]  # Cut off the first 0
0175 
0176     return "".join(chunks)
0177 
0178 
0179 class LxTimerList(gdb.Command):
0180     """Print /proc/timer_list"""
0181 
0182     def __init__(self):
0183         super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
0184 
0185     def invoke(self, arg, from_tty):
0186         hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
0187         max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
0188 
0189         text = "Timer List Version: gdb scripts\n"
0190         text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
0191         text += "now at {} nsecs\n".format(ktime_get())
0192 
0193         for cpu in cpus.each_online_cpu():
0194             text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
0195 
0196         if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
0197             if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
0198                 bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
0199                 text += print_tickdevice(bc_dev, -1)
0200                 text += "\n"
0201                 mask = gdb.parse_and_eval("tick_broadcast_mask")
0202                 mask = pr_cpumask(mask)
0203                 text += "tick_broadcast_mask: {}\n".format(mask)
0204                 if constants.LX_CONFIG_TICK_ONESHOT:
0205                     mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
0206                     mask = pr_cpumask(mask)
0207                     text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
0208                 text += "\n"
0209 
0210             tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
0211             for cpu in cpus.each_online_cpu():
0212                 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
0213                 text += print_tickdevice(tick_dev, cpu)
0214                 text += "\n"
0215 
0216         gdb.write(text)
0217 
0218 
0219 LxTimerList()