• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 range(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    if type(buf) is not str:
162        buf=buf.decode()
163
164    chunks = []
165    i = num_bytes
166    while i > 0:
167        i -= 1
168        start = i * 2
169        end = start + 2
170        chunks.append(buf[start:end])
171        if i != 0 and i % 4 == 0:
172            chunks.append(',')
173
174    extra = nr_cpu_ids % 8
175    if 0 < extra <= 4:
176        chunks[0] = chunks[0][0]  # Cut off the first 0
177
178    return "".join(chunks)
179
180
181class LxTimerList(gdb.Command):
182    """Print /proc/timer_list"""
183
184    def __init__(self):
185        super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
186
187    def invoke(self, arg, from_tty):
188        hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
189        max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
190
191        text = "Timer List Version: gdb scripts\n"
192        text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
193        text += "now at {} nsecs\n".format(ktime_get())
194
195        for cpu in cpus.each_online_cpu():
196            text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
197
198        if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
199            if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
200                bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
201                text += print_tickdevice(bc_dev, -1)
202                text += "\n"
203                mask = gdb.parse_and_eval("tick_broadcast_mask")
204                mask = pr_cpumask(mask)
205                text += "tick_broadcast_mask: {}\n".format(mask)
206                if constants.LX_CONFIG_TICK_ONESHOT:
207                    mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
208                    mask = pr_cpumask(mask)
209                    text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
210                text += "\n"
211
212            tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
213            for cpu in cpus.each_online_cpu():
214                tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
215                text += print_tickdevice(tick_dev, cpu)
216                text += "\n"
217
218        gdb.write(text)
219
220
221LxTimerList()
222