]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/cddl/dev/lockstat/lockstat.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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 #define LOCKSTAT_AFRAMES 1
50 #else
51 #error "architecture not supported"
52 #endif
53
54 static d_open_t lockstat_open;
55 static void     lockstat_provide(void *, dtrace_probedesc_t *);
56 static void     lockstat_destroy(void *, dtrace_id_t, void *);
57 static void     lockstat_enable(void *, dtrace_id_t, void *);
58 static void     lockstat_disable(void *, dtrace_id_t, void *);
59 static void     lockstat_load(void *);
60 static int      lockstat_unload(void);
61
62
63 typedef struct lockstat_probe {
64         char            *lsp_func;
65         char            *lsp_name;
66         int             lsp_probe;
67         dtrace_id_t     lsp_id;
68 #ifdef __FreeBSD__
69         int             lsp_frame;
70 #endif
71 } lockstat_probe_t;
72
73 #ifdef __FreeBSD__
74 lockstat_probe_t lockstat_probes[] =
75 {
76   /* Spin Locks */
77   { LS_MTX_SPIN_LOCK,   LSS_ACQUIRE,    LS_MTX_SPIN_LOCK_ACQUIRE,
78           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
79   { LS_MTX_SPIN_LOCK,   LSS_SPIN,       LS_MTX_SPIN_LOCK_SPIN,
80           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
81   { LS_MTX_SPIN_UNLOCK, LSS_RELEASE,    LS_MTX_SPIN_UNLOCK_RELEASE,
82           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
83   /* Adaptive Locks */
84   { LS_MTX_LOCK,        LSA_ACQUIRE,    LS_MTX_LOCK_ACQUIRE,
85           DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
86   { LS_MTX_LOCK,        LSA_BLOCK,      LS_MTX_LOCK_BLOCK,
87           DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
88   { LS_MTX_LOCK,        LSA_SPIN,       LS_MTX_LOCK_SPIN,
89           DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
90   { LS_MTX_UNLOCK,      LSA_RELEASE,    LS_MTX_UNLOCK_RELEASE,
91           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
92   { LS_MTX_TRYLOCK,     LSA_ACQUIRE,    LS_MTX_TRYLOCK_ACQUIRE,
93           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
94   /* Reader/Writer Locks */
95   { LS_RW_RLOCK,        LSR_ACQUIRE,    LS_RW_RLOCK_ACQUIRE,
96           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
97   { LS_RW_RLOCK,        LSR_BLOCK,      LS_RW_RLOCK_BLOCK,
98           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
99   { LS_RW_RLOCK,        LSR_SPIN,       LS_RW_RLOCK_SPIN,
100           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
101   { LS_RW_RUNLOCK,      LSR_RELEASE,    LS_RW_RUNLOCK_RELEASE,
102           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
103   { LS_RW_WLOCK,        LSR_ACQUIRE,    LS_RW_WLOCK_ACQUIRE,
104           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
105   { LS_RW_WLOCK,        LSR_BLOCK,      LS_RW_WLOCK_BLOCK,
106           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
107   { LS_RW_WLOCK,        LSR_SPIN,       LS_RW_WLOCK_SPIN,
108           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
109   { LS_RW_WUNLOCK,      LSR_RELEASE,    LS_RW_WUNLOCK_RELEASE,
110           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
111   { LS_RW_TRYUPGRADE,   LSR_UPGRADE,    LS_RW_TRYUPGRADE_UPGRADE,
112           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
113   { LS_RW_DOWNGRADE,    LSR_DOWNGRADE,  LS_RW_DOWNGRADE_DOWNGRADE,
114           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
115   /* Shared/Exclusive Locks */
116   { LS_SX_SLOCK,        LSX_ACQUIRE,    LS_SX_SLOCK_ACQUIRE,
117           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
118   { LS_SX_SLOCK,        LSX_BLOCK,      LS_SX_SLOCK_BLOCK,
119           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
120   { LS_SX_SLOCK,        LSX_SPIN,       LS_SX_SLOCK_SPIN,
121           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
122   { LS_SX_SUNLOCK,      LSX_RELEASE,    LS_SX_SUNLOCK_RELEASE,
123           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
124   { LS_SX_XLOCK,        LSX_ACQUIRE,    LS_SX_XLOCK_ACQUIRE,
125           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
126   { LS_SX_XLOCK,        LSX_BLOCK,      LS_SX_XLOCK_BLOCK,
127           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
128   { LS_SX_XLOCK,        LSX_SPIN,       LS_SX_XLOCK_SPIN,
129           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
130   { LS_SX_XUNLOCK,      LSX_RELEASE,    LS_SX_XUNLOCK_RELEASE,
131           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
132   { LS_SX_TRYUPGRADE,   LSX_UPGRADE,    LS_SX_TRYUPGRADE_UPGRADE,
133           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
134   { LS_SX_DOWNGRADE,    LSX_DOWNGRADE,  LS_SX_DOWNGRADE_DOWNGRADE,
135           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
136   /* Thread Locks */
137   { LS_THREAD_LOCK,     LST_SPIN,       LS_THREAD_LOCK_SPIN,
138           DTRACE_IDNONE, LOCKSTAT_AFRAMES },
139   { NULL }
140 };
141 #else
142 #error "OS not supported"
143 #endif
144
145
146 static struct cdevsw lockstat_cdevsw = {
147         .d_version      = D_VERSION,
148         .d_open         = lockstat_open,
149         .d_name         = "lockstat",
150 };
151
152 static struct cdev              *lockstat_cdev; 
153 static dtrace_provider_id_t     lockstat_id;
154
155 /*ARGSUSED*/
156 static void
157 lockstat_enable(void *arg, dtrace_id_t id, void *parg)
158 {
159         lockstat_probe_t *probe = parg;
160
161         ASSERT(!lockstat_probemap[probe->lsp_probe]);
162
163         lockstat_probemap[probe->lsp_probe] = id;
164 #ifdef DOODAD
165         membar_producer();
166 #endif
167
168         lockstat_probe_func = dtrace_probe;
169 #ifdef DOODAD
170         membar_producer();
171
172         lockstat_hot_patch();
173         membar_producer();
174 #endif
175 }
176
177 /*ARGSUSED*/
178 static void
179 lockstat_disable(void *arg, dtrace_id_t id, void *parg)
180 {
181         lockstat_probe_t *probe = parg;
182         int i;
183
184         ASSERT(lockstat_probemap[probe->lsp_probe]);
185
186         lockstat_probemap[probe->lsp_probe] = 0;
187 #ifdef DOODAD
188         lockstat_hot_patch();
189         membar_producer();
190 #endif
191
192         /*
193          * See if we have any probes left enabled.
194          */
195         for (i = 0; i < LS_NPROBES; i++) {
196                 if (lockstat_probemap[i]) {
197                         /*
198                          * This probe is still enabled.  We don't need to deal
199                          * with waiting for all threads to be out of the
200                          * lockstat critical sections; just return.
201                          */
202                         return;
203                 }
204         }
205
206 }
207
208 /*ARGSUSED*/
209 static int
210 lockstat_open(struct cdev *dev __unused, int oflags __unused, 
211               int devtype __unused, struct thread *td __unused)
212 {
213         return (0);
214 }
215
216 /*ARGSUSED*/
217 static void
218 lockstat_provide(void *arg, dtrace_probedesc_t *desc)
219 {
220         int i = 0;
221
222         for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) {
223                 lockstat_probe_t *probe = &lockstat_probes[i];
224
225                 if (dtrace_probe_lookup(lockstat_id, "kernel",
226                     probe->lsp_func, probe->lsp_name) != 0)
227                         continue;
228
229                 ASSERT(!probe->lsp_id);
230 #ifdef __FreeBSD__
231                 probe->lsp_id = dtrace_probe_create(lockstat_id,
232                     "kernel", probe->lsp_func, probe->lsp_name,
233                     probe->lsp_frame, probe);
234 #else
235                 probe->lsp_id = dtrace_probe_create(lockstat_id,
236                     "kernel", probe->lsp_func, probe->lsp_name,
237                     LOCKSTAT_AFRAMES, probe);
238 #endif
239         }
240 }
241
242 /*ARGSUSED*/
243 static void
244 lockstat_destroy(void *arg, dtrace_id_t id, void *parg)
245 {
246         lockstat_probe_t *probe = parg;
247
248         ASSERT(!lockstat_probemap[probe->lsp_probe]);
249         probe->lsp_id = 0;
250 }
251
252 static dtrace_pattr_t lockstat_attr = {
253 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
254 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
255 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
256 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
257 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
258 };
259
260 static dtrace_pops_t lockstat_pops = {
261         lockstat_provide,
262         NULL,
263         lockstat_enable,
264         lockstat_disable,
265         NULL,
266         NULL,
267         NULL,
268         NULL,
269         NULL,
270         lockstat_destroy
271 };
272
273 static void
274 lockstat_load(void *dummy)
275 {
276         /* Create the /dev/dtrace/lockstat entry. */
277         lockstat_cdev = make_dev(&lockstat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
278             "dtrace/lockstat");
279
280         if (dtrace_register("lockstat", &lockstat_attr, DTRACE_PRIV_USER,
281             NULL, &lockstat_pops, NULL, &lockstat_id) != 0)
282                 return;
283 }
284
285 static int
286 lockstat_unload()
287 {
288         int error = 0;
289
290         if ((error = dtrace_unregister(lockstat_id)) != 0)
291             return (error);
292
293         destroy_dev(lockstat_cdev);
294
295         return (error);
296 }
297
298 /* ARGSUSED */
299 static int
300 lockstat_modevent(module_t mod __unused, int type, void *data __unused)
301 {
302         int error = 0;
303
304         switch (type) {
305         case MOD_LOAD:
306                 break;
307
308         case MOD_UNLOAD:
309                 break;
310
311         case MOD_SHUTDOWN:
312                 break;
313
314         default:
315                 error = EOPNOTSUPP;
316                 break;
317         }
318         return (error);
319 }
320
321 SYSINIT(lockstat_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_load, NULL);
322 SYSUNINIT(lockstat_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_unload, NULL);
323
324 DEV_MODULE(lockstat, lockstat_modevent, NULL);
325 MODULE_VERSION(lockstat, 1);
326 MODULE_DEPEND(lockstat, dtrace, 1, 1, 1);
327 MODULE_DEPEND(lockstat, opensolaris, 1, 1, 1);