1 /*
2 * Copyright (c) 2017 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34 #ifndef _SYS_INDEFINITE2_H_
35 #define _SYS_INDEFINITE2_H_
36
37 /*
38 * Indefinite info collection and handling code for contention loops
39 */
40 #ifndef _SYS_INDEFINITE_H_
41 #include <sys/indefinite.h>
42 #endif
43 #ifndef _SYS_GLOBALDATA_H_
44 #include <sys/globaldata.h>
45 #endif
46
47 /*
48 * Initialize the indefinite state (only if the TSC is supported)
49 */
50 static __inline void
indefinite_init(indefinite_info_t * info,void * lock_addr,const char * ident,char now,char type)51 indefinite_init(indefinite_info_t *info, void *lock_addr, const char *ident,
52 char now, char type)
53 {
54 info->lock_addr = lock_addr;
55 info->ident = ident;
56 info->secs = 0;
57 info->count = 0;
58 info->reported = now;
59
60 if (tsc_frequency) {
61 info->type = type;
62 /* info->base = rdtsc(); (see indefinite_check()) */
63 } else {
64 info->type = 0;
65 info->base = 0;
66 }
67 if (now && info->ident) {
68 mycpu->gd_cnt.v_lock_addr = lock_addr;
69 mycpu->gd_cnt.v_lock_name[0] = info->type;
70 strncpy(mycpu->gd_cnt.v_lock_name + 1, info->ident,
71 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
72 }
73 }
74
75 /*
76 * Update the state during any loop, record collision time in microseconds.
77 */
78 static __inline int
indefinite_check(indefinite_info_t * info)79 indefinite_check(indefinite_info_t *info)
80 {
81 tsc_uclock_t delta;
82 const char *str;
83 int doreport;
84
85 #ifdef _KERNEL_VIRTUAL
86 vkernel_yield();
87 #else
88 cpu_pause();
89 #endif
90 if (info->type == 0)
91 return FALSE;
92 if (info->count == INDEF_INFO_START) { /* start recording time */
93 if (indefinite_uses_rdtsc)
94 info->base = rdtsc();
95 else
96 info->base = ticks;
97 if (info->reported == 0 && info->ident) {
98 mycpu->gd_cnt.v_lock_addr = info->lock_addr;
99 mycpu->gd_cnt.v_lock_name[0] = info->type;
100 strncpy(mycpu->gd_cnt.v_lock_name + 1, info->ident,
101 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
102 info->reported = 1;
103 }
104 }
105 if ((++info->count & 127) != 127)
106 return FALSE;
107 info->count = 128;
108 if (indefinite_uses_rdtsc)
109 delta = rdtsc() - info->base;
110 else
111 delta = ticks - info->base;
112
113 #if defined(INVARIANTS)
114 if (lock_test_mode > 0) {
115 --lock_test_mode;
116 print_backtrace(8);
117 }
118 #endif
119
120 /*
121 * Ignore minor one-second interval error accumulation in
122 * favor of ensuring that info->base is fully synchronized.
123 */
124 doreport = 0;
125 if (indefinite_uses_rdtsc) {
126 if (delta >= tsc_frequency) {
127 info->secs += delta / tsc_frequency;
128 info->base += delta;
129 mycpu->gd_cnt.v_lock_colls += 1000000U;
130 doreport = 1;
131 }
132 } else {
133 if (delta >= hz) {
134 info->secs += delta / hz;
135 info->base += delta;
136 mycpu->gd_cnt.v_lock_colls += 1000000U;
137 doreport = 1;
138 }
139 }
140 if (doreport) {
141 switch(info->type) {
142 case 's':
143 str = "spin_lock_sh";
144 break;
145 case 'S':
146 str = "spin_lock_ex";
147 break;
148 case 'm':
149 str = "mutex_sh";
150 break;
151 case 'M':
152 str = "mutex_ex";
153 break;
154 case 'l':
155 str = "lock_sh";
156 break;
157 case 'L':
158 str = "lock_ex";
159 break;
160 case 't':
161 str = "token";
162 break;
163 default:
164 str = "lock(?)";
165 break;
166 }
167 kprintf("%s: %s, indefinite wait (%d secs)!\n",
168 str, info->ident, info->secs);
169 if (panicstr)
170 return TRUE;
171 #if defined(INVARIANTS)
172 if (lock_test_mode) {
173 print_backtrace(-1);
174 return TRUE;
175 }
176 #endif
177 #if defined(INVARIANTS)
178 if (info->secs == 11 &&
179 (info->type == 's' || info->type == 'S')) {
180 print_backtrace(-1);
181 }
182 #endif
183 if (info->secs == 60 &&
184 (info->type == 's' || info->type == 'S')) {
185 panic("%s: %s, indefinite wait!", str, info->ident);
186 }
187
188 }
189 return FALSE;
190 }
191
192 /*
193 * Finalize the state, record collision time in microseconds if
194 * we got past the initial load.
195 */
196 static __inline void
indefinite_done(indefinite_info_t * info)197 indefinite_done(indefinite_info_t *info)
198 {
199 tsc_uclock_t delta;
200 globaldata_t gd;
201
202 if (info->type && info->count > INDEF_INFO_START) {
203 gd = mycpu;
204 if (indefinite_uses_rdtsc) {
205 delta = rdtsc() - info->base;
206 delta = delta * 1000000U / tsc_frequency;
207 gd->gd_cnt.v_lock_colls += delta;
208 } else {
209 delta = ticks - info->base;
210 delta = delta * 1000000U / hz;
211 gd->gd_cnt.v_lock_colls += delta;
212 }
213 }
214 info->type = 0;
215 }
216
217 #endif
218