]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/cddl/dev/lockstat/lockstat.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / cddl / dev / lockstat / lockstat.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  * Portions Copyright (c) 2008-2009 Stacey Son <sson@FreeBSD.org> 
22  *
23  * $FreeBSD$
24  *
25  */
26
27 /*
28  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
29  * Use is subject to license terms.
30  */
31
32 #include "opt_kdtrace.h"
33
34 #include <sys/cdefs.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/kernel.h>
39 #include <sys/limits.h>
40 #include <sys/lock.h>
41 #include <sys/linker.h>
42 #include <sys/module.h>
43 #include <sys/mutex.h>
44
45 #include <sys/dtrace.h>
46 #include <sys/lockstat.h>
47
48 #if defined(__i386__) || defined(__amd64__) || \
49         defined(__mips__) || defined(__powerpc__)
50 #define LOCKSTAT_AFRAMES 1
51 #else
52 #error "architecture not supported"
53 #endif
54
55 static d_open_t lockstat_open;
56 static void     lockstat_provide(void *, dtrace_probedesc_t *);
57 static void     lockstat_destroy(void *, dtrace_id_t, void *);
58 static void     lockstat_enable(void *, dtrace_id_t, void *);
59 static void     lockstat_disable(void *, dtrace_id_t, void *);
60 static void     lockstat_load(void *);
61 static int      lockstat_unload(void);
62
63
64 typedef struct lockstat_probe {
65         char            *lsp_func;
66         char            *lsp_name;
67         int             lsp_probe;
68         dtrace_id_t     lsp_id;
69 #ifdef __FreeBSD__
70         int             lsp_frame;
71 #endif
72 } lockstat_probe_t;
73
74 #ifdef __FreeBSD__
75 lockstat_probe_t lockstat_probes[] =
76 {
77   /* Spin Locks */
78   { LS_MTX_SPIN_LOCK,   LSS_ACQUIRE,    LS_MTX_SPIN_LOCK_ACQUIRE,
79           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
80   { LS_MTX_SPIN_LOCK,   LSS_SPIN,       LS_MTX_SPIN_LOCK_SPIN,
81           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
82   { LS_MTX_SPIN_UNLOCK, LSS_RELEASE,    LS_MTX_SPIN_UNLOCK_RELEASE,
83           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
84   /* Adaptive Locks */
85   { LS_MTX_LOCK,        LSA_ACQUIRE,    LS_MTX_LOCK_ACQUIRE,
86           DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
87   { LS_MTX_LOCK,        LSA_BLOCK,      LS_MTX_LOCK_BLOCK,
88           DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
89   { LS_MTX_LOCK,        LSA_SPIN,       LS_MTX_LOCK_SPIN,
90           DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
91   { LS_MTX_UNLOCK,      LSA_RELEASE,    LS_MTX_UNLOCK_RELEASE,
92           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
93   { LS_MTX_TRYLOCK,     LSA_ACQUIRE,    LS_MTX_TRYLOCK_ACQUIRE,
94           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
95   /* Reader/Writer Locks */
96   { LS_RW_RLOCK,        LSR_ACQUIRE,    LS_RW_RLOCK_ACQUIRE,
97           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
98   { LS_RW_RLOCK,        LSR_BLOCK,      LS_RW_RLOCK_BLOCK,
99           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
100   { LS_RW_RLOCK,        LSR_SPIN,       LS_RW_RLOCK_SPIN,
101           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
102   { LS_RW_RUNLOCK,      LSR_RELEASE,    LS_RW_RUNLOCK_RELEASE,
103           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
104   { LS_RW_WLOCK,        LSR_ACQUIRE,    LS_RW_WLOCK_ACQUIRE,
105           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
106   { LS_RW_WLOCK,        LSR_BLOCK,      LS_RW_WLOCK_BLOCK,
107           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
108   { LS_RW_WLOCK,        LSR_SPIN,       LS_RW_WLOCK_SPIN,
109           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
110   { LS_RW_WUNLOCK,      LSR_RELEASE,    LS_RW_WUNLOCK_RELEASE,
111           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
112   { LS_RW_TRYUPGRADE,   LSR_UPGRADE,    LS_RW_TRYUPGRADE_UPGRADE,
113           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
114   { LS_RW_DOWNGRADE,    LSR_DOWNGRADE,  LS_RW_DOWNGRADE_DOWNGRADE,
115           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
116   /* Shared/Exclusive Locks */
117   { LS_SX_SLOCK,        LSX_ACQUIRE,    LS_SX_SLOCK_ACQUIRE,
118           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
119   { LS_SX_SLOCK,        LSX_BLOCK,      LS_SX_SLOCK_BLOCK,
120           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
121   { LS_SX_SLOCK,        LSX_SPIN,       LS_SX_SLOCK_SPIN,
122           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
123   { LS_SX_SUNLOCK,      LSX_RELEASE,    LS_SX_SUNLOCK_RELEASE,
124           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
125   { LS_SX_XLOCK,        LSX_ACQUIRE,    LS_SX_XLOCK_ACQUIRE,
126           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
127   { LS_SX_XLOCK,        LSX_BLOCK,      LS_SX_XLOCK_BLOCK,
128           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
129   { LS_SX_XLOCK,        LSX_SPIN,       LS_SX_XLOCK_SPIN,
130           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
131   { LS_SX_XUNLOCK,      LSX_RELEASE,    LS_SX_XUNLOCK_RELEASE,
132           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
133   { LS_SX_TRYUPGRADE,   LSX_UPGRADE,    LS_SX_TRYUPGRADE_UPGRADE,
134           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
135   { LS_SX_DOWNGRADE,    LSX_DOWNGRADE,  LS_SX_DOWNGRADE_DOWNGRADE,
136           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
137   /* Thread Locks */
138   { LS_THREAD_LOCK,     LST_SPIN,       LS_THREAD_LOCK_SPIN,
139           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
140   { NULL }
141 };
142 #else
143 #error "OS not supported"
144 #endif
145
146
147 static struct cdevsw lockstat_cdevsw = {
148         .d_version      = D_VERSION,
149         .d_open         = lockstat_open,
150         .d_name         = "lockstat",
151 };
152
153 static struct cdev              *lockstat_cdev; 
154 static dtrace_provider_id_t     lockstat_id;
155
156 /*ARGSUSED*/
157 static void
158 lockstat_enable(void *arg, dtrace_id_t id, void *parg)
159 {
160         lockstat_probe_t *probe = parg;
161
162         ASSERT(!lockstat_probemap[probe->lsp_probe]);
163
164         lockstat_enabled++;
165
166         lockstat_probemap[probe->lsp_probe] = id;
167 #ifdef DOODAD
168         membar_producer();
169 #endif
170
171         lockstat_probe_func = dtrace_probe;
172 #ifdef DOODAD
173         membar_producer();
174
175         lockstat_hot_patch();
176         membar_producer();
177 #endif
178 }
179
180 /*ARGSUSED*/
181 static void
182 lockstat_disable(void *arg, dtrace_id_t id, void *parg)
183 {
184         lockstat_probe_t *probe = parg;
185         int i;
186
187         ASSERT(lockstat_probemap[probe->lsp_probe]);
188
189         lockstat_enabled--;
190
191         lockstat_probemap[probe->lsp_probe] = 0;
192 #ifdef DOODAD
193         lockstat_hot_patch();
194         membar_producer();
195 #endif
196
197         /*
198          * See if we have any probes left enabled.
199          */
200         for (i = 0; i < LS_NPROBES; i++) {
201                 if (lockstat_probemap[i]) {
202                         /*
203                          * This probe is still enabled.  We don't need to deal
204                          * with waiting for all threads to be out of the
205                          * lockstat critical sections; just return.
206                          */
207                         return;
208                 }
209         }
210
211 }
212
213 /*ARGSUSED*/
214 static int
215 lockstat_open(struct cdev *dev __unused, int oflags __unused, 
216               int devtype __unused, struct thread *td __unused)
217 {
218         return (0);
219 }
220
221 /*ARGSUSED*/
222 static void
223 lockstat_provide(void *arg, dtrace_probedesc_t *desc)
224 {
225         int i = 0;
226
227         for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) {
228                 lockstat_probe_t *probe = &lockstat_probes[i];
229
230                 if (dtrace_probe_lookup(lockstat_id, "kernel",
231                     probe->lsp_func, probe->lsp_name) != 0)
232                         continue;
233
234                 ASSERT(!probe->lsp_id);
235 #ifdef __FreeBSD__
236                 probe->lsp_id = dtrace_probe_create(lockstat_id,
237                     "kernel", probe->lsp_func, probe->lsp_name,
238                     probe->lsp_frame, probe);
239 #else
240                 probe->lsp_id = dtrace_probe_create(lockstat_id,
241                     "kernel", probe->lsp_func, probe->lsp_name,
242                     LOCKSTAT_AFRAMES, probe);
243 #endif
244         }
245 }
246
247 /*ARGSUSED*/
248 static void
249 lockstat_destroy(void *arg, dtrace_id_t id, void *parg)
250 {
251         lockstat_probe_t *probe = parg;
252
253         ASSERT(!lockstat_probemap[probe->lsp_probe]);
254         probe->lsp_id = 0;
255 }
256
257 static dtrace_pattr_t lockstat_attr = {
258 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
259 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
260 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
261 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
262 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
263 };
264
265 static dtrace_pops_t lockstat_pops = {
266         lockstat_provide,
267         NULL,
268         lockstat_enable,
269         lockstat_disable,
270         NULL,
271         NULL,
272         NULL,
273         NULL,
274         NULL,
275         lockstat_destroy
276 };
277
278 static void
279 lockstat_load(void *dummy)
280 {
281         /* Create the /dev/dtrace/lockstat entry. */
282         lockstat_cdev = make_dev(&lockstat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
283             "dtrace/lockstat");
284
285         if (dtrace_register("lockstat", &lockstat_attr, DTRACE_PRIV_USER,
286             NULL, &lockstat_pops, NULL, &lockstat_id) != 0)
287                 return;
288 }
289
290 static int
291 lockstat_unload()
292 {
293         int error = 0;
294
295         if ((error = dtrace_unregister(lockstat_id)) != 0)
296             return (error);
297
298         destroy_dev(lockstat_cdev);
299
300         return (error);
301 }
302
303 /* ARGSUSED */
304 static int
305 lockstat_modevent(module_t mod __unused, int type, void *data __unused)
306 {
307         int error = 0;
308
309         switch (type) {
310         case MOD_LOAD:
311                 break;
312
313         case MOD_UNLOAD:
314                 break;
315
316         case MOD_SHUTDOWN:
317                 break;
318
319         default:
320                 error = EOPNOTSUPP;
321                 break;
322         }
323         return (error);
324 }
325
326 SYSINIT(lockstat_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_load, NULL);
327 SYSUNINIT(lockstat_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_unload, NULL);
328
329 DEV_MODULE(lockstat, lockstat_modevent, NULL);
330 MODULE_VERSION(lockstat, 1);
331 MODULE_DEPEND(lockstat, dtrace, 1, 1, 1);
332 MODULE_DEPEND(lockstat, opensolaris, 1, 1, 1);