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