Hello Dave,
The problem is fixed and I changed the display according to your
suggestion. Please check.
One more thing is about current time. I think current time is needed
when debugging, for debuggers can compare the expires of hrtimers with
current time.
When realizing this functionality, I once tried to use xtime plus
wall_to_monotonic. But then I found the value is not that correct. So I
use uptime here. Since it seems strange, what about changing the
display?
--
--
Regards
Qiao Nuohan
>From a897e7492bbf0fe4f225e3f2aaf8b99f6ba91ba9 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Thu, 28 Feb 2013 15:20:06 +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.
e.g.
crash> timer -r
UPTIME: 101476365(1000HZ)
cpu: 0 HRTIMER_CPU_BASE: ffff88004fc0e740
clock: 0 HRTIMER_CLOCK_BASE: ffff88004fc0e780
OFFSET: 0
GET_TIME: ktime_get
ACTIVE TIMERS:
EXPIRES HRTIMER FUNCTION
101476368000000-101476368000000 ffff88004fc0e960 ffffffff810bdf70 <tick_sched_timer>
101476483197066-101476542940065 ffff88004b19dd78 ffffffff810892b0 <hrtimer_wakeup>
101477000000000-101477000000000 ffffffff81dbcca8 ffffffff810a5da0 <sched_rt_period_timer>
101477040836262-101477040886262 ffff88001c3bfe98 ffffffff810892b0 <hrtimer_wakeup>
101480042000000-101480042000000 ffff88004fc0eae0 ffffffff810ef660 <watchdog_timer_fn>
101483658577100-101483658627100 ffff88004b2bfe98 ffffffff810892b0 <hrtimer_wakeup>
101493474313352-101493504313351 ffff88004b67fa08 ffffffff810892b0 <hrtimer_wakeup>
101500659099107-101500718679106 ffff880018cd5a08 ffffffff810892b0 <hrtimer_wakeup>
101501914925514-101501914975514 ffff880049409e98 ffffffff810892b0 <hrtimer_wakeup>
101504763551291-101504763601291 ffff88004b853e98 ffffffff810892b0 <hrtimer_wakeup>
101568283611369-101568383611369 ffff88001315ba08 ffffffff810892b0 <hrtimer_wakeup>
101666437688089-101666537688089 ffff88000244da08 ffffffff810892b0 <hrtimer_wakeup>
103161659082464-103161759082464 ffff880018a9da08 ffffffff810892b0 <hrtimer_wakeup>
103654004944707-103654104944707 ffff88004a83da08 ffffffff810892b0 <hrtimer_wakeup>
104537771975347-104537772025347 ffff880037bd3e98 ffffffff810892b0 <hrtimer_wakeup>
115344661345131-115344661395131 ffff88004c5b1e98 ffffffff810892b0 <hrtimer_wakeup>
167961374089142-167961474089142 ffff88000263ba08 ffffffff810892b0 <hrtimer_wakeup>
clock: 1 HRTIMER_CLOCK_BASE: ffff88004fc0e7c0
OFFSET: 1361933899341424878
GET_TIME: ktime_get_real
ACTIVE TIMERS:
EXPIRES HRTIMER FUNCTION
1362035378304824000-1362035378304874000 ffff880049b23e18 ffffffff810892b0 <hrtimer_wakeup>
1362035413608278294-1362035413608328294 ffff8800167b3e18 ffffffff810892b0 <hrtimer_wakeup>
clock: 2 HRTIMER_CLOCK_BASE: ffff88004fc0e800
OFFSET: 0
GET_TIME: ktime_get_boottime
ACTIVE TIMERS:
EXPIRES HRTIMER FUNCTION
(empty)
cpu: 1 HRTIMER_CPU_BASE: ffff88004fd0e740
clock: 0 HRTIMER_CLOCK_BASE: ffff88004fd0e780
OFFSET: 0
GET_TIME: ktime_get
ACTIVE TIMERS:
EXPIRES HRTIMER FUNCTION
101476375000000-101476375000000 ffff88004fd0e960 ffffffff810bdf70 <tick_sched_timer>
101477437633959-101477441627957 ffff8800131b1a08 ffffffff810892b0 <hrtimer_wakeup>
101477659214391-101477661211390 ffff88000f5afa08 ffffffff810892b0 <hrtimer_wakeup>
101477659425626-101477689395624 ffff88004d5b9a08 ffffffff810892b0 <hrtimer_wakeup>
101478437554506-101478441548504 ffff880002a55a08 ffffffff810892b0 <hrtimer_wakeup>
...
---
defs.h | 22 ++++
help.c | 82 ++++++++++++-
kernel.c | 388 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 484 insertions(+), 8 deletions(-)
diff --git a/defs.h b/defs.h
index 2993f2b..66e75e4 100755
--- a/defs.h
+++ b/defs.h
@@ -1848,6 +1848,26 @@ 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_active;
+ 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 +2005,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..9b106ec 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,72 @@ 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",
+" UPTIME: 101476365(1000HZ)",
+" ",
+" cpu: 0 HRTIMER_CPU_BASE: ffff88004fc0e740",
+" clock: 0 HRTIMER_CLOCK_BASE: ffff88004fc0e780",
+" OFFSET: 0",
+" GET_TIME: ktime_get",
+" ACTIVE TIMERS:",
+" EXPIRES HRTIMER FUNCTION",
+" 101476368000000-101476368000000 ffff88004fc0e960 ffffffff810bdf70 <tick_sched_timer>",
+" 101476483197066-101476542940065 ffff88004b19dd78 ffffffff810892b0 <hrtimer_wakeup>",
+" 101477000000000-101477000000000 ffffffff81dbcca8 ffffffff810a5da0 <sched_rt_period_timer>",
+" 101477040836262-101477040886262 ffff88001c3bfe98 ffffffff810892b0 <hrtimer_wakeup>",
+" 101480042000000-101480042000000 ffff88004fc0eae0 ffffffff810ef660 <watchdog_timer_fn>",
+" 101483658577100-101483658627100 ffff88004b2bfe98 ffffffff810892b0 <hrtimer_wakeup>",
+" 101493474313352-101493504313351 ffff88004b67fa08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101500659099107-101500718679106 ffff880018cd5a08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101501914925514-101501914975514 ffff880049409e98 ffffffff810892b0 <hrtimer_wakeup>",
+" 101504763551291-101504763601291 ffff88004b853e98 ffffffff810892b0 <hrtimer_wakeup>",
+" 101568283611369-101568383611369 ffff88001315ba08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101666437688089-101666537688089 ffff88000244da08 ffffffff810892b0 <hrtimer_wakeup>",
+" 103161659082464-103161759082464 ffff880018a9da08 ffffffff810892b0 <hrtimer_wakeup>",
+" 103654004944707-103654104944707 ffff88004a83da08 ffffffff810892b0 <hrtimer_wakeup>",
+" 104537771975347-104537772025347 ffff880037bd3e98 ffffffff810892b0 <hrtimer_wakeup>",
+" 115344661345131-115344661395131 ffff88004c5b1e98 ffffffff810892b0 <hrtimer_wakeup>",
+" 167961374089142-167961474089142 ffff88000263ba08 ffffffff810892b0 <hrtimer_wakeup>",
+" ",
+" clock: 1 HRTIMER_CLOCK_BASE: ffff88004fc0e7c0",
+" OFFSET: 1361933899341424878",
+" GET_TIME: ktime_get_real",
+" ACTIVE TIMERS:",
+" EXPIRES HRTIMER FUNCTION",
+" 1362035378304824000-1362035378304874000 ffff880049b23e18 ffffffff810892b0 <hrtimer_wakeup>",
+" 1362035413608278294-1362035413608328294 ffff8800167b3e18 ffffffff810892b0 <hrtimer_wakeup>",
+" ",
+" clock: 2 HRTIMER_CLOCK_BASE: ffff88004fc0e800",
+" OFFSET: 0",
+" GET_TIME: ktime_get_boottime",
+" ACTIVE TIMERS:",
+" EXPIRES HRTIMER FUNCTION",
+" (empty)",
+" ",
+" cpu: 1 HRTIMER_CPU_BASE: ffff88004fd0e740",
+" clock: 0 HRTIMER_CLOCK_BASE: ffff88004fd0e780",
+" OFFSET: 0",
+" GET_TIME: ktime_get",
+" ACTIVE TIMERS:",
+" EXPIRES HRTIMER FUNCTION",
+" 101476375000000-101476375000000 ffff88004fd0e960 ffffffff810bdf70 <tick_sched_timer>",
+" 101477437633959-101477441627957 ffff8800131b1a08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101477659214391-101477661211390 ffff88000f5afa08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101477659425626-101477689395624 ffff88004d5b9a08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101478437554506-101478441548504 ffff880002a55a08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101479437513335-101479441507333 ffff88000fa09a08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101479438252334-101479448243333 ffff88000f5d7a08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101479437745656-101479467715653 ffff880002a19a08 ffffffff810892b0 <hrtimer_wakeup>",
+" 101479593440674-101479603440673 ffff880002801908 ffffffff810892b0 <hrtimer_wakeup>",
+" 101480055000000-101480055000000 ffff88004fd0eae0 ffffffff810ef660 <watchdog_timer_fn>",
+" 101516024553200-101516084553199 ffff88004845bd78 ffffffff810892b0 <hrtimer_wakeup>",
+" 101549823430729-101549923430729 ffff88004b26fd78 ffffffff810892b0 <hrtimer_wakeup>",
+" 101556024454821-101556124454820 ffff88004b9bfd78 ffffffff810892b0 <hrtimer_wakeup>",
+" 101582823375135-101582823375135 ffff8800379ba0f8 ffffffff81064bc0 <it_real_fn>",
+" 101789024549606-101789024549606 ffff88004ac0aa78 ffffffff81064bc0 <it_real_fn>",
+" ...",
NULL
};
diff --git a/kernel.c b/kernel.c
index c420518..2f96383 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,51 @@ 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_active, "hrtimer_base", "active");
+ 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 +6385,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 +6405,332 @@ 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;
+ ulonglong jiffies_64;
+ 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();
+
+ /* get current time(uptime) */
+ get_uptime(NULL, &jiffies_64);
+ fprintf(fp, "UPTIME: %lld(%dHZ)\n\n", jiffies_64, machdep->hz);
+
+ 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, "HRTIMER_BASES[]: %lx\n",
+ (ulong)(hrtimer_bases->value) +
+ kt->__per_cpu_offset[i]);
+
+ 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 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);
+
+ if (VALID_MEMBER(hrtimer_clock_base_offset)) {
+ offset = ktime_to_ns(base + OFFSET(hrtimer_clock_base_offset));
+ fprintf(fp, " OFFSET:\t%lld\n", 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:\t%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;
+ 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);
+
+ 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:\t%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, " ACTIVE TIMERS:\n");
+ 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 (accessible((ulong)(timer + OFFSET(hrtimer_function)))) {
+ readmem((ulong)(timer + OFFSET(hrtimer_function)), KVADDR, &function,
+ sizeof(function), "hrtimer function", FAULT_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 (VALID_MEMBER(ktime_t_tv64)) {
+ if (accessible((ulong)ktime + OFFSET(ktime_t_tv64)))
+ readmem((ulong)ktime + OFFSET(ktime_t_tv64), KVADDR, &ns,
+ sizeof(ns), "ktime_t tv64", FAULT_ON_ERROR);
+ } else {
+ uint32_t sec, nsec;
+
+ sec = 0;
+ nsec = 0;
+
+ if (accessible((ulong)ktime + OFFSET(ktime_t_sec)) &&
+ accessible((ulong)ktime + OFFSET(ktime_t_nsec))) {
+ readmem((ulong)ktime + OFFSET(ktime_t_sec), KVADDR, &sec,
+ sizeof(sec), "ktime_t sec", FAULT_ON_ERROR);
+
+ readmem((ulong)ktime + OFFSET(ktime_t_nsec), KVADDR, &nsec,
+ sizeof(nsec), "ktime_t nsec", FAULT_ON_ERROR);
+ }
+
+ ns = sec * 1000000000L + nsec;
+ }
+
+ return ns;
}
/*
--
1.7.1
>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
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility