diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-15 06:08:51 +0300 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-15 06:08:51 +0300 | 
| commit | 1064d857738187c764c0bd76040f424397f857c7 (patch) | |
| tree | 13d16c0aed50b64c20b8fe235b15172f3c997f15 /scripts/gdb/linux/timerlist.py | |
| parent | 35c99ffa20edd3c24be352d28a63cd3a23121282 (diff) | |
| parent | def0fdae813dbbbbb588bfc5f52856be2e842b35 (diff) | |
| download | linux-1064d857738187c764c0bd76040f424397f857c7.tar.xz | |
Merge branch 'akpm' (patches from Andrew)
Merge more updates from Andrew Morton:
 - a couple of hotfixes
 - almost all of the rest of MM
 - lib/ updates
 - binfmt_elf updates
 - autofs updates
 - quite a lot of misc fixes and updates
    - reiserfs, fatfs
    - signals
    - exec
    - cpumask
    - rapidio
    - sysctl
    - pids
    - eventfd
    - gcov
    - panic
    - pps
 - gdb script updates
 - ipc updates
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (126 commits)
  mm: memcontrol: fix NUMA round-robin reclaim at intermediate level
  mm: memcontrol: fix recursive statistics correctness & scalabilty
  mm: memcontrol: move stat/event counting functions out-of-line
  mm: memcontrol: make cgroup stats and events query API explicitly local
  drivers/virt/fsl_hypervisor.c: prevent integer overflow in ioctl
  drivers/virt/fsl_hypervisor.c: dereferencing error pointers in ioctl
  mm, memcg: rename ambiguously named memory.stat counters and functions
  arch: remove <asm/sizes.h> and <asm-generic/sizes.h>
  treewide: replace #include <asm/sizes.h> with #include <linux/sizes.h>
  fs/block_dev.c: Remove duplicate header
  fs/cachefiles/namei.c: remove duplicate header
  include/linux/sched/signal.h: replace `tsk' with `task'
  fs/coda/psdev.c: remove duplicate header
  ipc: do cyclic id allocation for the ipc object.
  ipc: conserve sequence numbers in ipcmni_extend mode
  ipc: allow boot time extension of IPCMNI from 32k to 16M
  ipc/mqueue: optimize msg_get()
  ipc/mqueue: remove redundant wq task assignment
  ipc: prevent lockup on alloc_msg and free_msg
  scripts/gdb: print cached rate in lx-clk-summary
  ...
Diffstat (limited to 'scripts/gdb/linux/timerlist.py')
| -rw-r--r-- | scripts/gdb/linux/timerlist.py | 219 | 
1 files changed, 219 insertions, 0 deletions
| diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py new file mode 100644 index 000000000000..071d0dd5a634 --- /dev/null +++ b/scripts/gdb/linux/timerlist.py @@ -0,0 +1,219 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2019 Google LLC. + +import binascii +import gdb + +from linux import constants +from linux import cpus +from linux import rbtree +from linux import utils + +timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type() +hrtimer_type = utils.CachedType("struct hrtimer").get_type() + + +def ktime_get(): +    """Returns the current time, but not very accurately + +    We can't read the hardware timer itself to add any nanoseconds +    that need to be added since we last stored the time in the +    timekeeper. But this is probably good enough for debug purposes.""" +    tk_core = gdb.parse_and_eval("&tk_core") + +    return tk_core['timekeeper']['tkr_mono']['base'] + + +def print_timer(rb_node, idx): +    timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(), +                                    "node") +    timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node") + +    function = str(timer['function']).split(" ")[1].strip("<>") +    softexpires = timer['_softexpires'] +    expires = timer['node']['expires'] +    now = ktime_get() + +    text = " #{}: <{}>, {}, ".format(idx, timer, function) +    text += "S:{:02x}\n".format(int(timer['state'])) +    text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format( +            softexpires, expires, softexpires - now, expires - now) +    return text + + +def print_active_timers(base): +    curr = base['active']['next']['node'] +    curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer()) +    idx = 0 +    while curr: +        yield print_timer(curr, idx) +        curr = rbtree.rb_next(curr) +        idx += 1 + + +def print_base(base): +    text = " .base:       {}\n".format(base.address) +    text += " .index:      {}\n".format(base['index']) + +    text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution) + +    text += " .get_time:   {}\n".format(base['get_time']) +    if constants.LX_CONFIG_HIGH_RES_TIMERS: +        text += "  .offset:     {} nsecs\n".format(base['offset']) +    text += "active timers:\n" +    text += "".join([x for x in print_active_timers(base)]) +    return text + + +def print_cpu(hrtimer_bases, cpu, max_clock_bases): +    cpu_base = cpus.per_cpu(hrtimer_bases, cpu) +    jiffies = gdb.parse_and_eval("jiffies_64") +    tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched") +    ts = cpus.per_cpu(tick_sched_ptr, cpu) + +    text = "cpu: {}\n".format(cpu) +    for i in xrange(max_clock_bases): +        text += " clock {}:\n".format(i) +        text += print_base(cpu_base['clock_base'][i]) + +        if constants.LX_CONFIG_HIGH_RES_TIMERS: +            fmts = [("  .{}   : {} nsecs", 'expires_next'), +                    ("  .{}    : {}", 'hres_active'), +                    ("  .{}      : {}", 'nr_events'), +                    ("  .{}     : {}", 'nr_retries'), +                    ("  .{}       : {}", 'nr_hangs'), +                    ("  .{}  : {}", 'max_hang_time')] +            text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts]) +            text += "\n" + +        if constants.LX_CONFIG_TICK_ONESHOT: +            fmts = [("  .{}      : {}", 'nohz_mode'), +                    ("  .{}      : {} nsecs", 'last_tick'), +                    ("  .{}   : {}", 'tick_stopped'), +                    ("  .{}   : {}", 'idle_jiffies'), +                    ("  .{}     : {}", 'idle_calls'), +                    ("  .{}    : {}", 'idle_sleeps'), +                    ("  .{} : {} nsecs", 'idle_entrytime'), +                    ("  .{}  : {} nsecs", 'idle_waketime'), +                    ("  .{}  : {} nsecs", 'idle_exittime'), +                    ("  .{} : {} nsecs", 'idle_sleeptime'), +                    ("  .{}: {} nsecs", 'iowait_sleeptime'), +                    ("  .{}   : {}", 'last_jiffies'), +                    ("  .{}     : {}", 'next_timer'), +                    ("  .{}   : {} nsecs", 'idle_expires')] +            text += "\n".join([s.format(f, ts[f]) for s, f in fmts]) +            text += "\njiffies: {}\n".format(jiffies) + +        text += "\n" + +    return text + + +def print_tickdevice(td, cpu): +    dev = td['evtdev'] +    text = "Tick Device: mode:     {}\n".format(td['mode']) +    if cpu < 0: +            text += "Broadcast device\n" +    else: +            text += "Per CPU device: {}\n".format(cpu) + +    text += "Clock Event Device: " +    if dev == 0: +            text += "<NULL>\n" +            return text + +    text += "{}\n".format(dev['name']) +    text += " max_delta_ns:   {}\n".format(dev['max_delta_ns']) +    text += " min_delta_ns:   {}\n".format(dev['min_delta_ns']) +    text += " mult:           {}\n".format(dev['mult']) +    text += " shift:          {}\n".format(dev['shift']) +    text += " mode:           {}\n".format(dev['state_use_accessors']) +    text += " next_event:     {} nsecs\n".format(dev['next_event']) + +    text += " set_next_event: {}\n".format(dev['set_next_event']) + +    members = [('set_state_shutdown', " shutdown: {}\n"), +               ('set_state_periodic', " periodic: {}\n"), +               ('set_state_oneshot', " oneshot:  {}\n"), +               ('set_state_oneshot_stopped', " oneshot stopped: {}\n"), +               ('tick_resume', " resume:   {}\n")] +    for member, fmt in members: +        if dev[member]: +            text += fmt.format(dev[member]) + +    text += " event_handler:  {}\n".format(dev['event_handler']) +    text += " retries:        {}\n".format(dev['retries']) + +    return text + + +def pr_cpumask(mask): +    nr_cpu_ids = 1 +    if constants.LX_NR_CPUS > 1: +        nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids") + +    inf = gdb.inferiors()[0] +    bits = mask['bits'] +    num_bytes = (nr_cpu_ids + 7) / 8 +    buf = utils.read_memoryview(inf, bits, num_bytes).tobytes() +    buf = binascii.b2a_hex(buf) + +    chunks = [] +    i = num_bytes +    while i > 0: +        i -= 1 +        start = i * 2 +        end = start + 2 +        chunks.append(buf[start:end]) +        if i != 0 and i % 4 == 0: +            chunks.append(',') + +    extra = nr_cpu_ids % 8 +    if 0 < extra <= 4: +        chunks[0] = chunks[0][0]  # Cut off the first 0 + +    return "".join(chunks) + + +class LxTimerList(gdb.Command): +    """Print /proc/timer_list""" + +    def __init__(self): +        super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA) + +    def invoke(self, arg, from_tty): +        hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases") +        max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES") + +        text = "Timer List Version: gdb scripts\n" +        text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases) +        text += "now at {} nsecs\n".format(ktime_get()) + +        for cpu in cpus.each_online_cpu(): +            text += print_cpu(hrtimer_bases, cpu, max_clock_bases) + +        if constants.LX_CONFIG_GENERIC_CLOCKEVENTS: +            if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: +                bc_dev = gdb.parse_and_eval("&tick_broadcast_device") +                text += print_tickdevice(bc_dev, -1) +                text += "\n" +                mask = gdb.parse_and_eval("tick_broadcast_mask") +                mask = pr_cpumask(mask) +                text += "tick_broadcast_mask: {}\n".format(mask) +                if constants.LX_CONFIG_TICK_ONESHOT: +                    mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask") +                    mask = pr_cpumask(mask) +                    text += "tick_broadcast_oneshot_mask: {}\n".format(mask) +                text += "\n" + +            tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device") +            for cpu in cpus.each_online_cpu(): +                tick_dev = cpus.per_cpu(tick_cpu_devices, cpu) +                text += print_tickdevice(tick_dev, cpu) +                text += "\n" + +        gdb.write(text) + + +LxTimerList() | 
