ftrace-ops.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  3. #include <linux/ftrace.h>
  4. #include <linux/ktime.h>
  5. #include <linux/module.h>
  6. #include <asm/barrier.h>
  7. /*
  8. * Arbitrary large value chosen to be sufficiently large to minimize noise but
  9. * sufficiently small to complete quickly.
  10. */
  11. static unsigned int nr_function_calls = 100000;
  12. module_param(nr_function_calls, uint, 0);
  13. MODULE_PARM_DESC(nr_function_calls, "How many times to call the relevant tracee");
  14. /*
  15. * The number of ops associated with a call site affects whether a tracer can
  16. * be called directly or whether it's necessary to go via the list func, which
  17. * can be significantly more expensive.
  18. */
  19. static unsigned int nr_ops_relevant = 1;
  20. module_param(nr_ops_relevant, uint, 0);
  21. MODULE_PARM_DESC(nr_ops_relevant, "How many ftrace_ops to associate with the relevant tracee");
  22. /*
  23. * On architectures where all call sites share the same trampoline, having
  24. * tracers enabled for distinct functions can force the use of the list func
  25. * and incur overhead for all call sites.
  26. */
  27. static unsigned int nr_ops_irrelevant;
  28. module_param(nr_ops_irrelevant, uint, 0);
  29. MODULE_PARM_DESC(nr_ops_irrelevant, "How many ftrace_ops to associate with the irrelevant tracee");
  30. /*
  31. * On architectures with DYNAMIC_FTRACE_WITH_REGS, saving the full pt_regs can
  32. * be more expensive than only saving the minimal necessary regs.
  33. */
  34. static bool save_regs;
  35. module_param(save_regs, bool, 0);
  36. MODULE_PARM_DESC(save_regs, "Register ops with FTRACE_OPS_FL_SAVE_REGS (save all registers in the trampoline)");
  37. static bool assist_recursion;
  38. module_param(assist_recursion, bool, 0);
  39. MODULE_PARM_DESC(assist_reursion, "Register ops with FTRACE_OPS_FL_RECURSION");
  40. static bool assist_rcu;
  41. module_param(assist_rcu, bool, 0);
  42. MODULE_PARM_DESC(assist_reursion, "Register ops with FTRACE_OPS_FL_RCU");
  43. /*
  44. * By default, a trivial tracer is used which immediately returns to mimimize
  45. * overhead. Sometimes a consistency check using a more expensive tracer is
  46. * desireable.
  47. */
  48. static bool check_count;
  49. module_param(check_count, bool, 0);
  50. MODULE_PARM_DESC(check_count, "Check that tracers are called the expected number of times\n");
  51. /*
  52. * Usually it's not interesting to leave the ops registered after the test
  53. * runs, but sometimes it can be useful to leave them registered so that they
  54. * can be inspected through the tracefs 'enabled_functions' file.
  55. */
  56. static bool persist;
  57. module_param(persist, bool, 0);
  58. MODULE_PARM_DESC(persist, "Successfully load module and leave ftrace ops registered after test completes\n");
  59. /*
  60. * Marked as noinline to ensure that an out-of-line traceable copy is
  61. * generated by the compiler.
  62. *
  63. * The barrier() ensures the compiler won't elide calls by determining there
  64. * are no side-effects.
  65. */
  66. static noinline void tracee_relevant(void)
  67. {
  68. barrier();
  69. }
  70. /*
  71. * Marked as noinline to ensure that an out-of-line traceable copy is
  72. * generated by the compiler.
  73. *
  74. * The barrier() ensures the compiler won't elide calls by determining there
  75. * are no side-effects.
  76. */
  77. static noinline void tracee_irrelevant(void)
  78. {
  79. barrier();
  80. }
  81. struct sample_ops {
  82. struct ftrace_ops ops;
  83. unsigned int count;
  84. };
  85. static void ops_func_nop(unsigned long ip, unsigned long parent_ip,
  86. struct ftrace_ops *op,
  87. struct ftrace_regs *fregs)
  88. {
  89. /* do nothing */
  90. }
  91. static void ops_func_count(unsigned long ip, unsigned long parent_ip,
  92. struct ftrace_ops *op,
  93. struct ftrace_regs *fregs)
  94. {
  95. struct sample_ops *self;
  96. self = container_of(op, struct sample_ops, ops);
  97. self->count++;
  98. }
  99. static struct sample_ops *ops_relevant;
  100. static struct sample_ops *ops_irrelevant;
  101. static struct sample_ops *ops_alloc_init(void *tracee, ftrace_func_t func,
  102. unsigned long flags, int nr)
  103. {
  104. struct sample_ops *ops;
  105. ops = kcalloc(nr, sizeof(*ops), GFP_KERNEL);
  106. if (WARN_ON_ONCE(!ops))
  107. return NULL;
  108. for (unsigned int i = 0; i < nr; i++) {
  109. ops[i].ops.func = func;
  110. ops[i].ops.flags = flags;
  111. WARN_ON_ONCE(ftrace_set_filter_ip(&ops[i].ops, (unsigned long)tracee, 0, 0));
  112. WARN_ON_ONCE(register_ftrace_function(&ops[i].ops));
  113. }
  114. return ops;
  115. }
  116. static void ops_destroy(struct sample_ops *ops, int nr)
  117. {
  118. if (!ops)
  119. return;
  120. for (unsigned int i = 0; i < nr; i++) {
  121. WARN_ON_ONCE(unregister_ftrace_function(&ops[i].ops));
  122. ftrace_free_filter(&ops[i].ops);
  123. }
  124. kfree(ops);
  125. }
  126. static void ops_check(struct sample_ops *ops, int nr,
  127. unsigned int expected_count)
  128. {
  129. if (!ops || !check_count)
  130. return;
  131. for (unsigned int i = 0; i < nr; i++) {
  132. if (ops->count == expected_count)
  133. continue;
  134. pr_warn("Counter called %u times (expected %u)\n",
  135. ops->count, expected_count);
  136. }
  137. }
  138. static ftrace_func_t tracer_relevant = ops_func_nop;
  139. static ftrace_func_t tracer_irrelevant = ops_func_nop;
  140. static int __init ftrace_ops_sample_init(void)
  141. {
  142. unsigned long flags = 0;
  143. ktime_t start, end;
  144. u64 period;
  145. if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) && save_regs) {
  146. pr_info("this kernel does not support saving registers\n");
  147. save_regs = false;
  148. } else if (save_regs) {
  149. flags |= FTRACE_OPS_FL_SAVE_REGS;
  150. }
  151. if (assist_recursion)
  152. flags |= FTRACE_OPS_FL_RECURSION;
  153. if (assist_rcu)
  154. flags |= FTRACE_OPS_FL_RCU;
  155. if (check_count) {
  156. tracer_relevant = ops_func_count;
  157. tracer_irrelevant = ops_func_count;
  158. }
  159. pr_info("registering:\n"
  160. " relevant ops: %u\n"
  161. " tracee: %ps\n"
  162. " tracer: %ps\n"
  163. " irrelevant ops: %u\n"
  164. " tracee: %ps\n"
  165. " tracer: %ps\n"
  166. " saving registers: %s\n"
  167. " assist recursion: %s\n"
  168. " assist RCU: %s\n",
  169. nr_ops_relevant, tracee_relevant, tracer_relevant,
  170. nr_ops_irrelevant, tracee_irrelevant, tracer_irrelevant,
  171. save_regs ? "YES" : "NO",
  172. assist_recursion ? "YES" : "NO",
  173. assist_rcu ? "YES" : "NO");
  174. ops_relevant = ops_alloc_init(tracee_relevant, tracer_relevant,
  175. flags, nr_ops_relevant);
  176. ops_irrelevant = ops_alloc_init(tracee_irrelevant, tracer_irrelevant,
  177. flags, nr_ops_irrelevant);
  178. start = ktime_get();
  179. for (unsigned int i = 0; i < nr_function_calls; i++)
  180. tracee_relevant();
  181. end = ktime_get();
  182. ops_check(ops_relevant, nr_ops_relevant, nr_function_calls);
  183. ops_check(ops_irrelevant, nr_ops_irrelevant, 0);
  184. period = ktime_to_ns(ktime_sub(end, start));
  185. pr_info("Attempted %u calls to %ps in %lluns (%lluns / call)\n",
  186. nr_function_calls, tracee_relevant,
  187. period, div_u64(period, nr_function_calls));
  188. if (persist)
  189. return 0;
  190. ops_destroy(ops_relevant, nr_ops_relevant);
  191. ops_destroy(ops_irrelevant, nr_ops_irrelevant);
  192. /*
  193. * The benchmark completed sucessfully, but there's no reason to keep
  194. * the module around. Return an error do the user doesn't have to
  195. * manually unload the module.
  196. */
  197. return -EINVAL;
  198. }
  199. module_init(ftrace_ops_sample_init);
  200. static void __exit ftrace_ops_sample_exit(void)
  201. {
  202. ops_destroy(ops_relevant, nr_ops_relevant);
  203. ops_destroy(ops_irrelevant, nr_ops_irrelevant);
  204. }
  205. module_exit(ftrace_ops_sample_exit);
  206. MODULE_AUTHOR("Mark Rutland");
  207. MODULE_DESCRIPTION("Example of using custom ftrace_ops");
  208. MODULE_LICENSE("GPL");