1/*	$NetBSD: lockstat.h,v 1.9 2008/04/28 20:23:46 martin Exp $	*/
2
3/*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#ifndef _SYS_LOCKSTAT_H_
33#define _SYS_LOCKSTAT_H_
34
35#ifdef _KERNEL_OPT
36#include <lockstat.h>
37#endif
38
39#include <sys/types.h>
40#include <sys/ioccom.h>
41#include <sys/queue.h>
42#include <sys/time.h>
43
44#if defined(_KERNEL) && defined(__HAVE_CPU_COUNTER)
45#include <machine/cpu_counter.h>
46#endif
47
48/*
49 * Interface version.  The interface is not designed to provide
50 * compatibility across NetBSD releases.
51 */
52
53#define	IOC_LOCKSTAT_GVERSION	_IOR('L', 0, int)
54
55#define	LS_VERSION	5
56
57/*
58 * Enable request.  We can limit tracing by the call site and by
59 * the lock.  We also specify the number of event buffers to
60 * allocate up front, and what kind of events to track.
61 */
62
63#define	IOC_LOCKSTAT_ENABLE	_IOW('L', 1, lsenable_t)
64
65#define LE_CALLSITE	0x01		/* track call sites */
66#define	LE_ONE_CALLSITE	0x02		/* specific call site */
67#define	LE_ONE_LOCK	0x04		/* specific lock */
68#define LE_LOCK		0x08		/* track locks */
69
70typedef struct lsenable {
71	uintptr_t	le_csstart;	/* callsite start */
72	uintptr_t	le_csend;	/* callsite end */
73	uintptr_t	le_lockstart;	/* lock address start */
74	uintptr_t	le_lockend;	/* lock address end */
75	uintptr_t	le_nbufs;	/* buffers to allocate, 0 = default */
76	u_int		le_flags;	/* request flags */
77	u_int		le_mask;	/* event mask (LB_*) */
78} lsenable_t;
79
80/*
81 * Disable request.
82 */
83
84#define	IOC_LOCKSTAT_DISABLE	_IOR('L', 2, lsdisable_t)
85
86typedef struct lsdisable {
87	size_t		ld_size;	/* buffer space allocated */
88	struct timespec	ld_time;	/* time spent enabled */
89	uint64_t	ld_freq[64];	/* counter HZ by CPU number */
90} lsdisable_t;
91
92/*
93 * Event buffers returned from reading from the devices.
94 */
95
96/*
97 * Event types, for lockstat_event().  Stored in lb_flags but should be
98 * meaningless to the consumer, also provided with the enable request
99 * in le_mask.
100 */
101#define	LB_SPIN			0x00000001
102#define	LB_SLEEP1		0x00000002
103#define	LB_SLEEP2		0x00000003
104#define	LB_NEVENT		0x00000003
105#define	LB_EVENT_MASK		0x000000ff
106
107/*
108 * Lock types, the only part of lb_flags that should be inspected.  Also
109 * provided with the enable request in le_mask.
110 */
111#define	LB_ADAPTIVE_MUTEX	0x00000100
112#define	LB_SPIN_MUTEX		0x00000200
113#define	LB_RWLOCK		0x00000300
114#define	LB_NOPREEMPT		0x00000400
115#define	LB_KERNEL_LOCK		0x00000500
116#define	LB_MISC			0x00000600
117#define	LB_NLOCK		0x00000600
118#define	LB_LOCK_MASK		0x0000ff00
119#define	LB_LOCK_SHIFT		8
120
121typedef struct lsbuf {
122	union {
123		LIST_ENTRY(lsbuf) list;
124		SLIST_ENTRY(lsbuf) slist;
125		TAILQ_ENTRY(lsbuf) tailq;
126	} lb_chain;
127	uintptr_t	lb_lock;		/* lock address */
128	uintptr_t	lb_callsite;		/* call site */
129	uint64_t	lb_times[LB_NEVENT];	/* cumulative times */
130	uint32_t	lb_counts[LB_NEVENT];	/* count of events */
131	uint16_t	lb_flags;		/* lock type */
132	uint16_t	lb_cpu;			/* CPU number */
133} lsbuf_t;
134
135/*
136 * Tracing stubs used by lock providers.
137 */
138
139#if defined(_KERNEL) && defined(__HAVE_CPU_COUNTER) && NLOCKSTAT > 0
140
141#define	LOCKSTAT_EVENT(flag, lock, type, count, time)			\
142do {									\
143	if (__predict_false(flag))					\
144		lockstat_event((uintptr_t)(lock),			\
145		    (uintptr_t)__builtin_return_address(0),		\
146		    (type), (count), (time));				\
147} while (/* CONSTCOND */ 0);
148
149#define	LOCKSTAT_EVENT_RA(flag, lock, type, count, time, ra)		\
150do {									\
151	if (__predict_false(flag))					\
152		lockstat_event((uintptr_t)(lock), (uintptr_t)ra,	\
153		    (type), (count), (time));				\
154} while (/* CONSTCOND */ 0);
155
156#define	LOCKSTAT_TIMER(name)	uint64_t name = 0
157#define	LOCKSTAT_COUNTER(name)	uint64_t name = 0
158#define	LOCKSTAT_FLAG(name)	int name
159#define	LOCKSTAT_ENTER(name)	name = lockstat_enabled
160#define	LOCKSTAT_EXIT(name)
161
162#define	LOCKSTAT_START_TIMER(flag, name)				\
163do {									\
164	if (__predict_false(flag))					\
165		(name) -= cpu_counter();				\
166} while (/* CONSTCOND */ 0)
167
168#define	LOCKSTAT_STOP_TIMER(flag, name)					\
169do {									\
170	if (__predict_false(flag))					\
171		(name) += cpu_counter();				\
172} while (/* CONSTCOND */ 0)
173
174#define	LOCKSTAT_COUNT(name, inc)					\
175do {									\
176	(name) += (inc);						\
177} while (/* CONSTCOND */ 0)
178
179void	lockstat_event(uintptr_t, uintptr_t, u_int, u_int, uint64_t);
180
181extern volatile u_int	lockstat_enabled;
182
183#else
184
185#define	LOCKSTAT_FLAG(name)					/* nothing */
186#define	LOCKSTAT_ENTER(name)					/* nothing */
187#define	LOCKSTAT_EXIT(name)					/* nothing */
188#define	LOCKSTAT_EVENT(flag, lock, type, count, time)		/* nothing */
189#define	LOCKSTAT_EVENT_RA(flag, lock, type, count, time, ra)	/* nothing */
190#define	LOCKSTAT_TIMER(void)					/* nothing */
191#define	LOCKSTAT_COUNTER(void)					/* nothing */
192#define	LOCKSTAT_START_TIMER(flag, void)			/* nothing */
193#define	LOCKSTAT_STOP_TIMER(flag, void)				/* nothing */
194#define	LOCKSTAT_COUNT(name, int)				/* nothing */
195
196#endif
197
198#endif	/* _SYS_LOCKSTAT_H_ */
199