Hello Dave,
It's done. I use *NOW* to replace *OFFSET*. Please check.
At 2013-3-6 22:56, Dave Anderson wrote:
----- Original Message -----
Hello Dave,
Sorry for late. And I think my last mail is not that clear, so I will
add some explanation here.
And firstly, some answers to your question.
1. offset means the offset of the clock to the monotonic time.
2. If offset is 0 or without offset, the clock gets the monotonic time
with it.
3. If offset is not 0, lick clock 0 on cpu 0, the time of this clock is
monotonic time together with the value of offset. Additionally,
expiration of the clock is also based on the offset.
If I want to compare expiration with current time, I should first add
offset with monotonic time(I use uptime in my command, for accurate time
is unable to get), then get the current time of the clock.
Right, so what I was saying is that it doesn't make much sense to
show "OFFSET: 0", and it's also confusing when nothing is shown on
the older versions.
Perhaps there could be a "NOW:" field, where you come up with
per-timer-type algorithms to show a value that relates to the
expires value?
And while you're at it, can you please remove the "HRTIMER_BASES[]"
and also clean up the unnecessary accessible() calls?
Thanks,
Dave
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility
--
--
Regards
Qiao Nuohan
>From ea306a81c53fd6b4e3a6ade6e8ce6ef44a2c7b21 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Thu, 28 Feb 2013 15:04:10 +0800
Subject: [PATCH 1/2] make rbtree manipulation functions global
rbtree manipulation functions were only used by runq cmd. Now make
them global and available to other commands.
---
defs.h | 20 ++++++++++
task.c | 94 ----------------------------------------------
tools.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 148 insertions(+), 94 deletions(-)
diff --git a/defs.h b/defs.h
index 1f693c3..2993f2b 100755
--- a/defs.h
+++ b/defs.h
@@ -2256,6 +2256,20 @@ struct alias_data { /* command alias storage */
char argbuf[1];
};
+struct rb_node
+{
+ unsigned long rb_parent_color;
+#define RB_RED 0
+#define RB_BLACK 1
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
+};
+
+struct rb_root
+{
+ struct rb_node *rb_node;
+};
+
#define NUMBER_STACKFRAMES 4
#define SAVE_RETURN_ADDRESS(retaddr) \
@@ -4082,6 +4096,12 @@ uint16_t swap16(uint16_t, int);
uint32_t swap32(uint32_t, int);
int make_cpumask(char *, ulong *, int, int *);
size_t strlcpy(char *, char *, size_t);
+struct rb_node *rb_first(struct rb_root *);
+struct rb_node *rb_parent(struct rb_node *, struct rb_node *);
+struct rb_node *rb_right(struct rb_node *, struct rb_node *);
+struct rb_node *rb_left(struct rb_node *, struct rb_node *);
+struct rb_node *rb_next(struct rb_node *);
+struct rb_node *rb_last(struct rb_root *);
/*
* symbols.c
diff --git a/task.c b/task.c
index fec9f6a..6fb2b4e 100755
--- a/task.c
+++ b/task.c
@@ -56,13 +56,6 @@ static void dump_runq(void);
static void dump_on_rq_timestamp(void);
static void dump_runqueues(void);
static void dump_prio_array(int, ulong, char *);
-struct rb_root;
-static struct rb_node *rb_first(struct rb_root *);
-struct rb_node;
-static struct rb_node *rb_next(struct rb_node *);
-static struct rb_node *rb_parent(struct rb_node *, struct rb_node *);
-static struct rb_node *rb_right(struct rb_node *, struct rb_node *);
-static struct rb_node *rb_left(struct rb_node *, struct rb_node *);
static void dump_task_runq_entry(struct task_context *);
static void print_group_header_fair(int, ulong, void *);
static void print_parent_task_group_fair(void *, int);
@@ -7529,93 +7522,6 @@ dump_prio_array(int which, ulong k_prio_array, char *u_prio_array)
}
}
-/*
- * CFS scheduler uses Red-Black trees to maintain run queue.
- */
-struct rb_node
-{
- unsigned long rb_parent_color;
-#define RB_RED 0
-#define RB_BLACK 1
- struct rb_node *rb_right;
- struct rb_node *rb_left;
-};
-
-struct rb_root
-{
- struct rb_node *rb_node;
-};
-
-static struct rb_node *
-rb_first(struct rb_root *root)
-{
- struct rb_root rloc;
- struct rb_node *n;
- struct rb_node nloc;
-
- readmem((ulong)root, KVADDR, &rloc, sizeof(struct rb_root),
- "rb_root", FAULT_ON_ERROR);
-
- n = rloc.rb_node;
- if (!n)
- return NULL;
- while (rb_left(n, &nloc))
- n = nloc.rb_left;
-
- return n;
-}
-
-static struct rb_node *
-rb_parent(struct rb_node *node, struct rb_node *nloc)
-{
- readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node),
- "rb_node", FAULT_ON_ERROR);
-
- return (struct rb_node *)(nloc->rb_parent_color & ~3);
-}
-
-static struct rb_node *
-rb_right(struct rb_node *node, struct rb_node *nloc)
-{
- readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node),
- "rb_node", FAULT_ON_ERROR);
-
- return nloc->rb_right;
-}
-
-static struct rb_node *
-rb_left(struct rb_node *node, struct rb_node *nloc)
-{
- readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node),
- "rb_node", FAULT_ON_ERROR);
-
- return nloc->rb_left;
-}
-
-static struct rb_node *
-rb_next(struct rb_node *node)
-{
- struct rb_node nloc;
- struct rb_node *parent;
-
- parent = rb_parent(node, &nloc);
-
- if (parent == node)
- return NULL;
-
- if (nloc.rb_right) {
- node = nloc.rb_right;
- while (rb_left(node, &nloc))
- node = nloc.rb_left;
- return node;
- }
-
- while ((parent = rb_parent(node, &nloc)) && (node == rb_right(parent, &nloc)))
- node = parent;
-
- return parent;
-}
-
#define MAX_GROUP_NUM 200
struct task_group_info {
int use;
diff --git a/tools.c b/tools.c
index d8dd04a..066f7fa 100755
--- a/tools.c
+++ b/tools.c
@@ -5555,3 +5555,131 @@ strlcpy(char *dest, char *src, size_t size)
return ret;
}
+struct rb_node *
+rb_first(struct rb_root *root)
+{
+ struct rb_root rloc;
+ struct rb_node *n;
+ struct rb_node nloc;
+
+ readmem((ulong)root, KVADDR, &rloc, sizeof(struct rb_root),
+ "rb_root", FAULT_ON_ERROR);
+
+ n = rloc.rb_node;
+ if (!n)
+ return NULL;
+ while (rb_left(n, &nloc))
+ n = nloc.rb_left;
+
+ return n;
+}
+
+struct rb_node *
+rb_parent(struct rb_node *node, struct rb_node *nloc)
+{
+ readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node),
+ "rb_node", FAULT_ON_ERROR);
+
+ return (struct rb_node *)(nloc->rb_parent_color & ~3);
+}
+
+struct rb_node *
+rb_right(struct rb_node *node, struct rb_node *nloc)
+{
+ readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node),
+ "rb_node", FAULT_ON_ERROR);
+
+ return nloc->rb_right;
+}
+
+struct rb_node *
+rb_left(struct rb_node *node, struct rb_node *nloc)
+{
+ readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node),
+ "rb_node", FAULT_ON_ERROR);
+
+ return nloc->rb_left;
+}
+
+struct rb_node *
+rb_next(struct rb_node *node)
+{
+ struct rb_node nloc;
+ struct rb_node *parent;
+
+ /* node is destroyed */
+ if (!accessible((ulong)node))
+ return NULL;
+
+ parent = rb_parent(node, &nloc);
+
+ if (parent == node)
+ return NULL;
+
+ if (nloc.rb_right) {
+ /* rb_right is destroyed */
+ if (!accessible((ulong)nloc.rb_right))
+ return NULL;
+
+ node = nloc.rb_right;
+ while (rb_left(node, &nloc)) {
+ /* rb_left is destroyed */
+ if (!accessible((ulong)nloc.rb_left))
+ return NULL;
+ node = nloc.rb_left;
+ }
+ return node;
+ }
+
+ while ((parent = rb_parent(node, &nloc))) {
+ /* parent is destroyed */
+ if (!accessible((ulong)parent))
+ return NULL;
+
+
+ if (node != rb_right(parent, &nloc))
+ break;
+
+ node = parent;
+ }
+
+ return parent;
+}
+
+struct rb_node *
+rb_last(struct rb_root *root)
+{
+ struct rb_node *node;
+ struct rb_node nloc;
+
+ /* meet destroyed data */
+ if (!accessible((ulong)(root + OFFSET(rb_root_rb_node))))
+ return NULL;
+
+ readmem((ulong)(root + OFFSET(rb_root_rb_node)), KVADDR, &node,
+ sizeof(node), "rb_root node", FAULT_ON_ERROR);
+
+ while (1) {
+ if (!node)
+ break;
+
+ /* meet destroyed data */
+ if (!accessible((ulong)node))
+ return NULL;
+
+ readmem((ulong)node, KVADDR, &nloc, sizeof(struct rb_node),
+ "rb_node last", FAULT_ON_ERROR);
+
+ /* meet the last one */
+ if (!nloc.rb_right)
+ break;
+
+ /* meet destroyed data */
+ if (!!accessible((ulong)nloc.rb_right))
+ break;
+
+ node = nloc.rb_right;
+ }
+
+ return node;
+}
--
1.7.1
>From aedcbc777e26ea6e096b37eb7123b7ccabaa34ac Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Thu, 7 Mar 2013 14:10:59 +0800
Subject: [PATCH 2/2] hrtimer: add -r option to command timer
command timer -r is used to display all hrtimers and their related
information.
---
defs.h | 21 ++++
help.c | 70 ++++++++++-
kernel.c | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
symbols.c | 42 +++++++
4 files changed, 510 insertions(+), 8 deletions(-)
diff --git a/defs.h b/defs.h
index 2993f2b..8f03672 100755
--- a/defs.h
+++ b/defs.h
@@ -1848,6 +1848,25 @@ struct offset_table { /* stash of commonly-used offsets */
long vmap_area_list;
long vmap_area_flags;
long vmap_area_vm;
+ long hrtimer_cpu_base_clock_base;
+ long hrtimer_clock_base_offset;
+ long hrtimer_clock_base_active;
+ long hrtimer_clock_base_first;
+ long hrtimer_clock_base_get_time;
+ long hrtimer_base_first;
+ long hrtimer_base_pending;
+ long hrtimer_base_get_time;
+ long hrtimer_node;
+ long hrtimer_list;
+ long hrtimer_softexpires;
+ long hrtimer_expires;
+ long hrtimer_function;
+ long timerqueue_head_next;
+ long timerqueue_node_expires;
+ long timerqueue_node_node;
+ long ktime_t_tv64;
+ long ktime_t_sec;
+ long ktime_t_nsec;
};
struct size_table { /* stash of commonly-used sizes */
@@ -1985,6 +2004,8 @@ struct size_table { /* stash of commonly-used sizes */
long rt_rq;
long task_group;
long vmap_area;
+ long hrtimer_clock_base;
+ long hrtimer_base;
};
struct array_table {
diff --git a/help.c b/help.c
index c542743..2ee6a41 100755
--- a/help.c
+++ b/help.c
@@ -2154,13 +2154,17 @@ NULL
char *help_timer[] = {
"timer",
-"timer queue data",
-" ",
-" This command displays the timer queue entries, both old- and new-style,",
-" in chronological order. In the case of the old-style timers, the",
-" timer_table array index is shown; in the case of the new-style timers, ",
-" the timer_list address is shown. On later kernels, the timer data is",
-" per-cpu.",
+"timer data",
+"[-r]"
+" ",
+" This command provides information of timer. With no arguments, the command",
+" displays the timer queue entries, both old- and new-style, in chronological",
+" order. In the case of the old-style timers, the timer_table array index is",
+" shown; in the case of the new-style timers, the timer_list address is",
+" shown. On later kernels, the timer data is per-cpu.",
+" ",
+" -r shows all hrtimers and their related information. On earlier kernels, ",
+" expire is an integer, and on later kernels, expire is a range.",
"\nEXAMPLES",
" %s> timer",
" JIFFIES",
@@ -2218,6 +2222,60 @@ char *help_timer[] = {
" 18277900 ceebaec0 c01232bb <process_timeout>",
" 18283769 cf739f64 c01232bb <process_timeout>",
" 18331902 cee8af64 c01232bb <process_timeout>",
+" ",
+" Display hrtimers on a 2-cpu system:\n",
+" %s> timer -r",
+" cpu: 0 HRTIMER_CPU_BASE: ffff880002210f40",
+" clock: 0 HRTIMER_CLOCK_BASE: ffff880002210f48",
+" NOW: 1362620950491987011 GET_TIME: ktime_get_real",
+" EXPIRES HRTIMER FUNCTION",
+" (empty)",
+" ",
+" clock: 1 HRTIMER_CLOCK_BASE: ffff880002210f88",
+" NOW: 13820002 GET_TIME: ktime_get",
+" EXPIRES HRTIMER FUNCTION",
+" 13820004000000-13820004000000 ffff880002211040 ffffffff810a0b70 <tick_sched_timer>",
+" 13820047762608-13820057762606 ffff88004ac67918 ffffffff81094d50 <hrtimer_wakeup>",
+" 13820522286784-13820524283783 ffff88004ca09a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13820812094057-13820812144057 ffff88004c18fea8 ffffffff81094d50 <hrtimer_wakeup>",
+" 13823521834929-13823521884929 ffff88004b98fea8 ffffffff81094d50 <hrtimer_wakeup>",
+" 13824044999849-13824044999849 ffff880002211260 ffffffff810d8ab0 <watchdog_timer_fn>",
+" 13826262209346-13826272199344 ffff88004bdcda68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13840047844819-13840077844818 ffff880037acda68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13848261840083-13848291809081 ffff88004ab23a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13850641290754-13850641340754 ffff88004b3ffea8 ffffffff81094d50 <hrtimer_wakeup>",
+" 13885261687273-13885361687273 ffff88004af81a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 14110527437880-14110527437880 ffff88003763b868 ffffffff8106f8b0 <it_real_fn>",
+" 14784522032763-14784622032763 ffff88004c8d3a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 14785261501208-14785361501208 ffff88004bc13a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 15276374899060-15276474899060 ffff88003760ba68 ffffffff81094d50 <hrtimer_wakeup>",
+" 19777527419538-19777527419538 ffff88004b2cf468 ffffffff8106f8b0 <it_real_fn>",
+" 86432266536437-86432366536437 ffff88004dbb9918 ffffffff81094d50 <hrtimer_wakeup>",
+" 86439093359718-86439093409718 ffff88004b139ea8 ffffffff81094d50 <hrtimer_wakeup>",
+" 86783002034854-86783102034854 ffff880049cc5a68 ffffffff81094d50 <hrtimer_wakeup>",
+" ",
+" cpu: 1 HRTIMER_CPU_BASE: ffff880002310f40",
+" clock: 0 HRTIMER_CLOCK_BASE: ffff880002310f48",
+" NOW: 1362620950491987012 GET_TIME: ktime_get_real",
+" EXPIRES HRTIMER FUNCTION",
+" 1362634771895683234-1362634771895733234 ffff88004a887d18 ffffffff81094d50 <hrtimer_wakeup>",
+" 1362634809909532000-1362634809909582000 ffff88004b3bdd18 ffffffff81094d50 <hrtimer_wakeup>",
+" ",
+" clock: 1 HRTIMER_CLOCK_BASE: ffff880002310f88",
+" NOW: 13820003 GET_TIME: ktime_get",
+" EXPIRES HRTIMER FUNCTION",
+" 13820038000000-13820038000000 ffff880002311040 ffffffff810a0b70 <tick_sched_timer>",
+" 13821261379829-13821265374827 ffff88004ab63a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13822261296148-13822265291146 ffff88004bdc3a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13822261387239-13822265382238 ffff88004bf07a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13824046999849-13824046999849 ffff880002311260 ffffffff810d8ab0 <watchdog_timer_fn>",
+" 13834521892661-13834551860659 ffff8800376f9a68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13844070773829-13844070823829 ffff88004c76bea8 ffffffff81094d50 <hrtimer_wakeup>",
+" 13849522920692-13849582858691 ffff88004c29da68 ffffffff81094d50 <hrtimer_wakeup>",
+" 13870524298091-13870524298091 ffff880037b33068 ffffffff8106f8b0 <it_real_fn>",
+" 14437908074941-14437908124941 ffff88004ac8dea8 ffffffff81094d50 <hrtimer_wakeup>",
+" 14439090702884-14439090752884 ffff88004b123ea8 ffffffff81094d50 <hrtimer_wakeup>",
+" 15198126896086-15198226896086 ffff88004bfb3a68 ffffffff81094d50 <hrtimer_wakeup>",
NULL
};
diff --git a/kernel.c b/kernel.c
index c420518..91ca861 100755
--- a/kernel.c
+++ b/kernel.c
@@ -34,6 +34,13 @@ static void display_bh_1(void);
static void display_bh_2(void);
static void display_bh_3(void);
static void display_bh_4(void);
+static void dump_hrtimer_data(void);
+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 *);
+static int get_expires_len(const int, const ulong *);
+static void print_timer(const void *);
+static ulonglong ktime_to_ns(const void *);
static void dump_timer_data(void);
static void dump_timer_data_tvec_bases_v1(void);
static void dump_timer_data_tvec_bases_v2(void);
@@ -638,6 +645,50 @@ kernel_init()
BUG_bytes_init();
kt->flags &= ~PRE_KERNEL_INIT;
+
+ /*
+ * for hrtimer
+ */
+ MEMBER_OFFSET_INIT(hrtimer_cpu_base_clock_base, "hrtimer_cpu_base",
+ "clock_base");
+ MEMBER_OFFSET_INIT(hrtimer_clock_base_offset, "hrtimer_clock_base",
+ "offset");
+ MEMBER_OFFSET_INIT(hrtimer_clock_base_active, "hrtimer_clock_base",
+ "active");
+ MEMBER_OFFSET_INIT(hrtimer_clock_base_first, "hrtimer_clock_base",
+ "first");
+ MEMBER_OFFSET_INIT(hrtimer_clock_base_get_time, "hrtimer_clock_base",
+ "get_time");
+ MEMBER_OFFSET_INIT(hrtimer_base_first, "hrtimer_base", "first");
+ MEMBER_OFFSET_INIT(hrtimer_base_pending, "hrtimer_base", "pending");
+ MEMBER_OFFSET_INIT(hrtimer_base_get_time, "hrtimer_base", "get_time");
+ MEMBER_OFFSET_INIT(hrtimer_node, "hrtimer", "node");
+ MEMBER_OFFSET_INIT(hrtimer_list, "hrtimer", "list");
+ MEMBER_OFFSET_INIT(hrtimer_expires, "hrtimer", "expires");
+ if (INVALID_MEMBER(hrtimer_expires))
+ MEMBER_OFFSET_INIT(hrtimer_expires, "hrtimer", "_expires");
+ if (INVALID_MEMBER(hrtimer_expires)) {
+ MEMBER_OFFSET_INIT(timerqueue_head_next, "timerqueue_head", "next");
+ MEMBER_OFFSET_INIT(timerqueue_node_expires, "timerqueue_node",
+ "expires");
+ MEMBER_OFFSET_INIT(timerqueue_node_node, "timerqueue_node_node",
+ "node");
+ }
+
+ MEMBER_OFFSET_INIT(hrtimer_softexpires, "hrtimer", "_softexpires");
+ MEMBER_OFFSET_INIT(hrtimer_function, "hrtimer", "function");
+ MEMBER_OFFSET_INIT(ktime_t_tv64, "ktime", "tv64");
+ if (INVALID_MEMBER(ktime_t_tv64))
+ MEMBER_OFFSET_INIT(ktime_t_tv64, "ktime_t", "tv64");
+ MEMBER_OFFSET_INIT(ktime_t_sec, "ktime", "sec");
+ if (INVALID_MEMBER(ktime_t_sec))
+ MEMBER_OFFSET_INIT(ktime_t_sec, "ktime_t", "sec");
+ MEMBER_OFFSET_INIT(ktime_t_nsec, "ktime", "nsec");
+ if (INVALID_MEMBER(ktime_t_nsec))
+ MEMBER_OFFSET_INIT(ktime_t_nsec, "ktime_t", "nsec");
+
+ STRUCT_SIZE_INIT(hrtimer_clock_base, "hrtimer_clock_base");
+ STRUCT_SIZE_INIT(hrtimer_base, "hrtimer_base");
}
/*
@@ -6333,10 +6384,17 @@ void
cmd_timer(void)
{
int c;
+ int rflag;
- while ((c = getopt(argcnt, args, "")) != EOF) {
+ rflag = 0;
+
+ while ((c = getopt(argcnt, args, "r")) != EOF) {
switch(c)
{
+ case 'r':
+ rflag = 1;
+ break;
+
default:
argerrs++;
break;
@@ -6346,7 +6404,330 @@ cmd_timer(void)
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
- dump_timer_data();
+ if (rflag)
+ dump_hrtimer_data();
+ else
+ dump_timer_data();
+}
+
+static void
+dump_hrtimer_data(void)
+{
+ int i, j;
+ int hrtimer_max_clock_bases, max_hrtimer_bases;
+ struct syment * hrtimer_bases;
+
+ hrtimer_max_clock_bases = 0;
+ max_hrtimer_bases = 0;
+
+ /*
+ * deside whether hrtimer is available and
+ * set hrtimer_max_clock_bases or max_hrtimer_bases.
+ * if both are not available, hrtimer is not available.
+ */
+ if (VALID_SIZE(hrtimer_clock_base)) {
+ hrtimer_max_clock_bases = 2;
+ if (symbol_exists("ktime_get_boottime"))
+ hrtimer_max_clock_bases = 3;
+ } else if (VALID_SIZE(hrtimer_base)) {
+ max_hrtimer_bases = 2;
+ } else
+ command_not_supported();
+
+ hrtimer_bases = per_cpu_symbol_search("hrtimer_bases");
+ for (i = 0; i < kt->cpus; i++) {
+ if (i)
+ fprintf(fp, "\n");
+ fprintf(fp, "cpu: %d ", i);
+ if (VALID_SIZE(hrtimer_clock_base)) {
+ fprintf(fp, "HRTIMER_CPU_BASE: %lx\n",
+ (ulong)(hrtimer_bases->value +
+ kt->__per_cpu_offset[i]));
+
+ for (j = 0; j < hrtimer_max_clock_bases; j++) {
+ if (j)
+ fprintf(fp, "\n");
+ dump_hrtimer_clock_base(
+ (void *)(hrtimer_bases->value) +
+ kt->__per_cpu_offset[i], j);
+ }
+ } else {
+ fprintf(fp, "\n");
+ for (j = 0; j < max_hrtimer_bases; j++) {
+ if (j)
+ fprintf(fp, "\n");
+ dump_hrtimer_base(
+ (void *)(hrtimer_bases->value) +
+ kt->__per_cpu_offset[i], j);
+ }
+ }
+ }
+}
+
+static int expires_len = VADDR_PRLEN;
+
+static void
+dump_hrtimer_clock_base(const void *hrtimer_bases, const int num)
+{
+ void *base;
+ ulonglong current_time;
+ ulonglong offset;
+ ulong get_time;
+ char buf[BUFSIZE];
+
+ base = (void *)hrtimer_bases + OFFSET(hrtimer_cpu_base_clock_base) +
+ SIZE(hrtimer_clock_base) * num;
+ fprintf(fp, " clock: %d HRTIMER_CLOCK_BASE: %lx\n", num, (ulong)base);
+
+ /* get current time(uptime) */
+ get_uptime(NULL, ¤t_time);
+
+ offset = 0;
+ if (VALID_MEMBER(hrtimer_clock_base_offset))
+ offset = ktime_to_ns(base + OFFSET(hrtimer_clock_base_offset));
+
+ fprintf(fp, " NOW: %lld", current_time + offset);
+
+ readmem((ulong)(base + OFFSET(hrtimer_clock_base_get_time)), KVADDR,
+ &get_time, sizeof(get_time), "hrtimer_clock_base get_time",
+ FAULT_ON_ERROR);
+
+ fprintf(fp ," GET_TIME: %s\n", value_to_symstr(get_time, buf, 0));
+
+ dump_active_timers(base);
+}
+
+static void
+dump_hrtimer_base(const void *hrtimer_bases, const int num)
+{
+ void *base;
+ ulonglong current_time;
+ ulong get_time;
+ char buf[BUFSIZE];
+
+ base = (void *)hrtimer_bases + SIZE(hrtimer_base) * num;
+ fprintf(fp, " clock: %d HRTIMER_BASE: %lx\n", num, (ulong)base);
+
+ /* get current time(uptime) */
+ get_uptime(NULL, ¤t_time);
+ fprintf(fp, " NOW: %lld", current_time);
+
+ readmem((ulong)(base + OFFSET(hrtimer_base_get_time)), KVADDR,
+ &get_time, sizeof(get_time), "hrtimer_base get_time",
+ FAULT_ON_ERROR);
+
+ fprintf(fp ," GET_TIME: %s\n", value_to_symstr(get_time, buf, 0));
+
+ dump_active_timers(base);
+}
+
+static void
+dump_active_timers(const void *base)
+{
+ int next, i, t;
+ struct rb_node *curr;
+ int timer_cnt;
+ ulong *timer_list;
+ void *timer;
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+
+
+ next = 0;
+
+ /* search hrtimers */
+ hq_open();
+ timer_cnt = 0;
+next_one:
+ i = 0;
+
+ /* get the first node */
+ if (VALID_MEMBER(hrtimer_base_pending))
+ readmem((ulong)(base + OFFSET(hrtimer_base_pending) -
+ OFFSET(hrtimer_list) + OFFSET(hrtimer_node)),
+ KVADDR, &curr, sizeof(curr), "hrtimer_base pending",
+ FAULT_ON_ERROR);
+ else if (VALID_MEMBER(hrtimer_base_first))
+ readmem((ulong)(base + OFFSET(hrtimer_base_first)),
+ KVADDR, &curr, sizeof(curr), "hrtimer_base first",
+ FAULT_ON_ERROR);
+ else if (VALID_MEMBER(hrtimer_clock_base_first))
+ readmem((ulong)(base + OFFSET(hrtimer_clock_base_first)),
+ KVADDR, &curr, sizeof(curr), "hrtimer_clock_base first",
+ FAULT_ON_ERROR);
+ else
+ readmem((ulong)(base + OFFSET(hrtimer_clock_base_active) +
+ OFFSET(timerqueue_head_next)),
+ KVADDR, &curr, sizeof(curr), "hrtimer_clock base",
+ FAULT_ON_ERROR);
+
+ while (curr && i < next) {
+ curr = rb_next(curr);
+ i++;
+ }
+
+ if (curr) {
+ if (!hq_enter((ulong)curr)) {
+ error(INFO, "duplicate rb_node: %lx\n", curr);
+ return;
+ }
+
+ timer_cnt++;
+ next++;
+ goto next_one;
+ }
+
+ if (timer_cnt) {
+ timer_list = (ulong *)GETBUF(timer_cnt * sizeof(long));
+ timer_cnt = retrieve_list(timer_list, timer_cnt);
+ }
+ hq_close();
+
+ /* dump hrtimers */
+ /* print header */
+ expires_len = get_expires_len(timer_cnt, timer_list);
+ if (expires_len < 8)
+ expires_len = 8;
+
+ fprintf(fp, " %s %s %s\n",
+ mkstring(buf1, expires_len, CENTER|RJUST, "EXPIRES"),
+ mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "HRTIMER"),
+ mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
+
+ /* print timer */
+ if (!timer_cnt)
+ fprintf(fp, " (empty)\n");
+
+ for (t = 0; t < timer_cnt; t++) {
+ if (VALID_MEMBER(timerqueue_node_node))
+ timer = (void *)(timer_list[t] -
+ OFFSET(timerqueue_node_node) -
+ OFFSET(hrtimer_node));
+ else
+ timer = (void *)(timer_list[t] - OFFSET(hrtimer_node));
+
+ print_timer(timer);
+ }
+}
+
+static int
+get_expires_len(const int timer_cnt, const ulong *timer_list)
+{
+ void *last_timer;
+ char buf[BUFSIZE];
+ ulonglong softexpires, expires;
+ int len;
+
+ len = 0;
+
+ if (!timer_cnt)
+ return 8;
+
+ if (VALID_MEMBER(timerqueue_node_node))
+ last_timer = (void *)(timer_list[timer_cnt - 1] -
+ OFFSET(timerqueue_node_node) -
+ OFFSET(hrtimer_node));
+ else
+ last_timer = (void *)(timer_list[timer_cnt -1] -
+ OFFSET(hrtimer_node));
+
+ /* expire is range */
+ if (VALID_MEMBER(hrtimer_softexpires)) {
+ softexpires = ktime_to_ns(last_timer + OFFSET(hrtimer_softexpires));
+ sprintf(buf, "%lld", softexpires);
+ len += strlen(buf) + 1;
+ }
+
+ if (VALID_MEMBER(hrtimer_expires))
+ expires = ktime_to_ns(last_timer + OFFSET(hrtimer_expires));
+ else
+ expires = ktime_to_ns(last_timer + OFFSET(hrtimer_node) +
+ OFFSET(timerqueue_node_expires));
+
+ sprintf(buf, "%lld", expires);
+ len += strlen(buf);
+
+ return len;
+}
+
+/*
+ * print hrtimer and its related information
+ */
+static void
+print_timer(const void *timer)
+{
+ ulonglong softexpires, expires;
+
+ ulong function;
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+
+ /* align information */
+ fprintf(fp, " ");
+
+ if (!accessible((ulong)timer)) {
+ fprintf(fp, "(destroyed timer)\n");
+ return;
+ }
+
+ if (VALID_MEMBER(hrtimer_expires))
+ expires = ktime_to_ns(timer + OFFSET(hrtimer_expires));
+ else
+ expires = ktime_to_ns(timer + OFFSET(hrtimer_node) +
+ OFFSET(timerqueue_node_expires));
+
+ if (VALID_MEMBER(hrtimer_softexpires)) {
+ softexpires = ktime_to_ns(timer + OFFSET(hrtimer_softexpires));
+ sprintf(buf1, "%lld-%lld", softexpires, expires);
+ } else {
+ sprintf(buf1, "%lld", expires);
+ }
+ fprintf(fp, "%s ", mkstring(buf2, expires_len, CENTER|RJUST, buf1));
+
+ fprintf(fp, "%lx ", (ulong)timer);
+
+ if (readmem((ulong)(timer + OFFSET(hrtimer_function)), KVADDR, &function,
+ sizeof(function), "hrtimer function", QUIET|RETURN_ON_ERROR)) {
+ fprintf(fp, "%lx ", function);
+ fprintf(fp ,"<%s>", value_to_symstr(function, buf3, 0));
+ }
+
+ fprintf(fp, "\n");
+}
+
+/*
+ * convert ktime to ns, only need the address of ktime
+ */
+static ulonglong
+ktime_to_ns(const void *ktime)
+{
+ ulonglong ns;
+
+ ns = 0;
+
+ if (accessible((ulong)ktime)) {
+ if (VALID_MEMBER(ktime_t_tv64)) {
+ readmem((ulong)ktime + OFFSET(ktime_t_tv64), KVADDR, &ns,
+ sizeof(ns), "ktime_t tv64", QUIET|RETURN_ON_ERROR);
+ } else {
+ uint32_t sec, nsec;
+
+ sec = 0;
+ nsec = 0;
+
+ readmem((ulong)ktime + OFFSET(ktime_t_sec), KVADDR, &sec,
+ sizeof(sec), "ktime_t sec", QUIET|RETURN_ON_ERROR);
+
+ readmem((ulong)ktime + OFFSET(ktime_t_nsec), KVADDR, &nsec,
+ sizeof(nsec), "ktime_t nsec", QUIET|RETURN_ON_ERROR);
+
+ ns = sec * 1000000000L + nsec;
+ }
+ }
+
+ return ns;
}
/*
diff --git a/symbols.c b/symbols.c
index 4fb397c..c8e556b 100755
--- a/symbols.c
+++ b/symbols.c
@@ -8860,6 +8860,44 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(rt_rq_highest_prio));
fprintf(fp, " rt_rq_rt_nr_running: %ld\n",
OFFSET(rt_rq_rt_nr_running));
+ fprintf(fp, " hrtimer_cpu_base_clock_base: %ld\n",
+ OFFSET(hrtimer_cpu_base_clock_base));
+ fprintf(fp, " hrtimer_clock_base_offset: %ld\n",
+ OFFSET(hrtimer_clock_base_offset));
+ fprintf(fp, " hrtimer_clock_base_active: %ld\n",
+ OFFSET(hrtimer_clock_base_active));
+ fprintf(fp, " hrtimer_clock_base_first: %ld\n",
+ OFFSET(hrtimer_clock_base_first));
+ fprintf(fp, " hrtimer_clock_base_get_time: %ld\n",
+ OFFSET(hrtimer_clock_base_get_time));
+ fprintf(fp, " hrtimer_base_first: %ld\n",
+ OFFSET(hrtimer_base_first));
+ fprintf(fp, " hrtimer_base_pending: %ld\n",
+ OFFSET(hrtimer_base_pending));
+ fprintf(fp, " hrtimer_base_get_time: %ld\n",
+ OFFSET(hrtimer_base_get_time));
+ fprintf(fp, " hrtimer_node: %ld\n",
+ OFFSET(hrtimer_node));
+ fprintf(fp, " hrtimer_list: %ld\n",
+ OFFSET(hrtimer_list));
+ fprintf(fp, " hrtimer_softexpires: %ld\n",
+ OFFSET(hrtimer_softexpires));
+ fprintf(fp, " hrtimer_expires: %ld\n",
+ OFFSET(hrtimer_expires));
+ fprintf(fp, " hrtimer_function: %ld\n",
+ OFFSET(hrtimer_function));
+ fprintf(fp, " timerqueue_head_next: %ld\n",
+ OFFSET(timerqueue_head_next));
+ fprintf(fp, " timerqueue_node_expires: %ld\n",
+ OFFSET(timerqueue_node_expires));
+ fprintf(fp, " timerqueue_node_node: %ld\n",
+ OFFSET(timerqueue_node_node));
+ fprintf(fp, " ktime_t_tv64: %ld\n",
+ OFFSET(ktime_t_tv64));
+ fprintf(fp, " ktime_t_sec: %ld\n",
+ OFFSET(ktime_t_sec));
+ fprintf(fp, " ktime_t_nsec: %ld\n",
+ OFFSET(ktime_t_nsec));
fprintf(fp, "\n size_table:\n");
fprintf(fp, " page: %ld\n", SIZE(page));
@@ -9081,6 +9119,10 @@ dump_offset_table(char *spec, ulong makestruct)
SIZE(task_group));
fprintf(fp, " vmap_area: %ld\n",
SIZE(vmap_area));
+ fprintf(fp, " hrtimer_clock_base: %ld\n",
+ SIZE(hrtimer_clock_base));
+ fprintf(fp, " hrtimer_base: %ld\n",
+ SIZE(hrtimer_base));
fprintf(fp, "\n array_table:\n");
/*
--
1.7.1
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility