----- 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.
> 
> The commit doesn't implement human-readable format for TTE. This will
> be addressed in a subsequent submission once this one is refined.

OK, so far, so good...

> 
> `help` output is not amended since I do not have original vmcores to
> preserve old printout. Should I replace it with my own data, or you can
> run `timer` on those vmcores?

I can't even find any old vmcores that still have "timer_table" entries,
so yeah, I would go ahead an replace it with your own data.

Thanks,
  Dave


> 
> 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 <[email protected]>
> ---
>  defs.h   |   1 +
>  kernel.c | 255 ++++++++++++++++++++++++++++++++++++++-----------------
>  tools.c  |   5 +-
>  3 files changed, 184 insertions(+), 77 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/kernel.c b/kernel.c
> index 22909d2..77cdc16 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 *);
> @@ -7504,6 +7504,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)
> @@ -7567,6 +7568,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;
> @@ -7626,10 +7628,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)
> @@ -7639,9 +7642,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 {
> @@ -7649,8 +7653,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"));
>       }
> @@ -7664,12 +7669,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];
> @@ -7689,7 +7694,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 +
> @@ -7704,7 +7709,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);
>       }
>  
> @@ -7715,14 +7720,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, "  ");
> @@ -7753,6 +7759,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,
> @@ -7808,6 +7817,7 @@ struct timer_data {
>       ulong address;
>       ulong expires;
>       ulong function;
> +     long tte;
>  };
>  
>  struct tv_range {
> @@ -7828,14 +7838,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) {
> @@ -7889,15 +7900,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));
> @@ -7909,6 +7920,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)
> @@ -7920,21 +7932,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);
>  
> @@ -7947,13 +7962,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  ",
> @@ -7992,15 +8015,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];
>  
>       /*
>           */
> @@ -8027,33 +8051,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);
>  
> @@ -8066,8 +8092,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"));
>  
> @@ -8075,6 +8106,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)));
> @@ -8112,17 +8146,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));
> @@ -8169,33 +8204,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);
>  
> @@ -8218,8 +8255,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"));
>  
> @@ -8227,6 +8269,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)));
> @@ -8263,17 +8308,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);
> @@ -8314,33 +8360,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);
>  
> @@ -8358,8 +8406,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"));
>  
> @@ -8367,6 +8420,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)));
> @@ -8506,7 +8562,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;
> @@ -8584,8 +8642,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++;
>                                  }
>                       }
> @@ -8648,8 +8709,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++;
>                          }
>               }
> @@ -8666,7 +8730,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;
> @@ -8732,8 +8798,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++;
>                       }
>               }
> @@ -8755,7 +8824,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;
> @@ -8815,6 +8884,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) {
> @@ -8841,12 +8911,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");
> @@ -8901,12 +8972,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;
> @@ -8935,6 +9036,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
> 
> 

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to