diff options
-rw-r--r-- | Documentation/hrtimer/timer_stats.txt | 4 | ||||
-rw-r--r-- | include/linux/hrtimer.h | 5 | ||||
-rw-r--r-- | include/linux/timer.h | 15 | ||||
-rw-r--r-- | kernel/time/timer_stats.c | 14 | ||||
-rw-r--r-- | kernel/timer.c | 14 |
5 files changed, 36 insertions, 16 deletions
diff --git a/Documentation/hrtimer/timer_stats.txt b/Documentation/hrtimer/timer_stats.txt index 22b0814d0ad0..20d368c59814 100644 --- a/Documentation/hrtimer/timer_stats.txt +++ b/Documentation/hrtimer/timer_stats.txt | |||
@@ -67,3 +67,7 @@ executed on expiry. | |||
67 | 67 | ||
68 | Thomas, Ingo | 68 | Thomas, Ingo |
69 | 69 | ||
70 | Added flag to indicate 'deferrable timer' in /proc/timer_stats. A deferrable | ||
71 | timer will appear as follows | ||
72 | 10D, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) | ||
73 | |||
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 17c29dca8354..540799bc85f8 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -329,12 +329,13 @@ extern void sysrq_timer_list_show(void); | |||
329 | #ifdef CONFIG_TIMER_STATS | 329 | #ifdef CONFIG_TIMER_STATS |
330 | 330 | ||
331 | extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, | 331 | extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, |
332 | void *timerf, char * comm); | 332 | void *timerf, char *comm, |
333 | unsigned int timer_flag); | ||
333 | 334 | ||
334 | static inline void timer_stats_account_hrtimer(struct hrtimer *timer) | 335 | static inline void timer_stats_account_hrtimer(struct hrtimer *timer) |
335 | { | 336 | { |
336 | timer_stats_update_stats(timer, timer->start_pid, timer->start_site, | 337 | timer_stats_update_stats(timer, timer->start_pid, timer->start_site, |
337 | timer->function, timer->start_comm); | 338 | timer->function, timer->start_comm, 0); |
338 | } | 339 | } |
339 | 340 | ||
340 | extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, | 341 | extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, |
diff --git a/include/linux/timer.h b/include/linux/timer.h index 2b59e6d4219c..78cf899b4409 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h | |||
@@ -90,16 +90,13 @@ extern unsigned long get_next_timer_interrupt(unsigned long now); | |||
90 | */ | 90 | */ |
91 | #ifdef CONFIG_TIMER_STATS | 91 | #ifdef CONFIG_TIMER_STATS |
92 | 92 | ||
93 | #define TIMER_STATS_FLAG_DEFERRABLE 0x1 | ||
94 | |||
93 | extern void init_timer_stats(void); | 95 | extern void init_timer_stats(void); |
94 | 96 | ||
95 | extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, | 97 | extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, |
96 | void *timerf, char * comm); | 98 | void *timerf, char *comm, |
97 | 99 | unsigned int timer_flag); | |
98 | static inline void timer_stats_account_timer(struct timer_list *timer) | ||
99 | { | ||
100 | timer_stats_update_stats(timer, timer->start_pid, timer->start_site, | ||
101 | timer->function, timer->start_comm); | ||
102 | } | ||
103 | 100 | ||
104 | extern void __timer_stats_timer_set_start_info(struct timer_list *timer, | 101 | extern void __timer_stats_timer_set_start_info(struct timer_list *timer, |
105 | void *addr); | 102 | void *addr); |
@@ -118,10 +115,6 @@ static inline void init_timer_stats(void) | |||
118 | { | 115 | { |
119 | } | 116 | } |
120 | 117 | ||
121 | static inline void timer_stats_account_timer(struct timer_list *timer) | ||
122 | { | ||
123 | } | ||
124 | |||
125 | static inline void timer_stats_timer_set_start_info(struct timer_list *timer) | 118 | static inline void timer_stats_timer_set_start_info(struct timer_list *timer) |
126 | { | 119 | { |
127 | } | 120 | } |
diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c index 321693724ad7..9b8a826236dd 100644 --- a/kernel/time/timer_stats.c +++ b/kernel/time/timer_stats.c | |||
@@ -68,6 +68,7 @@ struct entry { | |||
68 | * Number of timeout events: | 68 | * Number of timeout events: |
69 | */ | 69 | */ |
70 | unsigned long count; | 70 | unsigned long count; |
71 | unsigned int timer_flag; | ||
71 | 72 | ||
72 | /* | 73 | /* |
73 | * We save the command-line string to preserve | 74 | * We save the command-line string to preserve |
@@ -231,7 +232,8 @@ static struct entry *tstat_lookup(struct entry *entry, char *comm) | |||
231 | * incremented. Otherwise the timer is registered in a free slot. | 232 | * incremented. Otherwise the timer is registered in a free slot. |
232 | */ | 233 | */ |
233 | void timer_stats_update_stats(void *timer, pid_t pid, void *startf, | 234 | void timer_stats_update_stats(void *timer, pid_t pid, void *startf, |
234 | void *timerf, char * comm) | 235 | void *timerf, char *comm, |
236 | unsigned int timer_flag) | ||
235 | { | 237 | { |
236 | /* | 238 | /* |
237 | * It doesnt matter which lock we take: | 239 | * It doesnt matter which lock we take: |
@@ -249,6 +251,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf, | |||
249 | input.start_func = startf; | 251 | input.start_func = startf; |
250 | input.expire_func = timerf; | 252 | input.expire_func = timerf; |
251 | input.pid = pid; | 253 | input.pid = pid; |
254 | input.timer_flag = timer_flag; | ||
252 | 255 | ||
253 | spin_lock_irqsave(lock, flags); | 256 | spin_lock_irqsave(lock, flags); |
254 | if (!active) | 257 | if (!active) |
@@ -295,7 +298,7 @@ static int tstats_show(struct seq_file *m, void *v) | |||
295 | period = ktime_to_timespec(time); | 298 | period = ktime_to_timespec(time); |
296 | ms = period.tv_nsec / 1000000; | 299 | ms = period.tv_nsec / 1000000; |
297 | 300 | ||
298 | seq_puts(m, "Timer Stats Version: v0.1\n"); | 301 | seq_puts(m, "Timer Stats Version: v0.2\n"); |
299 | seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms); | 302 | seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms); |
300 | if (atomic_read(&overflow_count)) | 303 | if (atomic_read(&overflow_count)) |
301 | seq_printf(m, "Overflow: %d entries\n", | 304 | seq_printf(m, "Overflow: %d entries\n", |
@@ -303,8 +306,13 @@ static int tstats_show(struct seq_file *m, void *v) | |||
303 | 306 | ||
304 | for (i = 0; i < nr_entries; i++) { | 307 | for (i = 0; i < nr_entries; i++) { |
305 | entry = entries + i; | 308 | entry = entries + i; |
306 | seq_printf(m, "%4lu, %5d %-16s ", | 309 | if (entry->timer_flag & TIMER_STATS_FLAG_DEFERRABLE) { |
310 | seq_printf(m, "%4luD, %5d %-16s ", | ||
307 | entry->count, entry->pid, entry->comm); | 311 | entry->count, entry->pid, entry->comm); |
312 | } else { | ||
313 | seq_printf(m, " %4lu, %5d %-16s ", | ||
314 | entry->count, entry->pid, entry->comm); | ||
315 | } | ||
308 | 316 | ||
309 | print_name_offset(m, (unsigned long)entry->start_func); | 317 | print_name_offset(m, (unsigned long)entry->start_func); |
310 | seq_puts(m, " ("); | 318 | seq_puts(m, " ("); |
diff --git a/kernel/timer.c b/kernel/timer.c index 1ab3106a2b5d..1258371e0d2b 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -305,6 +305,20 @@ void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr) | |||
305 | memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); | 305 | memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); |
306 | timer->start_pid = current->pid; | 306 | timer->start_pid = current->pid; |
307 | } | 307 | } |
308 | |||
309 | static void timer_stats_account_timer(struct timer_list *timer) | ||
310 | { | ||
311 | unsigned int flag = 0; | ||
312 | |||
313 | if (unlikely(tbase_get_deferrable(timer->base))) | ||
314 | flag |= TIMER_STATS_FLAG_DEFERRABLE; | ||
315 | |||
316 | timer_stats_update_stats(timer, timer->start_pid, timer->start_site, | ||
317 | timer->function, timer->start_comm, flag); | ||
318 | } | ||
319 | |||
320 | #else | ||
321 | static void timer_stats_account_timer(struct timer_list *timer) {} | ||
308 | #endif | 322 | #endif |
309 | 323 | ||
310 | /** | 324 | /** |