timer_stats.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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 namebuf[KSYM_NAME_LEN+1];
  224. unsigned long size, offset;
  225. const char *sym_name;
  226. char *modname;
  227. sym_name = kallsyms_lookup(addr, &size, &offset, &modname, namebuf);
  228. if (sym_name)
  229. seq_printf(m, "%s", sym_name);
  230. else
  231. seq_printf(m, "<%p>", (void *)addr);
  232. }
  233. static int tstats_show(struct seq_file *m, void *v)
  234. {
  235. struct timespec period;
  236. struct entry *entry;
  237. unsigned long ms;
  238. long events = 0;
  239. ktime_t time;
  240. int i;
  241. mutex_lock(&show_mutex);
  242. /*
  243. * If still active then calculate up to now:
  244. */
  245. if (active)
  246. time_stop = ktime_get();
  247. time = ktime_sub(time_stop, time_start);
  248. period = ktime_to_timespec(time);
  249. ms = period.tv_nsec / 1000000;
  250. seq_puts(m, "Timer Stats Version: v0.1\n");
  251. seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms);
  252. if (atomic_read(&overflow_count))
  253. seq_printf(m, "Overflow: %d entries\n",
  254. atomic_read(&overflow_count));
  255. for (i = 0; i < nr_entries; i++) {
  256. entry = entries + i;
  257. seq_printf(m, "%4lu, %5d %-16s ",
  258. entry->count, entry->pid, entry->comm);
  259. print_name_offset(m, (unsigned long)entry->start_func);
  260. seq_puts(m, " (");
  261. print_name_offset(m, (unsigned long)entry->expire_func);
  262. seq_puts(m, ")\n");
  263. events += entry->count;
  264. }
  265. ms += period.tv_sec * 1000;
  266. if (!ms)
  267. ms = 1;
  268. if (events && period.tv_sec)
  269. seq_printf(m, "%ld total events, %ld.%ld events/sec\n", events,
  270. events / period.tv_sec, events * 1000 / ms);
  271. else
  272. seq_printf(m, "%ld total events\n", events);
  273. mutex_unlock(&show_mutex);
  274. return 0;
  275. }
  276. /*
  277. * After a state change, make sure all concurrent lookup/update
  278. * activities have stopped:
  279. */
  280. static void sync_access(void)
  281. {
  282. unsigned long flags;
  283. int cpu;
  284. for_each_online_cpu(cpu) {
  285. spin_lock_irqsave(&per_cpu(lookup_lock, cpu), flags);
  286. /* nothing */
  287. spin_unlock_irqrestore(&per_cpu(lookup_lock, cpu), flags);
  288. }
  289. }
  290. static ssize_t tstats_write(struct file *file, const char __user *buf,
  291. size_t count, loff_t *offs)
  292. {
  293. char ctl[2];
  294. if (count != 2 || *offs)
  295. return -EINVAL;
  296. if (copy_from_user(ctl, buf, count))
  297. return -EFAULT;
  298. mutex_lock(&show_mutex);
  299. switch (ctl[0]) {
  300. case '0':
  301. if (active) {
  302. active = 0;
  303. time_stop = ktime_get();
  304. sync_access();
  305. }
  306. break;
  307. case '1':
  308. if (!active) {
  309. reset_entries();
  310. time_start = ktime_get();
  311. active = 1;
  312. }
  313. break;
  314. default:
  315. count = -EINVAL;
  316. }
  317. mutex_unlock(&show_mutex);
  318. return count;
  319. }
  320. static int tstats_open(struct inode *inode, struct file *filp)
  321. {
  322. return single_open(filp, tstats_show, NULL);
  323. }
  324. static struct file_operations tstats_fops = {
  325. .open = tstats_open,
  326. .read = seq_read,
  327. .write = tstats_write,
  328. .llseek = seq_lseek,
  329. .release = seq_release,
  330. };
  331. void __init init_timer_stats(void)
  332. {
  333. int cpu;
  334. for_each_possible_cpu(cpu)
  335. spin_lock_init(&per_cpu(lookup_lock, cpu));
  336. }
  337. static int __init init_tstats_procfs(void)
  338. {
  339. struct proc_dir_entry *pe;
  340. pe = create_proc_entry("timer_stats", 0644, NULL);
  341. if (!pe)
  342. return -ENOMEM;
  343. pe->proc_fops = &tstats_fops;
  344. return 0;
  345. }
  346. __initcall(init_tstats_procfs);