profile.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/kernel/profile.c
  4. * Simple profiling. Manages a direct-mapped profile hit count buffer,
  5. * with configurable resolution, support for restricting the cpus on
  6. * which profiling is done, and switching between cpu time and
  7. * schedule() calls via kernel command line parameters passed at boot.
  8. *
  9. * Scheduler profiling support, Arjan van de Ven and Ingo Molnar,
  10. * Red Hat, July 2004
  11. * Consolidation of architecture support code for profiling,
  12. * Nadia Yvette Chambers, Oracle, July 2004
  13. * Amortized hit count accounting via per-cpu open-addressed hashtables
  14. * to resolve timer interrupt livelocks, Nadia Yvette Chambers,
  15. * Oracle, 2004
  16. */
  17. #include <linux/export.h>
  18. #include <linux/profile.h>
  19. #include <linux/memblock.h>
  20. #include <linux/notifier.h>
  21. #include <linux/mm.h>
  22. #include <linux/cpumask.h>
  23. #include <linux/cpu.h>
  24. #include <linux/highmem.h>
  25. #include <linux/mutex.h>
  26. #include <linux/slab.h>
  27. #include <linux/vmalloc.h>
  28. #include <linux/sched/stat.h>
  29. #include <asm/sections.h>
  30. #include <asm/irq_regs.h>
  31. #include <asm/ptrace.h>
  32. struct profile_hit {
  33. u32 pc, hits;
  34. };
  35. #define PROFILE_GRPSHIFT 3
  36. #define PROFILE_GRPSZ (1 << PROFILE_GRPSHIFT)
  37. #define NR_PROFILE_HIT (PAGE_SIZE/sizeof(struct profile_hit))
  38. #define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ)
  39. static atomic_t *prof_buffer;
  40. static unsigned long prof_len;
  41. static unsigned short int prof_shift;
  42. int prof_on __read_mostly;
  43. EXPORT_SYMBOL_GPL(prof_on);
  44. int profile_setup(char *str)
  45. {
  46. static const char schedstr[] = "schedule";
  47. static const char kvmstr[] = "kvm";
  48. const char *select = NULL;
  49. int par;
  50. if (!strncmp(str, schedstr, strlen(schedstr))) {
  51. prof_on = SCHED_PROFILING;
  52. select = schedstr;
  53. } else if (!strncmp(str, kvmstr, strlen(kvmstr))) {
  54. prof_on = KVM_PROFILING;
  55. select = kvmstr;
  56. } else if (get_option(&str, &par)) {
  57. prof_shift = clamp(par, 0, BITS_PER_LONG - 1);
  58. prof_on = CPU_PROFILING;
  59. pr_info("kernel profiling enabled (shift: %u)\n",
  60. prof_shift);
  61. }
  62. if (select) {
  63. if (str[strlen(select)] == ',')
  64. str += strlen(select) + 1;
  65. if (get_option(&str, &par))
  66. prof_shift = clamp(par, 0, BITS_PER_LONG - 1);
  67. pr_info("kernel %s profiling enabled (shift: %u)\n",
  68. select, prof_shift);
  69. }
  70. return 1;
  71. }
  72. __setup("profile=", profile_setup);
  73. int __ref profile_init(void)
  74. {
  75. int buffer_bytes;
  76. if (!prof_on)
  77. return 0;
  78. /* only text is profiled */
  79. prof_len = (_etext - _stext) >> prof_shift;
  80. if (!prof_len) {
  81. pr_warn("profiling shift: %u too large\n", prof_shift);
  82. prof_on = 0;
  83. return -EINVAL;
  84. }
  85. buffer_bytes = prof_len*sizeof(atomic_t);
  86. prof_buffer = kzalloc(buffer_bytes, GFP_KERNEL|__GFP_NOWARN);
  87. if (prof_buffer)
  88. return 0;
  89. prof_buffer = alloc_pages_exact(buffer_bytes,
  90. GFP_KERNEL|__GFP_ZERO|__GFP_NOWARN);
  91. if (prof_buffer)
  92. return 0;
  93. prof_buffer = vzalloc(buffer_bytes);
  94. if (prof_buffer)
  95. return 0;
  96. return -ENOMEM;
  97. }
  98. static void do_profile_hits(int type, void *__pc, unsigned int nr_hits)
  99. {
  100. unsigned long pc;
  101. pc = ((unsigned long)__pc - (unsigned long)_stext) >> prof_shift;
  102. if (pc < prof_len)
  103. atomic_add(nr_hits, &prof_buffer[pc]);
  104. }
  105. void profile_hits(int type, void *__pc, unsigned int nr_hits)
  106. {
  107. if (prof_on != type || !prof_buffer)
  108. return;
  109. do_profile_hits(type, __pc, nr_hits);
  110. }
  111. EXPORT_SYMBOL_GPL(profile_hits);
  112. void profile_tick(int type)
  113. {
  114. struct pt_regs *regs = get_irq_regs();
  115. /* This is the old kernel-only legacy profiling */
  116. if (!user_mode(regs))
  117. profile_hit(type, (void *)profile_pc(regs));
  118. }
  119. #ifdef CONFIG_PROC_FS
  120. #include <linux/proc_fs.h>
  121. #include <linux/seq_file.h>
  122. #include <linux/uaccess.h>
  123. /*
  124. * This function accesses profiling information. The returned data is
  125. * binary: the sampling step and the actual contents of the profile
  126. * buffer. Use of the program readprofile is recommended in order to
  127. * get meaningful info out of these data.
  128. */
  129. static ssize_t
  130. read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  131. {
  132. unsigned long p = *ppos;
  133. ssize_t read;
  134. char *pnt;
  135. unsigned long sample_step = 1UL << prof_shift;
  136. if (p >= (prof_len+1)*sizeof(unsigned int))
  137. return 0;
  138. if (count > (prof_len+1)*sizeof(unsigned int) - p)
  139. count = (prof_len+1)*sizeof(unsigned int) - p;
  140. read = 0;
  141. while (p < sizeof(unsigned int) && count > 0) {
  142. if (put_user(*((char *)(&sample_step)+p), buf))
  143. return -EFAULT;
  144. buf++; p++; count--; read++;
  145. }
  146. pnt = (char *)prof_buffer + p - sizeof(atomic_t);
  147. if (copy_to_user(buf, (void *)pnt, count))
  148. return -EFAULT;
  149. read += count;
  150. *ppos += read;
  151. return read;
  152. }
  153. /* default is to not implement this call */
  154. int __weak setup_profiling_timer(unsigned mult)
  155. {
  156. return -EINVAL;
  157. }
  158. /*
  159. * Writing to /proc/profile resets the counters
  160. *
  161. * Writing a 'profiling multiplier' value into it also re-sets the profiling
  162. * interrupt frequency, on architectures that support this.
  163. */
  164. static ssize_t write_profile(struct file *file, const char __user *buf,
  165. size_t count, loff_t *ppos)
  166. {
  167. #ifdef CONFIG_SMP
  168. if (count == sizeof(int)) {
  169. unsigned int multiplier;
  170. if (copy_from_user(&multiplier, buf, sizeof(int)))
  171. return -EFAULT;
  172. if (setup_profiling_timer(multiplier))
  173. return -EINVAL;
  174. }
  175. #endif
  176. memset(prof_buffer, 0, prof_len * sizeof(atomic_t));
  177. return count;
  178. }
  179. static const struct proc_ops profile_proc_ops = {
  180. .proc_read = read_profile,
  181. .proc_write = write_profile,
  182. .proc_lseek = default_llseek,
  183. };
  184. int __ref create_proc_profile(void)
  185. {
  186. struct proc_dir_entry *entry;
  187. int err = 0;
  188. if (!prof_on)
  189. return 0;
  190. entry = proc_create("profile", S_IWUSR | S_IRUGO,
  191. NULL, &profile_proc_ops);
  192. if (entry)
  193. proc_set_size(entry, (1 + prof_len) * sizeof(atomic_t));
  194. return err;
  195. }
  196. subsys_initcall(create_proc_profile);
  197. #endif /* CONFIG_PROC_FS */