Blame view
kernel/time/timer_list.c
8.94 KB
35728b820 time: Add SPDX li... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
289f480af [PATCH] Add debug... |
2 |
/* |
289f480af [PATCH] Add debug... |
3 4 5 |
* List pending timers * * Copyright(C) 2006, Red Hat, Inc., Ingo Molnar |
289f480af [PATCH] Add debug... |
6 7 8 9 10 11 12 13 |
*/ #include <linux/proc_fs.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/sched.h> #include <linux/seq_file.h> #include <linux/kallsyms.h> |
010704276 sysrq: Reset the ... |
14 |
#include <linux/nmi.h> |
289f480af [PATCH] Add debug... |
15 |
|
7c0f6ba68 Replace <asm/uacc... |
16 |
#include <linux/uaccess.h> |
289f480af [PATCH] Add debug... |
17 |
|
c1797baf6 tick: Move core o... |
18 |
#include "tick-internal.h" |
b3956a896 timer_list: Conve... |
19 20 21 22 23 24 |
struct timer_list_iter { int cpu; bool second_pass; u64 now; }; |
289f480af [PATCH] Add debug... |
25 26 27 28 |
/* * This allows printing both to /proc/timer_list and * to the console (on SysRq-Q): */ |
7de4e7443 timer_list: Reduc... |
29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
__printf(2, 3) static void SEQ_printf(struct seq_file *m, const char *fmt, ...) { va_list args; va_start(args, fmt); if (m) seq_vprintf(m, fmt, args); else vprintk(fmt, args); va_end(args); } |
289f480af [PATCH] Add debug... |
43 44 45 |
static void print_name_offset(struct seq_file *m, void *sym) { |
9281acea6 kallsyms: make KS... |
46 |
char symname[KSYM_NAME_LEN]; |
289f480af [PATCH] Add debug... |
47 |
|
9d65cb4a1 Fix race between ... |
48 |
if (lookup_symbol_name((unsigned long)sym, symname) < 0) |
f59030853 timer debug: Hide... |
49 |
SEQ_printf(m, "<%pK>", sym); |
9d65cb4a1 Fix race between ... |
50 51 |
else SEQ_printf(m, "%s", symname); |
289f480af [PATCH] Add debug... |
52 53 54 |
} static void |
e67ef25a3 timer_list: print... |
55 56 |
print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer, int idx, u64 now) |
289f480af [PATCH] Add debug... |
57 |
{ |
289f480af [PATCH] Add debug... |
58 |
SEQ_printf(m, " #%d: ", idx); |
e67ef25a3 timer_list: print... |
59 |
print_name_offset(m, taddr); |
289f480af [PATCH] Add debug... |
60 61 |
SEQ_printf(m, ", "); print_name_offset(m, timer->function); |
203cbf77d hrtimer: Handle r... |
62 |
SEQ_printf(m, ", S:%02x", timer->state); |
289f480af [PATCH] Add debug... |
63 64 |
SEQ_printf(m, " "); |
704af52bd hrtimer: show the... |
65 66 67 |
SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs] ", (unsigned long long)ktime_to_ns(hrtimer_get_softexpires(timer)), |
cc584b213 hrtimer: convert ... |
68 |
(unsigned long long)ktime_to_ns(hrtimer_get_expires(timer)), |
704af52bd hrtimer: show the... |
69 |
(long long)(ktime_to_ns(hrtimer_get_softexpires(timer)) - now), |
cc584b213 hrtimer: convert ... |
70 |
(long long)(ktime_to_ns(hrtimer_get_expires(timer)) - now)); |
289f480af [PATCH] Add debug... |
71 72 73 74 75 76 77 78 |
} static void print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, u64 now) { struct hrtimer *timer, tmp; unsigned long next = 0, i; |
998adc3dd hrtimers: Convert... |
79 |
struct timerqueue_node *curr; |
289f480af [PATCH] Add debug... |
80 81 82 83 |
unsigned long flags; next_one: i = 0; |
010704276 sysrq: Reset the ... |
84 85 |
touch_nmi_watchdog(); |
ecb49d1a6 hrtimers: Convert... |
86 |
raw_spin_lock_irqsave(&base->cpu_base->lock, flags); |
289f480af [PATCH] Add debug... |
87 |
|
998adc3dd hrtimers: Convert... |
88 |
curr = timerqueue_getnext(&base->active); |
289f480af [PATCH] Add debug... |
89 90 91 92 93 |
/* * Crude but we have to do this O(N*N) thing, because * we have to unlock the base when printing: */ while (curr && i < next) { |
998adc3dd hrtimers: Convert... |
94 |
curr = timerqueue_iterate_next(curr); |
289f480af [PATCH] Add debug... |
95 96 97 98 |
i++; } if (curr) { |
998adc3dd hrtimers: Convert... |
99 |
timer = container_of(curr, struct hrtimer, node); |
289f480af [PATCH] Add debug... |
100 |
tmp = *timer; |
ecb49d1a6 hrtimers: Convert... |
101 |
raw_spin_unlock_irqrestore(&base->cpu_base->lock, flags); |
289f480af [PATCH] Add debug... |
102 |
|
e67ef25a3 timer_list: print... |
103 |
print_timer(m, timer, &tmp, i, now); |
289f480af [PATCH] Add debug... |
104 105 106 |
next++; goto next_one; } |
ecb49d1a6 hrtimers: Convert... |
107 |
raw_spin_unlock_irqrestore(&base->cpu_base->lock, flags); |
289f480af [PATCH] Add debug... |
108 109 110 111 112 |
} static void print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now) { |
f59030853 timer debug: Hide... |
113 114 |
SEQ_printf(m, " .base: %pK ", base); |
398ca17fb hrtimer: Get rid ... |
115 116 |
SEQ_printf(m, " .index: %d ", base->index); |
7551b02b9 timer_list: Remov... |
117 118 |
SEQ_printf(m, " .resolution: %u nsecs ", hrtimer_resolution); |
398ca17fb hrtimer: Get rid ... |
119 |
|
289f480af [PATCH] Add debug... |
120 121 122 123 124 |
SEQ_printf(m, " .get_time: "); print_name_offset(m, base->get_time); SEQ_printf(m, " "); #ifdef CONFIG_HIGH_RES_TIMERS |
9b04bd275 Fix printk format... |
125 126 127 |
SEQ_printf(m, " .offset: %Lu nsecs ", (unsigned long long) ktime_to_ns(base->offset)); |
289f480af [PATCH] Add debug... |
128 129 130 |
#endif SEQ_printf(m, "active timers: "); |
38bf985b0 timer_list: Add t... |
131 |
print_active_timers(m, base, now + ktime_to_ns(base->offset)); |
289f480af [PATCH] Add debug... |
132 133 134 135 136 137 |
} static void print_cpu(struct seq_file *m, int cpu, u64 now) { struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); int i; |
129f1d2c5 timer_list: Fix p... |
138 139 |
SEQ_printf(m, "cpu: %d ", cpu); |
289f480af [PATCH] Add debug... |
140 141 142 143 144 145 |
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { SEQ_printf(m, " clock %d: ", i); print_base(m, cpu_base->clock_base + i, now); } #define P(x) \ |
9b04bd275 Fix printk format... |
146 147 148 |
SEQ_printf(m, " .%-15s: %Lu ", #x, \ (unsigned long long)(cpu_base->x)) |
289f480af [PATCH] Add debug... |
149 |
#define P_ns(x) \ |
9b04bd275 Fix printk format... |
150 151 152 |
SEQ_printf(m, " .%-15s: %Lu nsecs ", #x, \ (unsigned long long)(ktime_to_ns(cpu_base->x))) |
289f480af [PATCH] Add debug... |
153 154 155 156 157 |
#ifdef CONFIG_HIGH_RES_TIMERS P_ns(expires_next); P(hres_active); P(nr_events); |
41d2e4949 hrtimer: Tune hrt... |
158 159 |
P(nr_retries); P(nr_hangs); |
a6ffebce7 hrtimer: Make the... |
160 |
P(max_hang_time); |
289f480af [PATCH] Add debug... |
161 162 163 164 165 166 |
#endif #undef P #undef P_ns #ifdef CONFIG_TICK_ONESHOT # define P(x) \ |
9b04bd275 Fix printk format... |
167 168 169 |
SEQ_printf(m, " .%-15s: %Lu ", #x, \ (unsigned long long)(ts->x)) |
289f480af [PATCH] Add debug... |
170 |
# define P_ns(x) \ |
9b04bd275 Fix printk format... |
171 172 173 |
SEQ_printf(m, " .%-15s: %Lu nsecs ", #x, \ (unsigned long long)(ktime_to_ns(ts->x))) |
289f480af [PATCH] Add debug... |
174 175 176 |
{ struct tick_sched *ts = tick_get_tick_sched(cpu); P(nohz_mode); |
f5d411c91 nohz: Rename ts->... |
177 |
P_ns(last_tick); |
289f480af [PATCH] Add debug... |
178 179 180 181 182 |
P(tick_stopped); P(idle_jiffies); P(idle_calls); P(idle_sleeps); P_ns(idle_entrytime); |
5df7fa1c6 tick-sched: add m... |
183 184 |
P_ns(idle_waketime); P_ns(idle_exittime); |
289f480af [PATCH] Add debug... |
185 |
P_ns(idle_sleeptime); |
0224cf4c5 sched: Intoduce g... |
186 |
P_ns(iowait_sleeptime); |
289f480af [PATCH] Add debug... |
187 |
P(last_jiffies); |
c1ad348b4 tick: Nohz: Rewor... |
188 |
P(next_timer); |
289f480af [PATCH] Add debug... |
189 |
P_ns(idle_expires); |
9b04bd275 Fix printk format... |
190 191 192 |
SEQ_printf(m, "jiffies: %Lu ", (unsigned long long)jiffies); |
289f480af [PATCH] Add debug... |
193 194 195 196 197 |
} #endif #undef P #undef P_ns |
60cf7ea84 timer_list: Split... |
198 199 |
SEQ_printf(m, " "); |
289f480af [PATCH] Add debug... |
200 201 202 203 |
} #ifdef CONFIG_GENERIC_CLOCKEVENTS static void |
c5b77a3d3 timer_list: print... |
204 |
print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu) |
289f480af [PATCH] Add debug... |
205 206 |
{ struct clock_event_device *dev = td->evtdev; |
010704276 sysrq: Reset the ... |
207 |
touch_nmi_watchdog(); |
129f1d2c5 timer_list: Fix p... |
208 209 |
SEQ_printf(m, "Tick Device: mode: %d ", td->mode); |
c5b77a3d3 timer_list: print... |
210 211 212 213 214 215 |
if (cpu < 0) SEQ_printf(m, "Broadcast device "); else SEQ_printf(m, "Per CPU device: %d ", cpu); |
289f480af [PATCH] Add debug... |
216 217 218 219 220 221 222 223 224 |
SEQ_printf(m, "Clock Event Device: "); if (!dev) { SEQ_printf(m, "<NULL> "); return; } SEQ_printf(m, "%s ", dev->name); |
97813f2fe nohz: Allow 32-bi... |
225 226 227 228 229 230 |
SEQ_printf(m, " max_delta_ns: %llu ", (unsigned long long) dev->max_delta_ns); SEQ_printf(m, " min_delta_ns: %llu ", (unsigned long long) dev->min_delta_ns); |
23af368e9 clockevents: Use ... |
231 232 233 234 |
SEQ_printf(m, " mult: %u ", dev->mult); SEQ_printf(m, " shift: %u ", dev->shift); |
eef7635a2 clockevents: Remo... |
235 236 |
SEQ_printf(m, " mode: %d ", clockevent_get_state(dev)); |
289f480af [PATCH] Add debug... |
237 238 239 240 241 242 243 244 |
SEQ_printf(m, " next_event: %Ld nsecs ", (unsigned long long) ktime_to_ns(dev->next_event)); SEQ_printf(m, " set_next_event: "); print_name_offset(m, dev->set_next_event); SEQ_printf(m, " "); |
eef7635a2 clockevents: Remo... |
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
if (dev->set_state_shutdown) { SEQ_printf(m, " shutdown: "); print_name_offset(m, dev->set_state_shutdown); SEQ_printf(m, " "); } if (dev->set_state_periodic) { SEQ_printf(m, " periodic: "); print_name_offset(m, dev->set_state_periodic); SEQ_printf(m, " "); } if (dev->set_state_oneshot) { SEQ_printf(m, " oneshot: "); print_name_offset(m, dev->set_state_oneshot); SEQ_printf(m, " "); } if (dev->set_state_oneshot_stopped) { SEQ_printf(m, " oneshot stopped: "); print_name_offset(m, dev->set_state_oneshot_stopped); SEQ_printf(m, " "); } if (dev->tick_resume) { SEQ_printf(m, " resume: "); print_name_offset(m, dev->tick_resume); |
bd624d75d clockevents: Intr... |
276 277 |
SEQ_printf(m, " "); |
bd624d75d clockevents: Intr... |
278 |
} |
289f480af [PATCH] Add debug... |
279 280 281 282 283 |
SEQ_printf(m, " event_handler: "); print_name_offset(m, dev->event_handler); SEQ_printf(m, " "); |
80a05b9ff clockevents: Sani... |
284 285 |
SEQ_printf(m, " retries: %lu ", dev->retries); |
60cf7ea84 timer_list: Split... |
286 287 |
SEQ_printf(m, " "); |
289f480af [PATCH] Add debug... |
288 |
} |
60cf7ea84 timer_list: Split... |
289 |
static void timer_list_show_tickdevices_header(struct seq_file *m) |
289f480af [PATCH] Add debug... |
290 |
{ |
289f480af [PATCH] Add debug... |
291 |
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST |
c5b77a3d3 timer_list: print... |
292 |
print_tickdevice(m, tick_get_broadcast_device(), -1); |
1ef09cd71 tick-broadcast: F... |
293 294 295 |
SEQ_printf(m, "tick_broadcast_mask: %*pb ", cpumask_pr_args(tick_get_broadcast_mask())); |
289f480af [PATCH] Add debug... |
296 |
#ifdef CONFIG_TICK_ONESHOT |
1ef09cd71 tick-broadcast: F... |
297 298 299 |
SEQ_printf(m, "tick_broadcast_oneshot_mask: %*pb ", cpumask_pr_args(tick_get_broadcast_oneshot_mask())); |
289f480af [PATCH] Add debug... |
300 301 302 303 |
#endif SEQ_printf(m, " "); #endif |
289f480af [PATCH] Add debug... |
304 |
} |
289f480af [PATCH] Add debug... |
305 |
#endif |
b3956a896 timer_list: Conve... |
306 |
static inline void timer_list_header(struct seq_file *m, u64 now) |
289f480af [PATCH] Add debug... |
307 |
{ |
c1ad348b4 tick: Nohz: Rewor... |
308 309 |
SEQ_printf(m, "Timer List Version: v0.8 "); |
289f480af [PATCH] Add debug... |
310 311 312 313 |
SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d ", HRTIMER_MAX_CLOCK_BASES); SEQ_printf(m, "now at %Ld nsecs ", (unsigned long long)now); |
60cf7ea84 timer_list: Split... |
314 315 |
SEQ_printf(m, " "); |
b3956a896 timer_list: Conve... |
316 |
} |
b3956a896 timer_list: Conve... |
317 318 319 320 321 322 |
void sysrq_timer_list_show(void) { u64 now = ktime_to_ns(ktime_get()); int cpu; timer_list_header(NULL, now); |
289f480af [PATCH] Add debug... |
323 324 |
for_each_online_cpu(cpu) |
b3956a896 timer_list: Conve... |
325 |
print_cpu(NULL, cpu, now); |
289f480af [PATCH] Add debug... |
326 |
|
60cf7ea84 timer_list: Split... |
327 |
#ifdef CONFIG_GENERIC_CLOCKEVENTS |
b3956a896 timer_list: Conve... |
328 |
timer_list_show_tickdevices_header(NULL); |
60cf7ea84 timer_list: Split... |
329 |
for_each_online_cpu(cpu) |
b3956a896 timer_list: Conve... |
330 |
print_tickdevice(NULL, tick_get_device(cpu), cpu); |
60cf7ea84 timer_list: Split... |
331 |
#endif |
b3956a896 timer_list: Conve... |
332 333 |
return; } |
289f480af [PATCH] Add debug... |
334 |
|
a9314773a timer_list: Guard... |
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
#ifdef CONFIG_PROC_FS static int timer_list_show(struct seq_file *m, void *v) { struct timer_list_iter *iter = v; if (iter->cpu == -1 && !iter->second_pass) timer_list_header(m, iter->now); else if (!iter->second_pass) print_cpu(m, iter->cpu, iter->now); #ifdef CONFIG_GENERIC_CLOCKEVENTS else if (iter->cpu == -1 && iter->second_pass) timer_list_show_tickdevices_header(m); else print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu); #endif return 0; } |
84a78a650 timer_list: corre... |
352 |
static void *move_iter(struct timer_list_iter *iter, loff_t offset) |
b3956a896 timer_list: Conve... |
353 |
{ |
84a78a650 timer_list: corre... |
354 355 356 |
for (; offset; offset--) { iter->cpu = cpumask_next(iter->cpu, cpu_online_mask); if (iter->cpu >= nr_cpu_ids) { |
b3956a896 timer_list: Conve... |
357 |
#ifdef CONFIG_GENERIC_CLOCKEVENTS |
84a78a650 timer_list: corre... |
358 359 360 361 362 |
if (!iter->second_pass) { iter->cpu = -1; iter->second_pass = true; } else return NULL; |
b3956a896 timer_list: Conve... |
363 |
#else |
84a78a650 timer_list: corre... |
364 |
return NULL; |
b3956a896 timer_list: Conve... |
365 |
#endif |
84a78a650 timer_list: corre... |
366 |
} |
b3956a896 timer_list: Conve... |
367 368 |
} return iter; |
289f480af [PATCH] Add debug... |
369 |
} |
84a78a650 timer_list: corre... |
370 371 372 373 374 375 376 377 378 379 |
static void *timer_list_start(struct seq_file *file, loff_t *offset) { struct timer_list_iter *iter = file->private; if (!*offset) iter->now = ktime_to_ns(ktime_get()); iter->cpu = -1; iter->second_pass = false; return move_iter(iter, *offset); } |
b3956a896 timer_list: Conve... |
380 |
static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset) |
289f480af [PATCH] Add debug... |
381 |
{ |
b3956a896 timer_list: Conve... |
382 |
struct timer_list_iter *iter = file->private; |
b3956a896 timer_list: Conve... |
383 |
++*offset; |
84a78a650 timer_list: corre... |
384 |
return move_iter(iter, 1); |
289f480af [PATCH] Add debug... |
385 |
} |
b3956a896 timer_list: Conve... |
386 387 388 389 390 391 392 393 394 395 |
static void timer_list_stop(struct seq_file *seq, void *v) { } static const struct seq_operations timer_list_sops = { .start = timer_list_start, .next = timer_list_next, .stop = timer_list_stop, .show = timer_list_show, }; |
289f480af [PATCH] Add debug... |
396 397 398 |
static int __init init_timer_list_procfs(void) { struct proc_dir_entry *pe; |
44414d82c proc: introduce p... |
399 400 |
pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops, sizeof(struct timer_list_iter), NULL); |
289f480af [PATCH] Add debug... |
401 402 |
if (!pe) return -ENOMEM; |
289f480af [PATCH] Add debug... |
403 404 405 |
return 0; } __initcall(init_timer_list_procfs); |
a9314773a timer_list: Guard... |
406 |
#endif |