Commit c5c061b8 authored by Venki Pallipadi's avatar Venki Pallipadi Committed by Linus Torvalds

Add a flag to indicate deferrable timers in /proc/timer_stats

Add a flag in /proc/timer_stats to indicate deferrable timers.  This will
let developers/users to differentiate between types of tiemrs in
/proc/timer_stats.

Deferrable timer and normal timer will appear in /proc/timer_stats as below.
  10D,     1 swapper          queue_delayed_work_on (delayed_work_timer_fn)
   10,     1 swapper          queue_delayed_work_on (delayed_work_timer_fn)

Also version of timer_stats changes from v0.1 to v0.2
Signed-off-by: default avatarVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Acked-by: default avatarIngo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: john stultz <johnstul@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e0807061
...@@ -67,3 +67,7 @@ executed on expiry. ...@@ -67,3 +67,7 @@ executed on expiry.
Thomas, Ingo Thomas, Ingo
Added flag to indicate 'deferrable timer' in /proc/timer_stats. A deferrable
timer will appear as follows
10D, 1 swapper queue_delayed_work_on (delayed_work_timer_fn)
...@@ -329,12 +329,13 @@ extern void sysrq_timer_list_show(void); ...@@ -329,12 +329,13 @@ extern void sysrq_timer_list_show(void);
#ifdef CONFIG_TIMER_STATS #ifdef CONFIG_TIMER_STATS
extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
void *timerf, char * comm); void *timerf, char *comm,
unsigned int timer_flag);
static inline void timer_stats_account_hrtimer(struct hrtimer *timer) static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
{ {
timer_stats_update_stats(timer, timer->start_pid, timer->start_site, timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
timer->function, timer->start_comm); timer->function, timer->start_comm, 0);
} }
extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer,
......
...@@ -90,16 +90,13 @@ extern unsigned long get_next_timer_interrupt(unsigned long now); ...@@ -90,16 +90,13 @@ extern unsigned long get_next_timer_interrupt(unsigned long now);
*/ */
#ifdef CONFIG_TIMER_STATS #ifdef CONFIG_TIMER_STATS
#define TIMER_STATS_FLAG_DEFERRABLE 0x1
extern void init_timer_stats(void); extern void init_timer_stats(void);
extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
void *timerf, char * comm); void *timerf, char *comm,
unsigned int timer_flag);
static inline void timer_stats_account_timer(struct timer_list *timer)
{
timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
timer->function, timer->start_comm);
}
extern void __timer_stats_timer_set_start_info(struct timer_list *timer, extern void __timer_stats_timer_set_start_info(struct timer_list *timer,
void *addr); void *addr);
...@@ -118,10 +115,6 @@ static inline void init_timer_stats(void) ...@@ -118,10 +115,6 @@ static inline void init_timer_stats(void)
{ {
} }
static inline void timer_stats_account_timer(struct timer_list *timer)
{
}
static inline void timer_stats_timer_set_start_info(struct timer_list *timer) static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
{ {
} }
......
...@@ -68,6 +68,7 @@ struct entry { ...@@ -68,6 +68,7 @@ struct entry {
* Number of timeout events: * Number of timeout events:
*/ */
unsigned long count; unsigned long count;
unsigned int timer_flag;
/* /*
* We save the command-line string to preserve * We save the command-line string to preserve
...@@ -231,7 +232,8 @@ static struct entry *tstat_lookup(struct entry *entry, char *comm) ...@@ -231,7 +232,8 @@ static struct entry *tstat_lookup(struct entry *entry, char *comm)
* incremented. Otherwise the timer is registered in a free slot. * incremented. Otherwise the timer is registered in a free slot.
*/ */
void timer_stats_update_stats(void *timer, pid_t pid, void *startf, void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
void *timerf, char * comm) void *timerf, char *comm,
unsigned int timer_flag)
{ {
/* /*
* It doesnt matter which lock we take: * It doesnt matter which lock we take:
...@@ -249,6 +251,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf, ...@@ -249,6 +251,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
input.start_func = startf; input.start_func = startf;
input.expire_func = timerf; input.expire_func = timerf;
input.pid = pid; input.pid = pid;
input.timer_flag = timer_flag;
spin_lock_irqsave(lock, flags); spin_lock_irqsave(lock, flags);
if (!active) if (!active)
...@@ -295,7 +298,7 @@ static int tstats_show(struct seq_file *m, void *v) ...@@ -295,7 +298,7 @@ static int tstats_show(struct seq_file *m, void *v)
period = ktime_to_timespec(time); period = ktime_to_timespec(time);
ms = period.tv_nsec / 1000000; ms = period.tv_nsec / 1000000;
seq_puts(m, "Timer Stats Version: v0.1\n"); seq_puts(m, "Timer Stats Version: v0.2\n");
seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms); seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms);
if (atomic_read(&overflow_count)) if (atomic_read(&overflow_count))
seq_printf(m, "Overflow: %d entries\n", seq_printf(m, "Overflow: %d entries\n",
...@@ -303,8 +306,13 @@ static int tstats_show(struct seq_file *m, void *v) ...@@ -303,8 +306,13 @@ static int tstats_show(struct seq_file *m, void *v)
for (i = 0; i < nr_entries; i++) { for (i = 0; i < nr_entries; i++) {
entry = entries + i; entry = entries + i;
seq_printf(m, "%4lu, %5d %-16s ", if (entry->timer_flag & TIMER_STATS_FLAG_DEFERRABLE) {
seq_printf(m, "%4luD, %5d %-16s ",
entry->count, entry->pid, entry->comm); entry->count, entry->pid, entry->comm);
} else {
seq_printf(m, " %4lu, %5d %-16s ",
entry->count, entry->pid, entry->comm);
}
print_name_offset(m, (unsigned long)entry->start_func); print_name_offset(m, (unsigned long)entry->start_func);
seq_puts(m, " ("); seq_puts(m, " (");
......
...@@ -305,6 +305,20 @@ void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr) ...@@ -305,6 +305,20 @@ void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
timer->start_pid = current->pid; timer->start_pid = current->pid;
} }
static void timer_stats_account_timer(struct timer_list *timer)
{
unsigned int flag = 0;
if (unlikely(tbase_get_deferrable(timer->base)))
flag |= TIMER_STATS_FLAG_DEFERRABLE;
timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
timer->function, timer->start_comm, flag);
}
#else
static void timer_stats_account_timer(struct timer_list *timer) {}
#endif #endif
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment