[Crash-utility] [PATCH v2] kernel/timers: show time to expire for each timer
Dave Anderson
anderson at redhat.com
Wed Jun 26 18:59:24 UTC 2019
Hi Oleksandr,
Looks good -- queued for crash-7.2.7:
https://github.com/crash-utility/crash/commit/496d503e84147a24bdaf86782ab1d8af2fd76c9e
Thanks,
Dave
----- Original Message -----
> Extend `timer` command to show time to expire (TTE) for each timer.
>
> This is useful to verify what CPU is blocked due to looping with
> interrupts disabled or due to lack of resources to run the vCPU on a
> hypervisor side.
>
> `help` output is amended accordingly. Old examples are replaced with two
> new ones, both are for the vmcore from the modern RHEL8 system.
>
> The commit was tested on the vmcores with the following kernel versions:
>
> * 2.6.18-436.el5
> * 2.6.32-431.el6.x86_64
> * 3.10.0-693.11.6.el7.x86_64
> * 4.18.0-80.1.2.el8_0.x86_64
>
> Signed-off-by: Oleksandr Natalenko <oleksandr at redhat.com>
> ---
> defs.h | 1 +
> help.c | 167 ++++++++++++------------------------
> kernel.c | 255 ++++++++++++++++++++++++++++++++++++++-----------------
> tools.c | 5 +-
> 4 files changed, 236 insertions(+), 192 deletions(-)
>
> diff --git a/defs.h b/defs.h
> index ccffe58..ceb6eb7 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -4387,6 +4387,7 @@ struct machine_specific {
> #define INT_HEX (0x40)
> #define LONGLONG_HEX (0x80)
> #define ZERO_FILL (0x100)
> +#define SLONG_DEC (0x200)
>
> #define INIT_TIME (1)
> #define RUN_TIME (2)
> diff --git a/help.c b/help.c
> index 581e616..4f67ccf 100644
> --- a/help.c
> +++ b/help.c
> @@ -2891,128 +2891,65 @@ char *help_timer[] = {
> " -C cpu Restrict the output to one or more CPUs, where multiple cpu[s]
> can",
> " be specified, for example, as \"1,3,5\", \"1-3\", or
> \"1,3,5-7,10\".",
> "\nEXAMPLES",
> +" Display the timer queue on an SMP system:\n",
> " %s> timer",
> " JIFFIES",
> -" 68102",
> -" EXPIRES TIMER_LIST/TABLE FUNCTION",
> -" 68346 c0241934 c01775d4 <tcp_sltimer_handler>",
> -" 68379 c0241204 c01696d8 <dev_do_watchdog>",
> -" 68523 c7fcdfc0 c0112d6c <process_timeout>",
> -" 68718 c7fd8edc c018719c <irlmp_discovery_timer_expired>",
> -" 68723 timer_table[2] c01c707c <rs_timer>",
> -" 68742 c20c1f7c c0112d6c <process_timeout>",
> -" 68742 c20c1f7c c0112d6c <process_timeout>",
> -" 68742 c20c1f7c c0112d6c <process_timeout>",
> -" 68752 c7fd1fc4 c0112d6c <process_timeout>",
> -" 68752 c7fd1fc4 c0112d6c <process_timeout>",
> -" 68989 c0241d40 c0168060 <neigh_periodic_timer>",
> -" 69028 c2533f7c c0112d6c <process_timeout>",
> -" 69134 c22dd868 c0181948 <unix_destroy_timer>",
> -" 71574 c0241430 c0169ea4 <rt_check_expire>",
> -" 72179 c7fb1c48 c01cb9a0 <vortex_timer>",
> -" 73144 c1b17f10 c0112d6c <process_timeout>",
> -" 73259 c17a5f10 c0112d6c <process_timeout>",
> -" 112929 c203ff10 c0112d6c <process_timeout>",
> -" 372010 c2323f7c c0112d6c <process_timeout>",
> -" 372138 c2191f10 c0112d6c <process_timeout>",
> -" 8653052 c1f13f10 c0112d6c <process_timeout>",
> -" ",
> -" Display the timer queue on a 2-cpu system:\n",
> -" %s> timer",
> -" TVEC_BASES[0]: c1299be0",
> -" JIFFIES",
> -" 18256298",
> -" EXPIRES TIMER_LIST FUNCTION",
> -" 18256406 cd5ddec0 c01232bb <process_timeout>",
> -" 18256677 ceea93e0 c011e3cc <it_real_fn>",
> -" 18256850 ceea7f64 c01232bb <process_timeout>",
> -" 18258751 cd1d4f64 c01232bb <process_timeout>",
> -" 18258792 cf5782f0 c011e3cc <it_real_fn>",
> -" 18261266 c03c9f80 c022fad5 <rt_check_expire>",
> -" 18262196 c02dc2e0 c0233329 <peer_check_expire>",
> -" 18270518 ceb8bf1c c01232bb <process_timeout>",
> -" 18271327 c03c9120 c0222074 <flow_cache_new_hashrnd>",
> -" 18271327 c03ca580 c0233ace <ipfrag_secret_rebuild>",
> -" 18272532 c02d1e18 c0129946 <delayed_work_timer_fn>",
> -" 18276518 c03c9fc0 c022fd40 <rt_secret_rebuild>",
> -" 18332334 ceea9970 c011e3cc <it_real_fn>",
> -" 18332334 cfb6a840 c011e3cc <it_real_fn>",
> -" 18665378 cec25ec0 c01232bb <process_timeout>",
> -" TVEC_BASES[1]: c12a1be0",
> -" JIFFIES",
> -" 18256298",
> -" EXPIRES TIMER_LIST FUNCTION",
> -" 18256493 c02c7d00 c013dad5 <wb_timer_fn>",
> -" 18256499 c12a2db8 c0129946 <delayed_work_timer_fn>",
> -" 18277900 ceebaec0 c01232bb <process_timeout>",
> -" 18283769 cf739f64 c01232bb <process_timeout>",
> -" 18331902 cee8af64 c01232bb <process_timeout>",
> +" 4296291038",
> +" ...",
> +" TIMER_BASES[1][BASE_STD]: ffff9801aba5aa00",
> +" EXPIRES TTE TIMER_LIST FUNCTION",
> +" 4296282997 -8041 ffff9801aba55ce0 ffffffff83a3bda0
> <mce_timer_fn>",
> +" 4296283104 -7934 ffff97fd84bd35e0 ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +" 4296291061 23 ffffa6b283967de0 ffffffff83b29880
> <process_timeout>",
> +" 4296291112 74 ffff9800c9b62ad8 ffffffff83e6b550
> <cursor_timer_handler>",
> +" 4296291345 307 ffff980186d5ef88 ffffffff84146b80
> <tcp_keepalive_timer>",
> +" 4296291484 446 ffff9801a7c54740 ffffffff84147f50
> <tcp_write_timer>",
> +" 4296291997 959 ffffffffc073f880 ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +" 4296296213 5175 ffffa6b28339be18 ffffffff83b29880
> <process_timeout>",
> +" 4296304383 13345 ffff980194ca72a8 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296305724 14686 ffff980194ca6918 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296306036 14998 ffff980194ca6d58 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296306883 15845 ffff980194ca7e58 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296307588 16550 ffff9801aaa27e58 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296307625 16587 ffff980194ca6a28 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296313542 22504 ffff980194ca7c38 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296317680 26642 ffff9800c9149c58 ffffffff840da870
> <neigh_timer_handler>",
> +" 4296317744 26706 ffff9801a5354468 ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +" 4296343322 52284 ffff980194ca63c8 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296343581 52543 ffff980194ca7088 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296343597 52559 ffff9801aaa274c8 ffffffff8412e4e0
> <tw_timer_handler>",
> +" 4296714205 423167 ffffffff84caf3c0 ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +" TIMER_BASES[1][BASE_DEF]: ffff9801aba5bc80",
> +" EXPIRES TTE TIMER_LIST FUNCTION",
> +" 4296291264 226 ffffffff855eb238 ffffffff83c08fb0
> <writeout_period>",
> +" 4296319997 28959 ffffffffc06ede40 ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +" 4296506084 215046 ffff9801aba629c8 ffffffff83ac5ea0
> <idle_worker_timeout>",
> +" ...",
> " ",
> " Display a new-style hrtimer queue:\n",
> " %s> timer -r",
> -" CPU: 0 HRTIMER_CPU_BASE: c1e03fc0",
> -" CLOCK: 0 HRTIMER_CLOCK_BASE: c1e03fc4 [ktime_get_real]",
> -" (empty)",
> -" ",
> -" CLOCK: 1 HRTIMER_CLOCK_BASE: c1e03ff0 [ktime_get]",
> -" CURRENT",
> -" 322894000000",
> -" SOFTEXPIRES EXPIRES HRTIMER FUNCTION",
> -" 322895000000 322895000000 c1e04080 c04833e0 <tick_sched_timer>",
> -" 324022213609 324022213609 c1e041c0 c04b17d0 <watchdog_timer_fn>",
> -" 326766922781 326766972781 f3a45f44 c0477ed0 <hrtimer_wakeup>",
> -" 364516801997 364516851997 f43bbf44 c0477ed0 <hrtimer_wakeup>",
> -" ",
> -" CLOCK: 2 HRTIMER_CLOCK_BASE: c1e0401c [ktime_get_boottime]",
> -" (empty)",
> -" ",
> -" CPU: 1 HRTIMER_CPU_BASE: c1e43fc0",
> -" CLOCK: 0 HRTIMER_CLOCK_BASE: c1e43fc4 [ktime_get_real]",
> -" (empty)",
> -" ",
> -" CLOCK: 1 HRTIMER_CLOCK_BASE: c1e43ff0 [ktime_get]",
> -" CURRENT",
> -" 322894000000",
> -" SOFTEXPIRES EXPIRES HRTIMER FUNCTION",
> -" 322895062500 322895062500 c1e44080 c04833e0 <tick_sched_timer>",
> -" 324087213609 324087213609 c1e441c0 c04b17d0 <watchdog_timer_fn>",
> -" 381034500892 381034550892 f3a1bea0 c0477ed0 <hrtimer_wakeup>",
> -" ",
> -" CLOCK: 2 HRTIMER_CLOCK_BASE: c1e4401c [ktime_get_boottime]",
> -" (empty)",
> " ...",
> -" ",
> -" Display an old-style hrtimer queue:\n",
> -" %s> timer -r",
> -" CPU: 0",
> -" CLOCK: 0 HRTIMER_BASE: ca00dae0 [ktime_get_real]",
> -" (empty)",
> -" ",
> -" CLOCK: 1 HRTIMER_BASE: ca00db0c [ktime_get]",
> -" CURRENT",
> -" 1480537567000000",
> -" EXPIRES HRTIMER FUNCTION",
> -" 1480997557052703 f79c4944 c0427d18 <it_real_fn>",
> -" 1481009329944302 cdcbaf6c c0436a1e <hrtimer_wakeup>",
> -" 1481026181758643 ea01cf6c c0436a1e <hrtimer_wakeup>",
> -" 1481497068511094 f79a6244 c0427d18 <it_real_fn>",
> -" 1481589831928489 f7af6944 c0427d18 <it_real_fn>",
> -" 1481592731187337 f64ed784 c0427d18 <it_real_fn>",
> -" ",
> -" CPU: 1",
> -" CLOCK: 0 HRTIMER_BASE: ca0148c4 [ktime_get_real]",
> +" CPU: 2 HRTIMER_CPU_BASE: ffff9801aba9cf00",
> +" CLOCK: 0 HRTIMER_CLOCK_BASE: ffff9801aba9cf40 [ktime_get]",
> +" CURRENT",
> +" 1623742000000",
> +" SOFTEXPIRES EXPIRES TTE HRTIMER
> FUNCTION",
> +" 1623741000000 1623741000000 -1000000 ffff9801aba9d540
> ffffffff83b3c8e0 <tick_sched_timer>",
> +" 1624024000000 1624024000000 282000000 ffff9801aba9d720
> ffffffff83b7e7a0 <watchdog_timer_fn>",
> +" 1626000939806 1626010929804 2268929804 ffffa6b28399fa40
> ffffffff83b2c1e0 <hrtimer_wakeup>",
> +" 1627576915615 1627576915615 3834915615 ffff9801a5727978
> ffffffff83b365c0 <posix_timer_fn>",
> +" 1627637194488 1627647194487 3905194487 ffffa6b283977db0
> ffffffff83b2c1e0 <hrtimer_wakeup>",
> +" 1629937423000 1629937423000 6195423000 ffff9801a9af2900
> ffffffff83cf3d30 <timerfd_tmrproc>",
> +" ",
> +" CLOCK: 1 HRTIMER_CLOCK_BASE: ffff9801aba9cf80 [ktime_get_real]",
> +" CURRENT",
> +" 1558362388334558243",
> +" SOFTEXPIRES EXPIRES TTE HRTIMER
> FUNCTION",
> +" 1558362389331238000 1558362389331288000 996729757
> ffffa6b28574bcf0 ffffffff83b2c1e0 <hrtimer_wakeup>",
> +" 1558364372000000000 1558364372000000000 1983665441757
> ffff9801a3513278 ffffffff83b365c0 <posix_timer_fn>",
> +" ",
> +" CLOCK: 2 HRTIMER_CLOCK_BASE: ffff9801aba9cfc0
> [ktime_get_boottime]",
> " (empty)",
> -" ",
> -" CLOCK: 1 HRTIMER_BASE: ca0148f0 [ktime_get]",
> -" CURRENT",
> -" 1480537567000000",
> -" EXPIRES HRTIMER FUNCTION",
> -" 1481017523822478 ca3b15c4 c0427d18 <it_real_fn>",
> -" 1481238077723188 f5f35f6c c0436a1e <hrtimer_wakeup>",
> -" 1481492107740948 f5dadf6c c0436a1e <hrtimer_wakeup>",
> -" 1482936527251241 ca1becc4 c0427d18 <it_real_fn>",
> -" 1482936545249010 f7d42e84 c0427d18 <it_real_fn>",
> -" 1492850155229325 ea01ef6c c0436a1e <hrtimer_wakeup>",
> " ...",
> " ",
> NULL
> diff --git a/kernel.c b/kernel.c
> index f01dc2e..818c29a 100644
> --- a/kernel.c
> +++ b/kernel.c
> @@ -42,8 +42,8 @@ static void dump_hrtimer_data(const ulong *cpus);
> static void dump_hrtimer_clock_base(const void *, const int);
> static void dump_hrtimer_base(const void *, const int);
> static void dump_active_timers(const void *, ulonglong);
> -static int get_expires_len(const int, const ulong *, const int);
> -static void print_timer(const void *);
> +static int get_expires_len(const int, const ulong *, ulonglong, const int);
> +static void print_timer(const void *, ulonglong);
> static ulonglong ktime_to_ns(const void *);
> static void dump_timer_data(const ulong *cpus);
> static void dump_timer_data_tvec_bases_v1(const ulong *cpus);
> @@ -52,10 +52,10 @@ static void dump_timer_data_tvec_bases_v3(const ulong
> *cpus);
> static void dump_timer_data_timer_bases(const ulong *cpus);
> struct tv_range;
> static void init_tv_ranges(struct tv_range *, int, int, int);
> -static int do_timer_list(ulong,int, ulong *, void *,ulong *,struct tv_range
> *);
> -static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *);
> +static int do_timer_list(ulong,int, ulong *, void *,ulong *, ulong *, struct
> tv_range *, ulong);
> +static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *, ulong *,
> ulong);
> struct timer_bases_data;
> -static int do_timer_list_v4(struct timer_bases_data *);
> +static int do_timer_list_v4(struct timer_bases_data *, ulong);
> static int compare_timer_data(const void *, const void *);
> static void panic_this_kernel(void);
> static void dump_waitq(ulong, char *);
> @@ -7515,6 +7515,7 @@ dump_hrtimer_data(const ulong *cpus)
>
> static int expires_len = -1;
> static int softexpires_len = -1;
> +static int tte_len = -1;
>
> static void
> dump_hrtimer_clock_base(const void *hrtimer_bases, const int num)
> @@ -7578,6 +7579,7 @@ dump_active_timers(const void *base, ulonglong now)
> char buf2[BUFSIZE];
> char buf3[BUFSIZE];
> char buf4[BUFSIZE];
> + char buf5[BUFSIZE];
>
> next = 0;
> timer_list = 0;
> @@ -7637,10 +7639,11 @@ next_one:
>
> /* dump hrtimers */
> /* print header */
> - expires_len = get_expires_len(timer_cnt, timer_list, 0);
> + expires_len = get_expires_len(timer_cnt, timer_list, 0, 0);
> if (expires_len < 7)
> expires_len = 7;
> - softexpires_len = get_expires_len(timer_cnt, timer_list, 1);
> + softexpires_len = get_expires_len(timer_cnt, timer_list, 0, 1);
> + tte_len = get_expires_len(timer_cnt, timer_list, now, 2);
>
> if (softexpires_len > -1) {
> if (softexpires_len < 11)
> @@ -7650,9 +7653,10 @@ next_one:
> sprintf(buf1, "%lld", now);
> fprintf(fp, " %s\n", mkstring(buf1, softexpires_len,
> CENTER|RJUST, NULL));
> - fprintf(fp, " %s %s %s %s\n",
> + fprintf(fp, " %s %s %s %s %s\n",
> mkstring(buf1, softexpires_len, CENTER|RJUST, "SOFTEXPIRES"),
> mkstring(buf2, expires_len, CENTER|RJUST, "EXPIRES"),
> + mkstring(buf5, tte_len, CENTER|RJUST, "TTE"),
> mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "HRTIMER"),
> mkstring(buf4, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
> } else {
> @@ -7660,8 +7664,9 @@ next_one:
> "CURRENT"));
> sprintf(buf1, "%lld", now);
> fprintf(fp, " %s\n", mkstring(buf1, expires_len, CENTER|RJUST, NULL));
> - fprintf(fp, " %s %s %s\n",
> + fprintf(fp, " %s %s %s %s\n",
> mkstring(buf1, expires_len, CENTER|RJUST, "EXPIRES"),
> + mkstring(buf5, tte_len, CENTER|RJUST, "TTE"),
> mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "HRTIMER"),
> mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
> }
> @@ -7675,12 +7680,12 @@ next_one:
> else
> timer = (void *)(timer_list[t] - OFFSET(hrtimer_node));
>
> - print_timer(timer);
> + print_timer(timer, now);
> }
> }
>
> static int
> -get_expires_len(const int timer_cnt, const ulong *timer_list, const int
> getsoft)
> +get_expires_len(const int timer_cnt, const ulong *timer_list, ulonglong now,
> const int getsoft)
> {
> void *last_timer;
> char buf[BUFSIZE];
> @@ -7700,7 +7705,7 @@ get_expires_len(const int timer_cnt, const ulong
> *timer_list, const int getsoft)
> last_timer = (void *)(timer_list[timer_cnt -1] -
> OFFSET(hrtimer_node));
>
> - if (getsoft) {
> + if (getsoft == 1) {
> /* soft expires exist*/
> if (VALID_MEMBER(hrtimer_softexpires)) {
> softexpires = ktime_to_ns(last_timer +
> @@ -7715,7 +7720,7 @@ get_expires_len(const int timer_cnt, const ulong
> *timer_list, const int getsoft)
> expires = ktime_to_ns(last_timer + OFFSET(hrtimer_node) +
> OFFSET(timerqueue_node_expires));
>
> - sprintf(buf, "%lld", expires);
> + sprintf(buf, "%lld", getsoft ? expires - now : expires);
> len = strlen(buf);
> }
>
> @@ -7726,14 +7731,15 @@ get_expires_len(const int timer_cnt, const ulong
> *timer_list, const int getsoft)
> * print hrtimer and its related information
> */
> static void
> -print_timer(const void *timer)
> +print_timer(const void *timer, ulonglong now)
> {
> - ulonglong softexpires, expires;
> + ulonglong softexpires, expires, tte;
>
> ulong function;
> char buf1[BUFSIZE];
> char buf2[BUFSIZE];
> char buf3[BUFSIZE];
> + char buf4[BUFSIZE];
>
> /* align information */
> fprintf(fp, " ");
> @@ -7764,6 +7770,9 @@ print_timer(const void *timer)
> sprintf(buf1, "%lld", expires);
> fprintf(fp, "%s ", mkstring(buf2, expires_len, CENTER|RJUST, buf1));
>
> + tte = expires - now;
> + fprintf(fp, "%s ", mkstring(buf4, tte_len, SLONG_DEC|RJUST, MKSTR(tte)));
> +
> fprintf(fp, "%lx ", (ulong)timer);
>
> if (readmem((ulong)(timer + OFFSET(hrtimer_function)), KVADDR, &function,
> @@ -7819,6 +7828,7 @@ struct timer_data {
> ulong address;
> ulong expires;
> ulong function;
> + long tte;
> };
>
> struct tv_range {
> @@ -7839,14 +7849,15 @@ dump_timer_data(const ulong *cpus)
> } timer_table[32];
> char buf[BUFSIZE];
> char buf1[BUFSIZE];
> + char buf4[BUFSIZE];
> struct timer_struct *tp;
> - ulong mask, highest, function;
> + ulong mask, highest, highest_tte, function;
> ulong jiffies, timer_jiffies;
> ulong *vec;
> long count;
> int vec_root_size, vec_size;
> struct timer_data *td;
> - int flen, tdx, old_timers_exist;
> + int flen, tlen, tdx, old_timers_exist;
> struct tv_range tv[TVN];
>
> if (kt->flags2 & TIMER_BASES) {
> @@ -7900,15 +7911,15 @@ dump_timer_data(const ulong *cpus)
> init_tv_ranges(tv, vec_root_size, vec_size, 0);
>
> count += do_timer_list(symbol_value("tv1") +
> OFFSET(timer_vec_root_vec),
> - vec_root_size, vec, NULL, NULL, tv);
> + vec_root_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(symbol_value("tv2") + OFFSET(timer_vec_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(symbol_value("tv3") + OFFSET(timer_vec_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
>
> td = (struct timer_data *)
> GETBUF((count*2) * sizeof(struct timer_data));
> @@ -7920,6 +7931,7 @@ dump_timer_data(const ulong *cpus)
> get_symbol_data("timer_active", sizeof(ulong), &timer_active);
>
> highest = 0;
> + highest_tte = 0;
> for (i = 0, mask = 1, tp = timer_table+0; old_timers_exist && mask;
> i++, tp++, mask += mask) {
> if (mask > timer_active)
> @@ -7931,21 +7943,24 @@ dump_timer_data(const ulong *cpus)
> td[tdx].address = i;
> td[tdx].expires = tp->expires;
> td[tdx].function = (ulong)tp->fn;
> + td[tdx].tte = tp->expires - jiffies;
> if (td[tdx].expires > highest)
> highest = td[tdx].expires;
> + if (abs(td[tdx].tte) > highest_tte)
> + highest_tte = abs(td[tdx].tte);
> tdx++;
> }
>
> do_timer_list(symbol_value("tv1") + OFFSET(timer_vec_root_vec),
> - vec_root_size, vec, (void *)td, &highest, tv);
> + vec_root_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
> do_timer_list(symbol_value("tv2") + OFFSET(timer_vec_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
> do_timer_list(symbol_value("tv3") + OFFSET(timer_vec_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
> do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
> tdx = do_timer_list(symbol_value("tv5") + OFFSET(timer_vec_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
>
> qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>
> @@ -7958,13 +7973,21 @@ dump_timer_data(const ulong *cpus)
> fprintf(fp, "%s\n", mkstring(buf, flen, CENTER|LJUST, "JIFFIES"));
> fprintf(fp, "%s\n", mkstring(buf, flen, RJUST|LONG_DEC,MKSTR(jiffies)));
>
> - fprintf(fp, "%s TIMER_LIST/TABLE FUNCTION\n",
> - mkstring(buf, flen, CENTER|LJUST, "EXPIRES"));
> + /* +1 accounts possible "-" sign */
> + sprintf(buf4, "%ld", highest_tte);
> + tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> + fprintf(fp, "%s %s TIMER_LIST/TABLE FUNCTION\n",
> + mkstring(buf, flen, CENTER|LJUST, "EXPIRES"),
> + mkstring(buf4, tlen, CENTER|LJUST, "TTE"));
>
> for (i = 0; i < tdx; i++) {
> fprintf(fp, "%s",
> mkstring(buf, flen, RJUST|LONG_DEC, MKSTR(td[i].expires)));
>
> + fprintf(fp, " %s",
> + mkstring(buf4, tlen, RJUST|SLONG_DEC,
> MKSTR(td[i].tte)));
> +
> if (td[i].address < 32) {
> sprintf(buf, "timer_table[%ld]", td[i].address);
> fprintf(fp, " %s ",
> @@ -8003,15 +8026,16 @@ dump_timer_data(const ulong *cpus)
> static void
> dump_timer_data_tvec_bases_v1(const ulong *cpus)
> {
> - int i, cpu, tdx, flen;
> + int i, cpu, tdx, flen, tlen;
> struct timer_data *td;
> int vec_root_size, vec_size;
> struct tv_range tv[TVN];
> - ulong *vec, jiffies, highest, function;
> + ulong *vec, jiffies, highest, highest_tte, function;
> long count;
> char buf1[BUFSIZE];
> char buf2[BUFSIZE];
> char buf3[BUFSIZE];
> + char buf4[BUFSIZE];
>
> /*
> */
> @@ -8038,33 +8062,35 @@ next_cpu:
> init_tv_ranges(tv, vec_root_size, vec_size, cpu);
>
> count += do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> - vec_root_size, vec, NULL, NULL, tv);
> + vec_root_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
>
> if (count)
> td = (struct timer_data *)
> GETBUF((count*2) * sizeof(struct timer_data));
> tdx = 0;
> highest = 0;
> + highest_tte = 0;
> +
> get_symbol_data("jiffies", sizeof(ulong), &jiffies);
>
> do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> - vec_root_size, vec, (void *)td, &highest, tv);
> + vec_root_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> tdx = do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>
> qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>
> @@ -8077,8 +8103,13 @@ next_cpu:
> fprintf(fp, "%s\n", mkstring(buf1,flen,
> RJUST|LONG_DEC,MKSTR(jiffies)));
>
> - fprintf(fp, "%s %s %s\n",
> + /* +1 accounts possible "-" sign */
> + sprintf(buf4, "%ld", highest_tte);
> + tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> + fprintf(fp, "%s %s %s %s\n",
> mkstring(buf1, flen, CENTER|RJUST, "EXPIRES"),
> + mkstring(buf4, tlen, CENTER|RJUST, "TTE"),
> mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "TIMER_LIST"),
> mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>
> @@ -8086,6 +8117,9 @@ next_cpu:
> fprintf(fp, "%s",
> mkstring(buf1, flen, RJUST|LONG_DEC,
> MKSTR(td[i].expires)));
>
> + fprintf(fp, " %s",
> + mkstring(buf4, tlen, RJUST|SLONG_DEC,
> MKSTR(td[i].tte)));
> +
> fprintf(fp, " %s ", mkstring(buf1,
> MAX(VADDR_PRLEN, strlen("TIMER_LIST")),
> RJUST|CENTER|LONG_HEX, MKSTR(td[i].address)));
> @@ -8123,17 +8157,18 @@ next_cpu:
> static void
> dump_timer_data_tvec_bases_v2(const ulong *cpus)
> {
> - int i, cpu, tdx, flen;
> + int i, cpu, tdx, flen, tlen;
> struct timer_data *td;
> int vec_root_size, vec_size;
> struct tv_range tv[TVN];
> - ulong *vec, jiffies, highest, function;
> + ulong *vec, jiffies, highest, highest_tte, function;
> ulong tvec_bases;
> long count;
> struct syment *sp;
> char buf1[BUFSIZE];
> char buf2[BUFSIZE];
> char buf3[BUFSIZE];
> + char buf4[BUFSIZE];
>
> vec_root_size = (i = ARRAY_LENGTH(tvec_root_s_vec)) ?
> i : get_array_length("tvec_root_s.vec", NULL,
> SIZE(list_head));
> @@ -8180,33 +8215,35 @@ next_cpu:
> init_tv_ranges(tv, vec_root_size, vec_size, cpu);
>
> count += do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> - vec_root_size, vec, NULL, NULL, tv);
> + vec_root_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
> count += do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL, tv);
> + vec_size, vec, NULL, NULL, NULL, tv, 0);
>
> if (count)
> td = (struct timer_data *)
> GETBUF((count*2) * sizeof(struct timer_data));
> tdx = 0;
> highest = 0;
> + highest_tte = 0;
> +
> get_symbol_data("jiffies", sizeof(ulong), &jiffies);
>
> do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> - vec_root_size, vec, (void *)td, &highest, tv);
> + vec_root_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
> tdx = do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest, tv);
> + vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>
> qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>
> @@ -8229,8 +8266,13 @@ next_cpu:
> fprintf(fp, "%s\n", mkstring(buf1,flen,
> RJUST|LONG_DEC,MKSTR(jiffies)));
>
> - fprintf(fp, "%s %s %s\n",
> + /* +1 accounts possible "-" sign */
> + sprintf(buf4, "%ld", highest_tte);
> + tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> + fprintf(fp, "%s %s %s %s\n",
> mkstring(buf1, flen, CENTER|RJUST, "EXPIRES"),
> + mkstring(buf4, tlen, CENTER|RJUST, "TTE"),
> mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "TIMER_LIST"),
> mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>
> @@ -8238,6 +8280,9 @@ next_cpu:
> fprintf(fp, "%s",
> mkstring(buf1, flen, RJUST|LONG_DEC,
> MKSTR(td[i].expires)));
>
> + fprintf(fp, " %s",
> + mkstring(buf4, tlen, RJUST|SLONG_DEC,
> MKSTR(td[i].tte)));
> +
> fprintf(fp, " %s ", mkstring(buf1,
> MAX(VADDR_PRLEN, strlen("TIMER_LIST")),
> RJUST|CENTER|LONG_HEX, MKSTR(td[i].address)));
> @@ -8274,17 +8319,18 @@ next_cpu:
> static void
> dump_timer_data_tvec_bases_v3(const ulong *cpus)
> {
> - int i, cpu, tdx, flen;
> + int i, cpu, tdx, flen, tlen;
> struct timer_data *td;
> int vec_root_size, vec_size;
> struct tv_range tv[TVN];
> - ulong *vec, jiffies, highest, function;
> + ulong *vec, jiffies, highest, highest_tte, function;
> ulong tvec_bases;
> long count, head_size;
> struct syment *sp;
> char buf1[BUFSIZE];
> char buf2[BUFSIZE];
> char buf3[BUFSIZE];
> + char buf4[BUFSIZE];
>
> vec_root_size = vec_size = 0;
> head_size = SIZE(hlist_head);
> @@ -8325,33 +8371,35 @@ next_cpu:
> init_tv_ranges(tv, vec_root_size, vec_size, cpu);
>
> count += do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec),
> - vec_root_size, vec, NULL, NULL);
> + vec_root_size, vec, NULL, NULL, NULL, 0);
> count += do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL);
> + vec_size, vec, NULL, NULL, NULL, 0);
> count += do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL);
> + vec_size, vec, NULL, NULL, NULL, 0);
> count += do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL);
> + vec_size, vec, NULL, NULL, NULL, 0);
> count += do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec),
> - vec_size, vec, NULL, NULL);
> + vec_size, vec, NULL, NULL, NULL, 0);
>
> if (count)
> td = (struct timer_data *)
> GETBUF((count*2) * sizeof(struct timer_data));
> tdx = 0;
> highest = 0;
> + highest_tte = 0;
> +
> get_symbol_data("jiffies", sizeof(ulong), &jiffies);
>
> do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec),
> - vec_root_size, vec, (void *)td, &highest);
> + vec_root_size, vec, (void *)td, &highest, &highest_tte, jiffies);
> do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest);
> + vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
> do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest);
> + vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
> do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest);
> + vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
> tdx = do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec),
> - vec_size, vec, (void *)td, &highest);
> + vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
>
> qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>
> @@ -8369,8 +8417,13 @@ next_cpu:
> fprintf(fp, "%s\n", mkstring(buf1,flen,
> RJUST|LONG_DEC,MKSTR(jiffies)));
>
> - fprintf(fp, "%s %s %s\n",
> + /* +1 accounts possible "-" sign */
> + sprintf(buf4, "%ld", highest_tte);
> + tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> + fprintf(fp, "%s %s %s %s\n",
> mkstring(buf1, flen, CENTER|RJUST, "EXPIRES"),
> + mkstring(buf4, tlen, CENTER|RJUST, "TTE"),
> mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "TIMER_LIST"),
> mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>
> @@ -8378,6 +8431,9 @@ next_cpu:
> fprintf(fp, "%s",
> mkstring(buf1, flen, RJUST|LONG_DEC, MKSTR(td[i].expires)));
>
> + fprintf(fp, " %s",
> + mkstring(buf4, tlen, RJUST|SLONG_DEC, MKSTR(td[i].tte)));
> +
> fprintf(fp, " %s ", mkstring(buf1,
> MAX(VADDR_PRLEN, strlen("TIMER_LIST")),
> RJUST|CENTER|LONG_HEX, MKSTR(td[i].address)));
> @@ -8517,7 +8573,9 @@ do_timer_list(ulong vec_kvaddr,
> ulong *vec,
> void *option,
> ulong *highest,
> - struct tv_range *tv)
> + ulong *highest_tte,
> + struct tv_range *tv,
> + ulong jiffies)
> {
> int i, t;
> int count, tdx;
> @@ -8595,8 +8653,11 @@ do_timer_list(ulong vec_kvaddr,
> td[tdx].address = timer_list[t];
> td[tdx].expires = expires;
> td[tdx].function = function;
> + td[tdx].tte = expires - jiffies;
> if (highest && (expires > *highest))
> *highest = expires;
> + if (highest_tte && (abs(td[tdx].tte)
> > *highest_tte))
> + *highest_tte =
> abs(td[tdx].tte);
> tdx++;
> }
> }
> @@ -8659,8 +8720,11 @@ new_timer_list_format:
> td[tdx].address = timer_list[t];
> td[tdx].expires = expires;
> td[tdx].function = function;
> + td[tdx].tte = expires - jiffies;
> if (highest && (expires > *highest))
> *highest = expires;
> + if (highest_tte && (abs(td[tdx].tte) >
> *highest_tte))
> + *highest_tte = abs(td[tdx].tte);
> tdx++;
> }
> }
> @@ -8677,7 +8741,9 @@ do_timer_list_v3(ulong vec_kvaddr,
> int size,
> ulong *vec,
> void *option,
> - ulong *highest)
> + ulong *highest,
> + ulong *highest_tte,
> + ulong jiffies)
> {
> int i, t;
> int count, tdx;
> @@ -8743,8 +8809,11 @@ do_timer_list_v3(ulong vec_kvaddr,
> td[tdx].address = timer_list[t];
> td[tdx].expires = expires;
> td[tdx].function = function;
> + td[tdx].tte = expires - jiffies;
> if (highest && (expires > *highest))
> *highest = expires;
> + if (highest_tte && (abs(td[tdx].tte) > *highest_tte))
> + *highest_tte = abs(td[tdx].tte);
> tdx++;
> }
> }
> @@ -8766,7 +8835,7 @@ struct timer_bases_data {
> };
>
> static int
> -do_timer_list_v4(struct timer_bases_data *data)
> +do_timer_list_v4(struct timer_bases_data *data, ulong jiffies)
> {
> int i, t, timer_cnt, found;
> struct list_data list_data, *ld;
> @@ -8826,6 +8895,7 @@ do_timer_list_v4(struct timer_bases_data *data)
> data->timers[data->cnt].address = timer_list[t];
> data->timers[data->cnt].expires = expires;
> data->timers[data->cnt].function = function;
> + data->timers[data->cnt].tte = expires - jiffies;
> data->cnt++;
>
> if (data->cnt == data->total) {
> @@ -8852,12 +8922,13 @@ do_timer_list_v4(struct timer_bases_data *data)
> static void
> dump_timer_data_timer_bases(const ulong *cpus)
> {
> - int i, cpu, flen, base, nr_bases, found, display, j = 0;
> + int i, cpu, flen, tlen, base, nr_bases, found, display, j = 0;
> struct syment *sp;
> - ulong timer_base, jiffies, function;
> + ulong timer_base, jiffies, function, highest_tte;
> struct timer_bases_data data;
> char buf1[BUFSIZE];
> char buf2[BUFSIZE];
> + char buf4[BUFSIZE];
>
> if (!(data.num_vectors = get_array_length("timer_base.vectors", NULL, 0)))
> error(FATAL, "cannot determine timer_base.vectors[] array size\n");
> @@ -8912,12 +8983,42 @@ next_base:
> data.cnt = 0;
> data.timer_base = timer_base;
>
> - found = do_timer_list_v4(&data);
> + found = do_timer_list_v4(&data, jiffies);
>
> qsort(data.timers, found, sizeof(struct timer_data), compare_timer_data);
>
> - fprintf(fp, " %s TIMER_LIST FUNCTION\n",
> - mkstring(buf1, flen, LJUST, "EXPIRES"));
> + highest_tte = 0;
> + for (i = 0; i < found; i++) {
> + display = FALSE;
> +
> + if (is_kernel_text(data.timers[i].function)) {
> + display = TRUE;
> + } else {
> + if (readmem(data.timers[i].function, KVADDR, &function,
> + sizeof(ulong), "timer function",
> + RETURN_ON_ERROR|QUIET) && is_kernel_text(function)) {
> + display = TRUE;
> + } else {
> + if (LIVE())
> + display = FALSE;
> + else
> + display = TRUE;
> + }
> + }
> +
> + if (display) {
> + if (abs(data.timers[i].tte) > highest_tte)
> + highest_tte = abs(data.timers[i].tte);
> + }
> + }
> +
> + /* +1 accounts possible "-" sign */
> + sprintf(buf4, "%ld", highest_tte);
> + tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> + fprintf(fp, " %s %s TIMER_LIST FUNCTION\n",
> + mkstring(buf1, flen, LJUST, "EXPIRES"),
> + mkstring(buf4, tlen, LJUST, "TTE"));
>
> for (i = 0; i < found; i++) {
> display = FALSE;
> @@ -8946,6 +9047,8 @@ next_base:
> if (display) {
> fprintf(fp, " %s",
> mkstring(buf1, flen, RJUST|LONG_DEC, MKSTR(data.timers[i].expires)));
> + fprintf(fp, " %s",
> + mkstring(buf4, tlen, RJUST|SLONG_DEC, MKSTR(data.timers[i].tte)));
> mkstring(buf1, VADDR_PRLEN, RJUST|LONG_HEX,
> MKSTR(data.timers[i].address));
> fprintf(fp, " %s ", mkstring(buf2, 16, CENTER, buf1));
> fprintf(fp, "%s <%s>\n",
> diff --git a/tools.c b/tools.c
> index 2d95c3a..5c0e63e 100644
> --- a/tools.c
> +++ b/tools.c
> @@ -1650,11 +1650,14 @@ mkstring(char *s, int size, ulong flags, const char
> *opt)
> int left;
> int right;
>
> - switch (flags & (LONG_DEC|LONG_HEX|INT_HEX|INT_DEC|LONGLONG_HEX|ZERO_FILL))
> + switch (flags &
> (LONG_DEC|SLONG_DEC|LONG_HEX|INT_HEX|INT_DEC|LONGLONG_HEX|ZERO_FILL))
> {
> case LONG_DEC:
> sprintf(s, "%lu", (ulong)opt);
> break;
> + case SLONG_DEC:
> + sprintf(s, "%ld", (ulong)opt);
> + break;
> case LONG_HEX:
> sprintf(s, "%lx", (ulong)opt);
> break;
> --
> 2.22.0
>
>
More information about the Crash-utility
mailing list