timer_stats.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * kernel/time/timer_stats.c
  3. *
  4. * Collect timer usage statistics.
  5. *
  6. * Copyright(C) 2006, Red Hat, Inc., Ingo Molnar
  7. * Copyright(C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
  8. *
  9. * timer_stats is based on timer_top, a similar functionality which was part of
  10. * Con Kolivas dyntick patch set. It was developed by Daniel Petrini at the
  11. * Instituto Nokia de Tecnologia - INdT - Manaus. timer_top's design was based
  12. * on dynamic allocation of the statistics entries and linear search based
  13. * lookup combined with a global lock, rather than the static array, hash
  14. * and per-CPU locking which is used by timer_stats. It was written for the
  15. * pre hrtimer kernel code and therefore did not take hrtimers into account.
  16. * Nevertheless it provided the base for the timer_stats implementation and
  17. * was a helpful source of inspiration. Kudos to Daniel and the Nokia folks
  18. * for this effort.
  19. *
  20. * timer_top.c is
  21. * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus
  22. * Written by Daniel Petrini <d.pensator@gmail.com>
  23. * timer_top.c was released under the GNU General Public License version 2
  24. *
  25. * We export the addresses and counting of timer functions being called,
  26. * the pid and cmdline from the owner process if applicable.
  27. *
  28. * Start/stop data collection:
  29. * # echo 1[0] >/proc/timer_stats
  30. *
  31. * Display the information collected so far:
  32. * # cat /proc/timer_stats
  33. *
  34. * This program is free software; you can redistribute it and/or modify
  35. * it under the terms of the GNU General Public License version 2 as
  36. * published by the Free Software Foundation.
  37. */
  38. #include <linux/proc_fs.h>
  39. #include <linux/module.h>
  40. #include <linux/spinlock.h>
  41. #include <linux/sched.h>
  42. #include <linux/seq_file.h>
  43. #include <linux/kallsyms.h>
  44. #include <asm/uaccess.h>
  45. /*
  46. * This is our basic unit of interest: a timer expiry event identified
  47. * by the timer, its start/expire functions and the PID of the task that
  48. * started the timer. We count the number of times an event happens:
  49. */
  50. struct entry {
  51. /*
  52. * Hash list:
  53. */
  54. struct entry *next;
  55. /*
  56. * Hash keys:
  57. */
  58. void *timer;
  59. void *start_func;
  60. void *expire_func;
  61. pid_t pid;
  62. /*
  63. * Number of timeout events:
  64. */
  65. unsigned long count;
  66. /*
  67. * We save the command-line string to preserve
  68. * this information past task exit:
  69. */
  70. char comm[TASK_COMM_LEN + 1];
  71. } ____cacheline_aligned_in_smp;
  72. /*
  73. * Spinlock protecting the tables - not taken during lookup:
  74. */
  75. static DEFINE_SPINLOCK(table_lock);
  76. /*
  77. * Per-CPU lookup locks for fast hash lookup:
  78. */
  79. static DEFINE_PER_CPU(spinlock_t, lookup_lock);
  80. /*
  81. * Mutex to serialize state changes with show-stats activities:
  82. */
  83. static DEFINE_MUTEX(show_mutex);
  84. /*
  85. * Collection status, active/inactive:
  86. */
  87. static int __read_mostly active;
  88. /*
  89. * Beginning/end timestamps of measurement:
  90. */
  91. static ktime_t time_start, time_stop;
  92. /*
  93. * tstat entry structs only get allocated while collection is
  94. * active and never freed during that time - this simplifies
  95. * things quite a bit.
  96. *
  97. * They get freed when a new collection period is started.
  98. */
  99. #define MAX_ENTRIES_BITS 10
  100. #define MAX_ENTRIES (1UL << MAX_ENTRIES_BITS)
  101. static unsigned long nr_entries;
  102. static struct entry entries[MAX_ENTRIES];
  103. static atomic_t overflow_count;
  104. static void reset_entries(void)
  105. {
  106. nr_entries = 0;
  107. memset(entries, 0, sizeof(entries));
  108. atomic_set(&overflow_count, 0);
  109. }
  110. static struct entry *alloc_entry(void)
  111. {
  112. if (nr_entries >= MAX_ENTRIES)
  113. return NULL;
  114. return entries + nr_entries++;
  115. }
  116. /*
  117. * The entries are in a hash-table, for fast lookup:
  118. */
  119. #define TSTAT_HASH_BITS (MAX_ENTRIES_BITS - 1)
  120. #define TSTAT_HASH_SIZE (1UL << TSTAT_HASH_BITS)
  121. #define TSTAT_HASH_MASK (TSTAT_HASH_SIZE - 1)
  122. #define __tstat_hashfn(entry) \
  123. (((unsigned long)(entry)->timer ^ \
  124. (unsigned long)(entry)->start_func ^ \
  125. (unsigned long)(entry)->expire_func ^ \
  126. (unsigned long)(entry)->pid ) & TSTAT_HASH_MASK)
  127. #define tstat_hashentry(entry) (tstat_hash_table + __tstat_hashfn(entry))
  128. static struct entry *tstat_hash_table[TSTAT_HASH_SIZE] __read_mostly;
  129. static int match_entries(struct entry *entry1, struct entry *entry2)
  130. {
  131. return entry1->timer == entry2->timer &&
  132. entry1->start_func == entry2->start_func &&
  133. entry1->expire_func == entry2->expire_func &&
  134. entry1->pid == entry2->pid;
  135. }
  136. /*
  137. * Look up whether an entry matching this item is present
  138. * in the hash already. Must be called with irqs off and the
  139. * lookup lock held:
  140. */
  141. static struct entry *tstat_lookup(struct entry *entry, char *comm)
  142. {
  143. struct entry **head, *curr, *prev;
  144. head = tstat_hashentry(entry);
  145. curr = *head;
  146. /*
  147. * The fastpath is when the entry is already hashed,
  148. * we do this with the lookup lock held, but with the
  149. * table lock not held:
  150. */
  151. while (curr) {
  152. if (match_entries(curr, entry))
  153. return curr;
  154. curr = curr->next;
  155. }
  156. /*
  157. * Slowpath: allocate, set up and link a new hash entry:
  158. */
  159. prev = NULL;
  160. curr = *head;
  161. spin_lock(&table_lock);
  162. /*
  163. * Make sure we have not raced with another CPU:
  164. */
  165. while (curr) {
  166. if (match_entries(curr, entry))
  167. goto out_unlock;
  168. prev = curr;
  169. curr = curr->next;
  170. }
  171. curr = alloc_entry();
  172. if (curr) {
  173. *curr = *entry;
  174. curr->count = 0;
  175. memcpy(curr->comm, comm, TASK_COMM_LEN);
  176. if (prev)
  177. prev->next = curr;
  178. else
  179. *head = curr;
  180. curr->next = NULL;
  181. }
  182. out_unlock:
  183. spin_unlock(&table_lock);
  184. return curr;
  185. }
  186. /**
  187. * timer_stats_update_stats - Update the statistics for a timer.
  188. * @timer: pointer to either a timer_list or a hrtimer
  189. * @pid: the pid of the task which set up the timer
  190. * @startf: pointer to the function which did the timer setup
  191. * @timerf: pointer to the timer callback function of the timer
  192. * @comm: name of the process which set up the timer
  193. *
  194. * When the timer is already registered, then the event counter is
  195. * incremented. Otherwise the timer is registered in a free slot.
  196. */
  197. void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
  198. void *timerf, char * comm)
  199. {
  200. /*
  201. * It doesnt matter which lock we take:
  202. */
  203. spinlock_t *lock = &per_cpu(lookup_lock, raw_smp_processor_id());
  204. struct entry *entry, input;
  205. unsigned long flags;
  206. input.timer = timer;
  207. input.start_func = startf;
  208. input.expire_func = timerf;
  209. input.pid = pid;
  210. spin_lock_irqsave(lock, flags);
  211. if (!active)
  212. goto out_unlock;
  213. entry = tstat_lookup(&input, comm);
  214. if (likely(entry))
  215. entry->count++;
  216. else
  217. atomic_inc(&overflow_count);
  218. out_unlock:
  219. spin_unlock_irqrestore(lock, flags);
  220. }
  221. static void print_name_offset(struct seq_file *m, unsigned long addr)
  222. {
  223. char symname[KSYM_NAME_LEN+1];
  224. if (lookup_symbol_name(addr, symname) < 0)
  225. seq_printf(m, "<%p>", (void *)addr);
  226. else
  227. seq_printf(m, "%s", symname);
  228. }
  229. static int tstats_show(struct seq_file *m, void *v)
  230. {
  231. struct timespec period;
  232. struct entry *entry;
  233. unsigned long ms;
  234. long events = 0;
  235. ktime_t time;
  236. int i;
  237. mutex_lock(&show_mutex);
  238. /*
  239. * If still active then calculate up to now:
  240. */
  241. if (active)
  242. time_stop = ktime_get();
  243. time = ktime_sub(time_stop, time_start);
  244. period = ktime_to_timespec(time);
  245. ms = period.tv_nsec / 1000000;
  246. seq_puts(m, "Timer Stats Version: v0.1\n");
  247. seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms);
  248. if (atomic_read(&overflow_count))
  249. seq_printf(m, "Overflow: %d entries\n",
  250. atomic_read(&overflow_count));
  251. for (i = 0; i < nr_entries; i++) {
  252. entry = entries + i;
  253. seq_printf(m, "%4lu, %5d %-16s ",
  254. entry->count, entry->pid, entry->comm);
  255. print_name_offset(m, (unsigned long)entry->start_func);
  256. seq_puts(m, " (");
  257. print_name_offset(m, (unsigned long)entry->expire_func);
  258. seq_puts(m, ")\n");
  259. events += entry->count;
  260. }
  261. ms += period.tv_sec * 1000;
  262. if (!ms)
  263. ms = 1;
  264. if (events && period.tv_sec)
  265. seq_printf(m, "%ld total events, %ld.%ld events/sec\n", events,
  266. events / period.tv_sec, events * 1000 / ms);
  267. else
  268. seq_printf(m, "%ld total events\n", events);
  269. mutex_unlock(&show_mutex);
  270. return 0;
  271. }
  272. /*
  273. * After a state change, make sure all concurrent lookup/update
  274. * activities have stopped:
  275. */
  276. static void sync_access(void)
  277. {
  278. unsigned long flags;
  279. int cpu;
  280. for_each_online_cpu(cpu) {
  281. spin_lock_irqsave(&per_cpu(lookup_lock, cpu), flags);
  282. /* nothing */
  283. spin_unlock_irqrestore(&per_cpu(lookup_lock, cpu), flags);
  284. }
  285. }
  286. static ssize_t tstats_write(struct file *file, const char __user *buf,
  287. size_t count, loff_t *offs)
  288. {
  289. char ctl[2];
  290. if (count != 2 || *offs)
  291. return -EINVAL;
  292. if (copy_from_user(ctl, buf, count))
  293. return -EFAULT;
  294. mutex_lock(&show_mutex);
  295. switch (ctl[0]) {
  296. case '0':
  297. if (active) {
  298. active = 0;
  299. time_stop = ktime_get();
  300. sync_access();
  301. }
  302. break;
  303. case '1':
  304. if (!active) {
  305. reset_entries();
  306. time_start = ktime_get();
  307. active = 1;
  308. }
  309. break;
  310. default:
  311. count = -EINVAL;
  312. }
  313. mutex_unlock(&show_mutex);
  314. return count;
  315. }
  316. static int tstats_open(struct inode *inode, struct file *filp)
  317. {
  318. return single_open(filp, tstats_show, NULL);
  319. }
  320. static struct file_operations tstats_fops = {
  321. .open = tstats_open,
  322. .read = seq_read,
  323. .write = tstats_write,
  324. .llseek = seq_lseek,
  325. .release = seq_release,
  326. };
  327. void __init init_timer_stats(void)
  328. {
  329. int cpu;
  330. for_each_possible_cpu(cpu)
  331. spin_lock_init(&per_cpu(lookup_lock, cpu));
  332. }
  333. static int __init init_tstats_procfs(void)
  334. {
  335. struct proc_dir_entry *pe;
  336. pe = create_proc_entry("timer_stats", 0644, NULL);
  337. if (!pe)
  338. return -ENOMEM;
  339. pe->proc_fops = &tstats_fops;
  340. return 0;
  341. }
  342. __initcall(init_tstats_procfs);