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