1 /*	$NetBSD: syscall_stats.h,v 1.4 2008/11/12 12:36:28 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by David Laight.
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_SYCALL_STAT_H_
33 #define	_SYS_SYCALL_STAT_H_
34 
35 #ifdef _KERNEL_OPT
36 #include "opt_syscall_stats.h"
37 #endif
38 
39 #ifdef SYSCALL_STATS
40 #include <sys/syscall.h>
41 
42 extern uint64_t syscall_counts[SYS_NSYSENT];
43 extern uint64_t syscall_count_user, syscall_count_system, syscall_count_interrupt;
44 #define	SYSCALL_COUNT(table, code) ((table)[code]++)
45 
46 #if defined(SYSCALL_TIMES) && defined(__HAVE_CPU_COUNTER)
47 
48 #include <machine/cpu_counter.h>
49 extern uint64_t syscall_times[SYS_NSYSENT];
50 
51 #ifdef SYSCALL_TIMES_HASCOUNTER
52 /* Force use of cycle counter - needed for Soekris systems */
53 #define SYSCALL_TIME() (cpu_counter32())
54 #else
55 #define SYSCALL_TIME() (cpu_hascounter() ? cpu_counter32() : 0u)
56 #endif
57 
58 #ifdef SYSCALL_TIMES_PROCTIMES
59 #define SYSCALL_TIME_UPDATE_PROC(l, fld, delta) \
60 	(l)->l_proc->p_##fld##ticks += (delta)
61 #else
62 #define SYSCALL_TIME_UPDATE_PROC(l, fld, delta)
63 #endif
64 
65 /* lwp creation */
66 #define SYSCALL_TIME_LWP_INIT(l) do { \
67     (l)->l_syscall_counter = &syscall_count_system; \
68     SYSCALL_TIME_WAKEUP(l); \
69 } while (0)
70 
71 /* System call entry hook */
72 #define SYSCALL_TIME_SYS_ENTRY(l, table, code) do { \
73 	uint32_t now = SYSCALL_TIME(); \
74 	SYSCALL_TIME_UPDATE_PROC(l, u, elapsed = now - (l)->l_syscall_time); \
75 	(l)->l_syscall_counter = (table) + (code); \
76 	(l)->l_syscall_time = now; \
77 } while (0)
78 
79 /* System call - process sleep */
80 #define SYSCALL_TIME_SLEEP(l) do { \
81 	uint32_t now = SYSCALL_TIME(); \
82 	uint32_t elapsed = now - (l)->l_syscall_time; \
83 	(l)->l_syscall_time = now; \
84 	*(l)->l_syscall_counter += elapsed; \
85 	SYSCALL_TIME_UPDATE_PROC(l, s, elapsed); \
86 } while (0)
87 
88 /* Process wakeup */
89 #define SYSCALL_TIME_WAKEUP(l) \
90 	(l)->l_syscall_time = SYSCALL_TIME()
91 
92 /* System call exit */
93 #define SYSCALL_TIME_SYS_EXIT(l) do { \
94 	uint32_t now = SYSCALL_TIME(); \
95 	uint32_t elapsed = now - (l)->l_syscall_time; \
96 	(l)->l_syscall_time = now; \
97 	*(l)->l_syscall_counter += elapsed; \
98 	(l)->l_syscall_counter = &syscall_count_user; \
99 	SYSCALL_TIME_UPDATE_PROC(l, s, elapsed); \
100 } while (0)
101 
102 #ifdef _notyet
103 /* Interrupt entry hook */
104 #define SYSCALL_TIME_ISR_ENTRY(l, old) do { \
105 	uint32_t now = SYSCALL_TIME(); \
106 	uint32_t elapsed = now - (l)->l_syscall_time; \
107 	(l)->l_syscall_time = now; \
108 	old = (l)->l_syscall_counter; \
109 	if ((l)->l_syscall_counter != &syscall_count_interrupt) \
110 		if ((l)->l_syscall_counter == &syscall_count_user) \
111 			SYSCALL_TIME_UPDATE_PROC(l, u, elapsed); \
112 		else { \
113 			*(l)->l_syscall_counter += elapsed; \
114 			SYSCALL_TIME_UPDATE_PROC(l, s, elapsed); \
115 		} \
116 		(l)->l_syscall_counter = &syscall_count_interrupt; \
117 	} \
118 } while (0)
119 
120 /* Interrupt exit hook */
121 #define SYSCALL_TIME_ISR_EXIT(l, saved) do { \
122 	uint32_t now = SYSCALL_TIME(); \
123 	SYSCALL_TIME_UPDATE_PROC(l, i, now - (l)->l_syscall_time); \
124 	(l)->l_syscall_time = now; \
125 	(l)->l_syscall_counter = saved; \
126 } while (0)
127 #endif
128 
129 #endif
130 #endif
131 
132 #ifndef SYSCALL_TIME_SYS_ENTRY
133 #define SYSCALL_TIME_LWP_INIT(l)
134 #define SYSCALL_TIME_SYS_ENTRY(l,table,code)
135 #define SYSCALL_TIME_SLEEP(l)
136 #define SYSCALL_TIME_WAKEUP(l)
137 #define SYSCALL_TIME_SYS_EXIT(l)
138 #define SYSCALL_TIME_ISR_ENTRY(l,old)
139 #define SYSCALL_TIME_ISR_EXIT(l,saved)
140 #undef SYSCALL_TIMES
141 #endif
142 
143 #ifndef SYSCALL_COUNT
144 #define SYSCALL_COUNT(table, code)
145 #endif
146 
147 #endif /* !_SYS_SYCALL_STAT_H_ */
148