rcupreempt_trace.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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/rcupdate.h>
  42. #include <linux/cpu.h>
  43. #include <linux/mutex.h>
  44. #include <linux/rcupreempt_trace.h>
  45. #include <linux/debugfs.h>
  46. static struct mutex rcupreempt_trace_mutex;
  47. static char *rcupreempt_trace_buf;
  48. #define RCUPREEMPT_TRACE_BUF_SIZE 4096
  49. void rcupreempt_trace_move2done(struct rcupreempt_trace *trace)
  50. {
  51. trace->done_length += trace->wait_length;
  52. trace->done_add += trace->wait_length;
  53. trace->wait_length = 0;
  54. }
  55. void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace)
  56. {
  57. trace->wait_length += trace->next_length;
  58. trace->wait_add += trace->next_length;
  59. trace->next_length = 0;
  60. }
  61. void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace)
  62. {
  63. atomic_inc(&trace->rcu_try_flip_1);
  64. }
  65. void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace)
  66. {
  67. atomic_inc(&trace->rcu_try_flip_e1);
  68. }
  69. void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace)
  70. {
  71. trace->rcu_try_flip_i1++;
  72. }
  73. void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace)
  74. {
  75. trace->rcu_try_flip_ie1++;
  76. }
  77. void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace)
  78. {
  79. trace->rcu_try_flip_g1++;
  80. }
  81. void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace)
  82. {
  83. trace->rcu_try_flip_a1++;
  84. }
  85. void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace)
  86. {
  87. trace->rcu_try_flip_ae1++;
  88. }
  89. void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace)
  90. {
  91. trace->rcu_try_flip_a2++;
  92. }
  93. void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace)
  94. {
  95. trace->rcu_try_flip_z1++;
  96. }
  97. void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace)
  98. {
  99. trace->rcu_try_flip_ze1++;
  100. }
  101. void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace)
  102. {
  103. trace->rcu_try_flip_z2++;
  104. }
  105. void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace)
  106. {
  107. trace->rcu_try_flip_m1++;
  108. }
  109. void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace)
  110. {
  111. trace->rcu_try_flip_me1++;
  112. }
  113. void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace)
  114. {
  115. trace->rcu_try_flip_m2++;
  116. }
  117. void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace)
  118. {
  119. trace->rcu_check_callbacks++;
  120. }
  121. void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace)
  122. {
  123. trace->done_remove += trace->done_length;
  124. trace->done_length = 0;
  125. }
  126. void rcupreempt_trace_invoke(struct rcupreempt_trace *trace)
  127. {
  128. atomic_inc(&trace->done_invoked);
  129. }
  130. void rcupreempt_trace_next_add(struct rcupreempt_trace *trace)
  131. {
  132. trace->next_add++;
  133. trace->next_length++;
  134. }
  135. static void rcupreempt_trace_sum(struct rcupreempt_trace *sp)
  136. {
  137. struct rcupreempt_trace *cp;
  138. int cpu;
  139. memset(sp, 0, sizeof(*sp));
  140. for_each_possible_cpu(cpu) {
  141. cp = rcupreempt_trace_cpu(cpu);
  142. sp->next_length += cp->next_length;
  143. sp->next_add += cp->next_add;
  144. sp->wait_length += cp->wait_length;
  145. sp->wait_add += cp->wait_add;
  146. sp->done_length += cp->done_length;
  147. sp->done_add += cp->done_add;
  148. sp->done_remove += cp->done_remove;
  149. atomic_set(&sp->done_invoked, atomic_read(&cp->done_invoked));
  150. sp->rcu_check_callbacks += cp->rcu_check_callbacks;
  151. atomic_set(&sp->rcu_try_flip_1,
  152. atomic_read(&cp->rcu_try_flip_1));
  153. atomic_set(&sp->rcu_try_flip_e1,
  154. atomic_read(&cp->rcu_try_flip_e1));
  155. sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1;
  156. sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1;
  157. sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1;
  158. sp->rcu_try_flip_a1 += cp->rcu_try_flip_a1;
  159. sp->rcu_try_flip_ae1 += cp->rcu_try_flip_ae1;
  160. sp->rcu_try_flip_a2 += cp->rcu_try_flip_a2;
  161. sp->rcu_try_flip_z1 += cp->rcu_try_flip_z1;
  162. sp->rcu_try_flip_ze1 += cp->rcu_try_flip_ze1;
  163. sp->rcu_try_flip_z2 += cp->rcu_try_flip_z2;
  164. sp->rcu_try_flip_m1 += cp->rcu_try_flip_m1;
  165. sp->rcu_try_flip_me1 += cp->rcu_try_flip_me1;
  166. sp->rcu_try_flip_m2 += cp->rcu_try_flip_m2;
  167. }
  168. }
  169. static ssize_t rcustats_read(struct file *filp, char __user *buffer,
  170. size_t count, loff_t *ppos)
  171. {
  172. struct rcupreempt_trace trace;
  173. ssize_t bcount;
  174. int cnt = 0;
  175. rcupreempt_trace_sum(&trace);
  176. mutex_lock(&rcupreempt_trace_mutex);
  177. snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  178. "ggp=%ld rcc=%ld\n",
  179. rcu_batches_completed(),
  180. trace.rcu_check_callbacks);
  181. snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  182. "na=%ld nl=%ld wa=%ld wl=%ld da=%ld dl=%ld dr=%ld di=%d\n"
  183. "1=%d e1=%d i1=%ld ie1=%ld g1=%ld a1=%ld ae1=%ld a2=%ld\n"
  184. "z1=%ld ze1=%ld z2=%ld m1=%ld me1=%ld m2=%ld\n",
  185. trace.next_add, trace.next_length,
  186. trace.wait_add, trace.wait_length,
  187. trace.done_add, trace.done_length,
  188. trace.done_remove, atomic_read(&trace.done_invoked),
  189. atomic_read(&trace.rcu_try_flip_1),
  190. atomic_read(&trace.rcu_try_flip_e1),
  191. trace.rcu_try_flip_i1, trace.rcu_try_flip_ie1,
  192. trace.rcu_try_flip_g1,
  193. trace.rcu_try_flip_a1, trace.rcu_try_flip_ae1,
  194. trace.rcu_try_flip_a2,
  195. trace.rcu_try_flip_z1, trace.rcu_try_flip_ze1,
  196. trace.rcu_try_flip_z2,
  197. trace.rcu_try_flip_m1, trace.rcu_try_flip_me1,
  198. trace.rcu_try_flip_m2);
  199. bcount = simple_read_from_buffer(buffer, count, ppos,
  200. rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
  201. mutex_unlock(&rcupreempt_trace_mutex);
  202. return bcount;
  203. }
  204. static ssize_t rcugp_read(struct file *filp, char __user *buffer,
  205. size_t count, loff_t *ppos)
  206. {
  207. long oldgp = rcu_batches_completed();
  208. ssize_t bcount;
  209. mutex_lock(&rcupreempt_trace_mutex);
  210. synchronize_rcu();
  211. snprintf(rcupreempt_trace_buf, RCUPREEMPT_TRACE_BUF_SIZE,
  212. "oldggp=%ld newggp=%ld\n", oldgp, rcu_batches_completed());
  213. bcount = simple_read_from_buffer(buffer, count, ppos,
  214. rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
  215. mutex_unlock(&rcupreempt_trace_mutex);
  216. return bcount;
  217. }
  218. static ssize_t rcuctrs_read(struct file *filp, char __user *buffer,
  219. size_t count, loff_t *ppos)
  220. {
  221. int cnt = 0;
  222. int cpu;
  223. int f = rcu_batches_completed() & 0x1;
  224. ssize_t bcount;
  225. mutex_lock(&rcupreempt_trace_mutex);
  226. cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE,
  227. "CPU last cur F M\n");
  228. for_each_online_cpu(cpu) {
  229. long *flipctr = rcupreempt_flipctr(cpu);
  230. cnt += snprintf(&rcupreempt_trace_buf[cnt],
  231. RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  232. "%3d %4ld %3ld %d %d\n",
  233. cpu,
  234. flipctr[!f],
  235. flipctr[f],
  236. rcupreempt_flip_flag(cpu),
  237. rcupreempt_mb_flag(cpu));
  238. }
  239. cnt += snprintf(&rcupreempt_trace_buf[cnt],
  240. RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  241. "ggp = %ld, state = %s\n",
  242. rcu_batches_completed(),
  243. rcupreempt_try_flip_state_name());
  244. cnt += snprintf(&rcupreempt_trace_buf[cnt],
  245. RCUPREEMPT_TRACE_BUF_SIZE - cnt,
  246. "\n");
  247. bcount = simple_read_from_buffer(buffer, count, ppos,
  248. rcupreempt_trace_buf, strlen(rcupreempt_trace_buf));
  249. mutex_unlock(&rcupreempt_trace_mutex);
  250. return bcount;
  251. }
  252. static struct file_operations rcustats_fops = {
  253. .owner = THIS_MODULE,
  254. .read = rcustats_read,
  255. };
  256. static struct file_operations rcugp_fops = {
  257. .owner = THIS_MODULE,
  258. .read = rcugp_read,
  259. };
  260. static struct file_operations rcuctrs_fops = {
  261. .owner = THIS_MODULE,
  262. .read = rcuctrs_read,
  263. };
  264. static struct dentry *rcudir, *statdir, *ctrsdir, *gpdir;
  265. static int rcupreempt_debugfs_init(void)
  266. {
  267. rcudir = debugfs_create_dir("rcu", NULL);
  268. if (!rcudir)
  269. goto out;
  270. statdir = debugfs_create_file("rcustats", 0444, rcudir,
  271. NULL, &rcustats_fops);
  272. if (!statdir)
  273. goto free_out;
  274. gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
  275. if (!gpdir)
  276. goto free_out;
  277. ctrsdir = debugfs_create_file("rcuctrs", 0444, rcudir,
  278. NULL, &rcuctrs_fops);
  279. if (!ctrsdir)
  280. goto free_out;
  281. return 0;
  282. free_out:
  283. if (statdir)
  284. debugfs_remove(statdir);
  285. if (gpdir)
  286. debugfs_remove(gpdir);
  287. debugfs_remove(rcudir);
  288. out:
  289. return 1;
  290. }
  291. static int __init rcupreempt_trace_init(void)
  292. {
  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. return rcupreempt_debugfs_init();
  298. }
  299. static void __exit rcupreempt_trace_cleanup(void)
  300. {
  301. debugfs_remove(statdir);
  302. debugfs_remove(gpdir);
  303. debugfs_remove(ctrsdir);
  304. debugfs_remove(rcudir);
  305. kfree(rcupreempt_trace_buf);
  306. }
  307. module_init(rcupreempt_trace_init);
  308. module_exit(rcupreempt_trace_cleanup);