rcupreempt_trace.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * Read-Copy Update tracing for realtime implementation
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. *
  18. * Copyright IBM Corporation, 2006
  19. *
  20. * Papers: http://www.rdrop.com/users/paulmck/RCU
  21. *
  22. * For detailed explanation of Read-Copy Update mechanism see -
  23. * Documentation/RCU/ *.txt
  24. *
  25. */
  26. #include <linux/types.h>
  27. #include <linux/kernel.h>
  28. #include <linux/init.h>
  29. #include <linux/spinlock.h>
  30. #include <linux/smp.h>
  31. #include <linux/rcupdate.h>
  32. #include <linux/interrupt.h>
  33. #include <linux/sched.h>
  34. #include <asm/atomic.h>
  35. #include <linux/bitops.h>
  36. #include <linux/module.h>
  37. #include <linux/completion.h>
  38. #include <linux/moduleparam.h>
  39. #include <linux/percpu.h>
  40. #include <linux/notifier.h>
  41. #include <linux/cpu.h>
  42. #include <linux/mutex.h>
  43. #include <linux/rcupreempt_trace.h>
  44. #include <linux/debugfs.h>
  45. static struct mutex rcupreempt_trace_mutex;
  46. static char *rcupreempt_trace_buf;
  47. #define RCUPREEMPT_TRACE_BUF_SIZE 4096
  48. void rcupreempt_trace_move2done(struct rcupreempt_trace *trace)
  49. {
  50. trace->done_length += trace->wait_length;
  51. trace->done_add += trace->wait_length;
  52. trace->wait_length = 0;
  53. }
  54. void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace)
  55. {
  56. trace->wait_length += trace->next_length;
  57. trace->wait_add += trace->next_length;
  58. trace->next_length = 0;
  59. }
  60. void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace)
  61. {
  62. atomic_inc(&trace->rcu_try_flip_1);
  63. }
  64. void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace)
  65. {
  66. atomic_inc(&trace->rcu_try_flip_e1);
  67. }
  68. void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace)
  69. {
  70. trace->rcu_try_flip_i1++;
  71. }
  72. void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace)
  73. {
  74. trace->rcu_try_flip_ie1++;
  75. }
  76. void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace)
  77. {
  78. trace->rcu_try_flip_g1++;
  79. }
  80. void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace)
  81. {
  82. trace->rcu_try_flip_a1++;
  83. }
  84. void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace)
  85. {
  86. trace->rcu_try_flip_ae1++;
  87. }
  88. void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace)
  89. {
  90. trace->rcu_try_flip_a2++;
  91. }
  92. void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace)
  93. {
  94. trace->rcu_try_flip_z1++;
  95. }
  96. void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace)
  97. {
  98. trace->rcu_try_flip_ze1++;
  99. }
  100. void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace)
  101. {
  102. trace->rcu_try_flip_z2++;
  103. }
  104. void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace)
  105. {
  106. trace->rcu_try_flip_m1++;
  107. }
  108. void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace)
  109. {
  110. trace->rcu_try_flip_me1++;
  111. }
  112. void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace)
  113. {
  114. trace->rcu_try_flip_m2++;
  115. }
  116. void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace)
  117. {
  118. trace->rcu_check_callbacks++;
  119. }
  120. void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace)
  121. {
  122. trace->done_remove += trace->done_length;
  123. trace->done_length = 0;
  124. }
  125. void rcupreempt_trace_invoke(struct rcupreempt_trace *trace)
  126. {
  127. atomic_inc(&trace->done_invoked);
  128. }
  129. void rcupreempt_trace_next_add(struct rcupreempt_trace *trace)
  130. {
  131. trace->next_add++;
  132. trace->next_length++;
  133. }
  134. static void rcupreempt_trace_sum(struct rcupreempt_trace *sp)
  135. {
  136. struct rcupreempt_trace *cp;
  137. int cpu;
  138. memset(sp, 0, sizeof(*sp));
  139. for_each_possible_cpu(cpu) {
  140. cp = rcupreempt_trace_cpu(cpu);
  141. sp->next_length += cp->next_length;
  142. sp->next_add += cp->next_add;
  143. sp->wait_length += cp->wait_length;
  144. sp->wait_add += cp->wait_add;
  145. sp->done_length += cp->done_length;
  146. sp->done_add += cp->done_add;
  147. sp->done_remove += cp->done_remove;
  148. atomic_add(atomic_read(&cp->done_invoked), &sp->done_invoked);
  149. sp->rcu_check_callbacks += cp->rcu_check_callbacks;
  150. atomic_add(atomic_read(&cp->rcu_try_flip_1),
  151. &sp->rcu_try_flip_1);
  152. atomic_add(atomic_read(&cp->rcu_try_flip_e1),
  153. &sp->rcu_try_flip_e1);
  154. sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1;
  155. sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1;
  156. sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1;
  157. sp->rcu_try_flip_a1 += cp->rcu_try_flip_a1;
  158. sp->rcu_try_flip_ae1 += cp->rcu_try_flip_ae1;
  159. sp->rcu_try_flip_a2 += cp->rcu_try_flip_a2;
  160. sp->rcu_try_flip_z1 += cp->rcu_try_flip_z1;
  161. sp->rcu_try_flip_ze1 += cp->rcu_try_flip_ze1;
  162. sp->rcu_try_flip_z2 += cp->rcu_try_flip_z2;
  163. sp->rcu_try_flip_m1 += cp->rcu_try_flip_m1;
  164. sp->rcu_try_flip_me1 += cp->rcu_try_flip_me1;
  165. sp->rcu_try_flip_m2 += cp->rcu_try_flip_m2;
  166. }
  167. }
  168. static ssize_t rcustats_read(struct file *filp, char __user *buffer,
  169. size_t count, loff_t *ppos)
  170. {
  171. struct rcupreempt_trace trace;
  172. ssize_t bcount;
  173. int cnt = 0;
  174. rcupreempt_trace_sum(&trace);
  175. mutex_lock(&rcupreempt_trace_mutex);
  176. snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  177. "ggp=%ld rcc=%ld\n",
  178. rcu_batches_completed(),
  179. trace.rcu_check_callbacks);
  180. snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  181. "na=%ld nl=%ld wa=%ld wl=%ld da=%ld dl=%ld dr=%ld di=%d\n"
  182. "1=%d e1=%d i1=%ld ie1=%ld g1=%ld a1=%ld ae1=%ld a2=%ld\n"
  183. "z1=%ld ze1=%ld z2=%ld m1=%ld me1=%ld m2=%ld\n",
  184. trace.next_add, trace.next_length,
  185. trace.wait_add, trace.wait_length,
  186. trace.done_add, trace.done_length,
  187. trace.done_remove, atomic_read(&trace.done_invoked),
  188. atomic_read(&trace.rcu_try_flip_1),
  189. atomic_read(&trace.rcu_try_flip_e1),
  190. trace.rcu_try_flip_i1, trace.rcu_try_flip_ie1,
  191. trace.rcu_try_flip_g1,
  192. trace.rcu_try_flip_a1, trace.rcu_try_flip_ae1,
  193. trace.rcu_try_flip_a2,
  194. trace.rcu_try_flip_z1, trace.rcu_try_flip_ze1,
  195. trace.rcu_try_flip_z2,
  196. trace.rcu_try_flip_m1, trace.rcu_try_flip_me1,
  197. trace.rcu_try_flip_m2);
  198. bcount = simple_read_from_buffer(buffer, count, ppos,
  199. rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
  200. mutex_unlock(&rcupreempt_trace_mutex);
  201. return bcount;
  202. }
  203. static ssize_t rcugp_read(struct file *filp, char __user *buffer,
  204. size_t count, loff_t *ppos)
  205. {
  206. long oldgp = rcu_batches_completed();
  207. ssize_t bcount;
  208. mutex_lock(&rcupreempt_trace_mutex);
  209. synchronize_rcu();
  210. snprintf(rcupreempt_trace_buf, RCUPREEMPT_TRACE_BUF_SIZE,
  211. "oldggp=%ld newggp=%ld\n", oldgp, rcu_batches_completed());
  212. bcount = simple_read_from_buffer(buffer, count, ppos,
  213. rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
  214. mutex_unlock(&rcupreempt_trace_mutex);
  215. return bcount;
  216. }
  217. static ssize_t rcuctrs_read(struct file *filp, char __user *buffer,
  218. size_t count, loff_t *ppos)
  219. {
  220. int cnt = 0;
  221. int cpu;
  222. int f = rcu_batches_completed() & 0x1;
  223. ssize_t bcount;
  224. mutex_lock(&rcupreempt_trace_mutex);
  225. cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE,
  226. "CPU last cur F M\n");
  227. for_each_online_cpu(cpu) {
  228. long *flipctr = rcupreempt_flipctr(cpu);
  229. cnt += snprintf(&rcupreempt_trace_buf[cnt],
  230. RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  231. "%3d %4ld %3ld %d %d\n",
  232. cpu,
  233. flipctr[!f],
  234. flipctr[f],
  235. rcupreempt_flip_flag(cpu),
  236. rcupreempt_mb_flag(cpu));
  237. }
  238. cnt += snprintf(&rcupreempt_trace_buf[cnt],
  239. RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  240. "ggp = %ld, state = %s\n",
  241. rcu_batches_completed(),
  242. rcupreempt_try_flip_state_name());
  243. cnt += snprintf(&rcupreempt_trace_buf[cnt],
  244. RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  245. "\n");
  246. bcount = simple_read_from_buffer(buffer, count, ppos,
  247. rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
  248. mutex_unlock(&rcupreempt_trace_mutex);
  249. return bcount;
  250. }
  251. static struct file_operations rcustats_fops = {
  252. .owner = THIS_MODULE,
  253. .read = rcustats_read,
  254. };
  255. static struct file_operations rcugp_fops = {
  256. .owner = THIS_MODULE,
  257. .read = rcugp_read,
  258. };
  259. static struct file_operations rcuctrs_fops = {
  260. .owner = THIS_MODULE,
  261. .read = rcuctrs_read,
  262. };
  263. static struct dentry *rcudir, *statdir, *ctrsdir, *gpdir;
  264. static int rcupreempt_debugfs_init(void)
  265. {
  266. rcudir = debugfs_create_dir("rcu", NULL);
  267. if (!rcudir)
  268. goto out;
  269. statdir = debugfs_create_file("rcustats", 0444, rcudir,
  270. NULL, &rcustats_fops);
  271. if (!statdir)
  272. goto free_out;
  273. gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
  274. if (!gpdir)
  275. goto free_out;
  276. ctrsdir = debugfs_create_file("rcuctrs", 0444, rcudir,
  277. NULL, &rcuctrs_fops);
  278. if (!ctrsdir)
  279. goto free_out;
  280. return 0;
  281. free_out:
  282. if (statdir)
  283. debugfs_remove(statdir);
  284. if (gpdir)
  285. debugfs_remove(gpdir);
  286. debugfs_remove(rcudir);
  287. out:
  288. return 1;
  289. }
  290. static int __init rcupreempt_trace_init(void)
  291. {
  292. int ret;
  293. mutex_init(&rcupreempt_trace_mutex);
  294. rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL);
  295. if (!rcupreempt_trace_buf)
  296. return 1;
  297. ret = rcupreempt_debugfs_init();
  298. if (ret)
  299. kfree(rcupreempt_trace_buf);
  300. return ret;
  301. }
  302. static void __exit rcupreempt_trace_cleanup(void)
  303. {
  304. debugfs_remove(statdir);
  305. debugfs_remove(gpdir);
  306. debugfs_remove(ctrsdir);
  307. debugfs_remove(rcudir);
  308. kfree(rcupreempt_trace_buf);
  309. }
  310. module_init(rcupreempt_trace_init);
  311. module_exit(rcupreempt_trace_cleanup);