]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/cddl/dev/lockstat/lockstat.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.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_probemap[probe->lsp_probe] = id;
165 #ifdef DOODAD
166         membar_producer();
167 #endif
168
169         lockstat_probe_func = dtrace_probe;
170 #ifdef DOODAD
171         membar_producer();
172
173         lockstat_hot_patch();
174         membar_producer();
175 #endif
176 }
177
178 /*ARGSUSED*/
179 static void
180 lockstat_disable(void *arg, dtrace_id_t id, void *parg)
181 {
182         lockstat_probe_t *probe = parg;
183         int i;
184
185         ASSERT(lockstat_probemap[probe->lsp_probe]);
186
187         lockstat_probemap[probe->lsp_probe] = 0;
188 #ifdef DOODAD
189         lockstat_hot_patch();
190         membar_producer();
191 #endif
192
193         /*
194          * See if we have any probes left enabled.
195          */
196         for (i = 0; i < LS_NPROBES; i++) {
197                 if (lockstat_probemap[i]) {
198                         /*
199                          * This probe is still enabled.  We don't need to deal
200                          * with waiting for all threads to be out of the
201                          * lockstat critical sections; just return.
202                          */
203                         return;
204                 }
205         }
206
207 }
208
209 /*ARGSUSED*/
210 static int
211 lockstat_open(struct cdev *dev __unused, int oflags __unused, 
212               int devtype __unused, struct thread *td __unused)
213 {
214         return (0);
215 }
216
217 /*ARGSUSED*/
218 static void
219 lockstat_provide(void *arg, dtrace_probedesc_t *desc)
220 {
221         int i = 0;
222
223         for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) {
224                 lockstat_probe_t *probe = &lockstat_probes[i];
225
226                 if (dtrace_probe_lookup(lockstat_id, "kernel",
227                     probe->lsp_func, probe->lsp_name) != 0)
228                         continue;
229
230                 ASSERT(!probe->lsp_id);
231 #ifdef __FreeBSD__
232                 probe->lsp_id = dtrace_probe_create(lockstat_id,
233                     "kernel", probe->lsp_func, probe->lsp_name,
234                     probe->lsp_frame, probe);
235 #else
236                 probe->lsp_id = dtrace_probe_create(lockstat_id,
237                     "kernel", probe->lsp_func, probe->lsp_name,
238                     LOCKSTAT_AFRAMES, probe);
239 #endif
240         }
241 }
242
243 /*ARGSUSED*/
244 static void
245 lockstat_destroy(void *arg, dtrace_id_t id, void *parg)
246 {
247         lockstat_probe_t *probe = parg;
248
249         ASSERT(!lockstat_probemap[probe->lsp_probe]);
250         probe->lsp_id = 0;
251 }
252
253 static dtrace_pattr_t lockstat_attr = {
254 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
255 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
256 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
257 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
258 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
259 };
260
261 static dtrace_pops_t lockstat_pops = {
262         lockstat_provide,
263         NULL,
264         lockstat_enable,
265         lockstat_disable,
266         NULL,
267         NULL,
268         NULL,
269         NULL,
270         NULL,
271         lockstat_destroy
272 };
273
274 static void
275 lockstat_load(void *dummy)
276 {
277         /* Create the /dev/dtrace/lockstat entry. */
278         lockstat_cdev = make_dev(&lockstat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
279             "dtrace/lockstat");
280
281         if (dtrace_register("lockstat", &lockstat_attr, DTRACE_PRIV_USER,
282             NULL, &lockstat_pops, NULL, &lockstat_id) != 0)
283                 return;
284 }
285
286 static int
287 lockstat_unload()
288 {
289         int error = 0;
290
291         if ((error = dtrace_unregister(lockstat_id)) != 0)
292             return (error);
293
294         destroy_dev(lockstat_cdev);
295
296         return (error);
297 }
298
299 /* ARGSUSED */
300 static int
301 lockstat_modevent(module_t mod __unused, int type, void *data __unused)
302 {
303         int error = 0;
304
305         switch (type) {
306         case MOD_LOAD:
307                 break;
308
309         case MOD_UNLOAD:
310                 break;
311
312         case MOD_SHUTDOWN:
313                 break;
314
315         default:
316                 error = EOPNOTSUPP;
317                 break;
318         }
319         return (error);
320 }
321
322 SYSINIT(lockstat_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_load, NULL);
323 SYSUNINIT(lockstat_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_unload, NULL);
324
325 DEV_MODULE(lockstat, lockstat_modevent, NULL);
326 MODULE_VERSION(lockstat, 1);
327 MODULE_DEPEND(lockstat, dtrace, 1, 1, 1);
328 MODULE_DEPEND(lockstat, opensolaris, 1, 1, 1);