Commit | Line | Data |
---|---|---|
d3776285 MD |
1 | /* |
2 | * Copyright (c) 2005 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 | /* | |
35 | * The following copyright applies to the DDB command code: | |
36 | * | |
81540c2d EN |
37 | * Copyright (c) 2000 John Baldwin <jhb@FreeBSD.org> |
38 | * All rights reserved. | |
39 | * | |
40 | * Redistribution and use in source and binary forms, with or without | |
41 | * modification, are permitted provided that the following conditions | |
42 | * are met: | |
43 | * 1. Redistributions of source code must retain the above copyright | |
44 | * notice, this list of conditions and the following disclaimer. | |
45 | * 2. Redistributions in binary form must reproduce the above copyright | |
46 | * notice, this list of conditions and the following disclaimer in the | |
47 | * documentation and/or other materials provided with the distribution. | |
48 | * 3. Neither the name of the author nor the names of any co-contributors | |
49 | * may be used to endorse or promote products derived from this software | |
50 | * without specific prior written permission. | |
51 | * | |
52 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
54 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
55 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
56 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
57 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
58 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
59 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
60 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
61 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
62 | * SUCH DAMAGE. | |
63 | */ | |
6d22945a | 64 | |
81540c2d | 65 | /* |
d3776285 | 66 | * Kernel tracepoint facility. |
81540c2d EN |
67 | */ |
68 | ||
69 | #include "opt_ddb.h" | |
70 | #include "opt_ktr.h" | |
71 | ||
72 | #include <sys/param.h> | |
73 | #include <sys/cons.h> | |
74 | #include <sys/kernel.h> | |
81540c2d EN |
75 | #include <sys/libkern.h> |
76 | #include <sys/proc.h> | |
77 | #include <sys/sysctl.h> | |
d3776285 | 78 | #include <sys/ktr.h> |
81540c2d EN |
79 | #include <sys/systm.h> |
80 | #include <sys/time.h> | |
8e273a1d | 81 | #include <sys/malloc.h> |
c2751817 | 82 | #include <sys/spinlock.h> |
ce7866b8 MD |
83 | #include <sys/kbio.h> |
84 | #include <sys/ctype.h> | |
2fa6678b | 85 | #include <sys/limits.h> |
ce7866b8 | 86 | |
8e273a1d | 87 | #include <sys/thread2.h> |
c2751817 | 88 | #include <sys/spinlock2.h> |
81540c2d EN |
89 | |
90 | #include <machine/cpu.h> | |
91 | #include <machine/cpufunc.h> | |
92 | #include <machine/specialreg.h> | |
93 | #include <machine/md_var.h> | |
94 | ||
95 | #include <ddb/ddb.h> | |
96 | ||
97 | #ifndef KTR_ENTRIES | |
d3776285 | 98 | #define KTR_ENTRIES 2048 |
6d22945a SW |
99 | #elif (KTR_ENTRIES & KTR_ENTRIES - 1) |
100 | #error KTR_ENTRIES must be a power of two | |
81540c2d | 101 | #endif |
d3776285 | 102 | #define KTR_ENTRIES_MASK (KTR_ENTRIES - 1) |
81540c2d | 103 | |
62b18938 SZ |
104 | /* |
105 | * Used by earlier boot; default value consumes ~64K BSS. | |
106 | * | |
107 | * NOTE: | |
108 | * We use a small value here; this prevents kernel or module loading | |
109 | * failure due to excessive BSS usage if KTR_ENTRIES is large. | |
110 | */ | |
111 | #if (KTR_ENTRIES < 256) | |
112 | #define KTR_ENTRIES_BOOT0 KTR_ENTRIES | |
113 | #else | |
114 | #define KTR_ENTRIES_BOOT0 256 | |
115 | #endif | |
116 | #define KTR_ENTRIES_BOOT0_MASK (KTR_ENTRIES_BOOT0 - 1) | |
117 | ||
96328d40 MD |
118 | /* |
119 | * test logging support. When ktr_testlogcnt is non-zero each synchronization | |
0b698dca | 120 | * interrupt will issue six back-to-back ktr logging messages on cpu 0 |
96328d40 MD |
121 | * so the user can determine KTR logging overheads. |
122 | */ | |
123 | #if !defined(KTR_TESTLOG) | |
124 | #define KTR_TESTLOG KTR_ALL | |
125 | #endif | |
126 | KTR_INFO_MASTER(testlog); | |
8cb417fa | 127 | #if KTR_TESTLOG |
2fa6678b SW |
128 | KTR_INFO(KTR_TESTLOG, testlog, charfmt, 0, |
129 | "charfmt %hhd %hhi %#hho %hhu %#hhx %#hhX\n", | |
130 | signed char d1, signed char d2, | |
131 | unsigned char d3, unsigned char d4, | |
132 | unsigned char d5, unsigned char d6); | |
133 | KTR_INFO(KTR_TESTLOG, testlog, shortfmt, 1, | |
134 | "shortfmt %hd %hi %#ho %hu %#hx %#hX\n", | |
135 | short d1, short d2, | |
136 | unsigned short d3, unsigned short d4, | |
137 | unsigned short d5, unsigned short d6); | |
138 | KTR_INFO(KTR_TESTLOG, testlog, longfmt, 2, | |
139 | "longfmt %ld %li %#lo %lu %#lx %#lX\n", | |
140 | long d1, long d2, | |
141 | unsigned long d3, unsigned long d4, | |
142 | unsigned long d5, unsigned long d6); | |
143 | KTR_INFO(KTR_TESTLOG, testlog, longlongfmt, 3, | |
144 | "longlongfmt %lld %lli %#llo %llu %#llx %#llX\n", | |
145 | long long d1, long long d2, | |
146 | unsigned long long d3, unsigned long long d4, | |
147 | unsigned long long d5, unsigned long long d6); | |
148 | KTR_INFO(KTR_TESTLOG, testlog, intmaxfmt, 4, | |
149 | "intmaxfmt %jd %ji %#jo %ju %#jx %#jX\n", | |
150 | intmax_t d1, intmax_t d2, | |
151 | uintmax_t d3, uintmax_t d4, | |
152 | uintmax_t d5, uintmax_t d6); | |
153 | KTR_INFO(KTR_TESTLOG, testlog, ptrdifffmt, 5, | |
154 | "ptrdifffmt %td %ti\n", | |
155 | ptrdiff_t d1, ptrdiff_t d2); | |
156 | KTR_INFO(KTR_TESTLOG, testlog, sizefmt, 6, | |
157 | "sizefmt %zd %zi %#zo %zu %#zx %#zX\n", | |
158 | ssize_t d1, ssize_t d2, | |
159 | size_t d3, size_t d4, | |
160 | size_t d5, size_t d6); | |
ddd22766 SW |
161 | KTR_INFO(KTR_TESTLOG, testlog, pingpong, 17, "pingpong"); |
162 | KTR_INFO(KTR_TESTLOG, testlog, pipeline, 18, "pipeline"); | |
163 | KTR_INFO(KTR_TESTLOG, testlog, crit_beg, 19, "crit_beg"); | |
164 | KTR_INFO(KTR_TESTLOG, testlog, crit_end, 20, "crit_end"); | |
165 | KTR_INFO(KTR_TESTLOG, testlog, spin_beg, 21, "spin_beg"); | |
166 | KTR_INFO(KTR_TESTLOG, testlog, spin_end, 22, "spin_end"); | |
0b698dca | 167 | #define logtest_noargs(name) KTR_LOG(testlog_ ## name) |
8cb417fa | 168 | #endif |
96328d40 | 169 | |
8e273a1d EN |
170 | MALLOC_DEFINE(M_KTR, "ktr", "ktr buffers"); |
171 | ||
d3776285 | 172 | SYSCTL_NODE(_debug, OID_AUTO, ktr, CTLFLAG_RW, 0, "ktr"); |
81540c2d | 173 | |
62b18938 | 174 | static int ktr_entries = KTR_ENTRIES_BOOT0; |
f22af1e9 SW |
175 | SYSCTL_INT(_debug_ktr, OID_AUTO, entries, CTLFLAG_RD, &ktr_entries, 0, |
176 | "Size of the event buffer"); | |
62b18938 | 177 | static int ktr_entries_mask = KTR_ENTRIES_BOOT0_MASK; |
81540c2d | 178 | |
62b18938 | 179 | static int ktr_version = KTR_VERSION; |
81540c2d EN |
180 | SYSCTL_INT(_debug_ktr, OID_AUTO, version, CTLFLAG_RD, &ktr_version, 0, ""); |
181 | ||
af6ff89e MD |
182 | static int ktr_stacktrace = 1; |
183 | SYSCTL_INT(_debug_ktr, OID_AUTO, stacktrace, CTLFLAG_RD, &ktr_stacktrace, 0, ""); | |
184 | ||
374133e3 | 185 | static int ktr_resynchronize = 0; |
f22af1e9 SW |
186 | SYSCTL_INT(_debug_ktr, OID_AUTO, resynchronize, CTLFLAG_RW, |
187 | &ktr_resynchronize, 0, "Resynchronize TSC 10 times a second"); | |
374133e3 | 188 | |
96328d40 MD |
189 | #if KTR_TESTLOG |
190 | static int ktr_testlogcnt = 0; | |
191 | SYSCTL_INT(_debug_ktr, OID_AUTO, testlogcnt, CTLFLAG_RW, &ktr_testlogcnt, 0, ""); | |
72d379df MD |
192 | static int ktr_testipicnt = 0; |
193 | static int ktr_testipicnt_remainder; | |
194 | SYSCTL_INT(_debug_ktr, OID_AUTO, testipicnt, CTLFLAG_RW, &ktr_testipicnt, 0, ""); | |
c2751817 MD |
195 | static int ktr_testcritcnt = 0; |
196 | SYSCTL_INT(_debug_ktr, OID_AUTO, testcritcnt, CTLFLAG_RW, &ktr_testcritcnt, 0, ""); | |
197 | static int ktr_testspincnt = 0; | |
198 | SYSCTL_INT(_debug_ktr, OID_AUTO, testspincnt, CTLFLAG_RW, &ktr_testspincnt, 0, ""); | |
96328d40 MD |
199 | #endif |
200 | ||
d3776285 MD |
201 | /* |
202 | * Give cpu0 a static buffer so the tracepoint facility can be used during | |
203 | * early boot (note however that we still use a critical section, XXX). | |
204 | */ | |
62b18938 | 205 | static struct ktr_entry ktr_buf0[KTR_ENTRIES_BOOT0]; |
ddca1582 | 206 | |
02289741 | 207 | struct ktr_cpu ktr_cpu[MAXCPU] = { |
ddca1582 MD |
208 | { .core.ktr_buf = &ktr_buf0[0] } |
209 | }; | |
210 | ||
374133e3 MD |
211 | static int64_t ktr_sync_tsc; |
212 | struct callout ktr_resync_callout; | |
213 | ||
81540c2d EN |
214 | #ifdef KTR_VERBOSE |
215 | int ktr_verbose = KTR_VERBOSE; | |
216 | TUNABLE_INT("debug.ktr.verbose", &ktr_verbose); | |
f22af1e9 SW |
217 | SYSCTL_INT(_debug_ktr, OID_AUTO, verbose, CTLFLAG_RW, &ktr_verbose, 0, |
218 | "Log events to the console as well"); | |
81540c2d EN |
219 | #endif |
220 | ||
ba39e2e0 MD |
221 | static void ktr_resync_callback(void *dummy __unused); |
222 | ||
c2751817 | 223 | extern int64_t tsc_offsets[]; |
0b698dca | 224 | |
81540c2d EN |
225 | static void |
226 | ktr_sysinit(void *dummy) | |
227 | { | |
ddca1582 | 228 | struct ktr_cpu_core *kcpu; |
8e273a1d EN |
229 | int i; |
230 | ||
62b18938 | 231 | for (i = 0; i < ncpus; ++i) { |
ddca1582 MD |
232 | kcpu = &ktr_cpu[i].core; |
233 | kcpu->ktr_buf = kmalloc(KTR_ENTRIES * sizeof(struct ktr_entry), | |
234 | M_KTR, M_WAITOK | M_ZERO); | |
62b18938 SZ |
235 | if (i == 0) { |
236 | /* Migrate ktrs on CPU0 to the new location */ | |
237 | memcpy(kcpu->ktr_buf, ktr_buf0, sizeof(ktr_buf0)); | |
238 | } | |
8e273a1d | 239 | } |
62b18938 SZ |
240 | cpu_sfence(); |
241 | ktr_entries = KTR_ENTRIES; | |
242 | ktr_entries_mask = KTR_ENTRIES_MASK; | |
243 | ||
bf0ecf68 | 244 | callout_init_mp(&ktr_resync_callout); |
ba39e2e0 | 245 | callout_reset(&ktr_resync_callout, hz / 10, ktr_resync_callback, NULL); |
81540c2d | 246 | } |
ba39e2e0 | 247 | SYSINIT(ktr_sysinit, SI_BOOT2_KLD, SI_ORDER_ANY, ktr_sysinit, NULL); |
374133e3 | 248 | |
374133e3 MD |
249 | /* |
250 | * Try to resynchronize the TSC's for all cpus. This is really, really nasty. | |
251 | * We have to send an IPIQ message to all remote cpus, wait until they | |
252 | * get into their IPIQ processing code loop, then do an even stricter hard | |
253 | * loop to get the cpus as close to synchronized as we can to get the most | |
254 | * accurate reading. | |
255 | * | |
256 | * This callback occurs on cpu0. | |
257 | */ | |
8cb417fa | 258 | #if KTR_TESTLOG |
72d379df | 259 | static void ktr_pingpong_remote(void *dummy); |
c2751817 | 260 | static void ktr_pipeline_remote(void *dummy); |
8cb417fa | 261 | #endif |
374133e3 | 262 | |
1918fc5c | 263 | #ifdef _RDTSC_SUPPORTED_ |
b4c3db6f MD |
264 | |
265 | static void ktr_resync_remote(void *dummy); | |
374133e3 MD |
266 | |
267 | /* | |
268 | * We use a callout callback instead of a systimer because we cannot afford | |
269 | * to preempt anyone to do this, or we might deadlock a spin-lock or | |
270 | * serializer between two cpus. | |
271 | */ | |
272 | static | |
273 | void | |
274 | ktr_resync_callback(void *dummy __unused) | |
275 | { | |
f697b97d | 276 | struct lwkt_cpusync cs; |
ef4b87ee | 277 | #if KTR_TESTLOG |
374133e3 | 278 | int count; |
ef4b87ee | 279 | #endif |
374133e3 MD |
280 | |
281 | KKASSERT(mycpu->gd_cpuid == 0); | |
96328d40 MD |
282 | |
283 | #if KTR_TESTLOG | |
284 | /* | |
285 | * Test logging | |
286 | */ | |
287 | if (ktr_testlogcnt) { | |
288 | --ktr_testlogcnt; | |
289 | cpu_disable_intr(); | |
2fa6678b SW |
290 | KTR_LOG(testlog_charfmt, |
291 | (signed char)UCHAR_MAX, (signed char)UCHAR_MAX, | |
292 | (unsigned char)-1, (unsigned char)-1, | |
293 | (unsigned char)-1, (unsigned char)-1); | |
294 | KTR_LOG(testlog_shortfmt, | |
295 | (short)USHRT_MAX, (short)USHRT_MAX, | |
296 | (unsigned short)-1, (unsigned short)-1, | |
297 | (unsigned short)-1, (unsigned short)-1); | |
298 | KTR_LOG(testlog_longfmt, | |
299 | (long)ULONG_MAX, (long)ULONG_MAX, | |
300 | (unsigned long)-1, (unsigned long)-1, | |
301 | (unsigned long)-1, (unsigned long)-1); | |
302 | KTR_LOG(testlog_longlongfmt, | |
303 | (long long)ULLONG_MAX, (long long)ULLONG_MAX, | |
304 | (unsigned long long)-1, (unsigned long long)-1, | |
305 | (unsigned long long)-1, (unsigned long long)-1); | |
306 | KTR_LOG(testlog_intmaxfmt, | |
307 | (intmax_t)UINTMAX_MAX, (intmax_t)UINTMAX_MAX, | |
308 | (uintmax_t)-1, (uintmax_t)-1, | |
309 | (uintmax_t)-1, (uintmax_t)-1); | |
310 | KTR_LOG(testlog_ptrdifffmt, | |
311 | (ptrdiff_t)PTRDIFF_MAX, (ptrdiff_t)PTRDIFF_MAX); | |
312 | KTR_LOG(testlog_sizefmt, | |
313 | (ssize_t)SIZE_T_MAX, (ssize_t)SIZE_T_MAX, | |
314 | (size_t)-1, (size_t)-1, | |
315 | (size_t)-1, (size_t)-1); | |
96328d40 MD |
316 | cpu_enable_intr(); |
317 | } | |
72d379df MD |
318 | |
319 | /* | |
320 | * Test IPI messaging | |
321 | */ | |
322 | if (ktr_testipicnt && ktr_testipicnt_remainder == 0 && ncpus > 1) { | |
323 | ktr_testipicnt_remainder = ktr_testipicnt; | |
324 | ktr_testipicnt = 0; | |
325 | lwkt_send_ipiq_bycpu(1, ktr_pingpong_remote, NULL); | |
326 | } | |
c2751817 MD |
327 | |
328 | /* | |
329 | * Test critical sections | |
330 | */ | |
331 | if (ktr_testcritcnt) { | |
332 | crit_enter(); | |
333 | crit_exit(); | |
334 | logtest_noargs(crit_beg); | |
335 | for (count = ktr_testcritcnt; count; --count) { | |
336 | crit_enter(); | |
337 | crit_exit(); | |
338 | } | |
339 | logtest_noargs(crit_end); | |
340 | ktr_testcritcnt = 0; | |
341 | } | |
342 | ||
343 | /* | |
344 | * Test spinlock sections | |
345 | */ | |
346 | if (ktr_testspincnt) { | |
347 | struct spinlock spin; | |
348 | ||
ba87a4ab | 349 | spin_init(&spin, "ktrresync"); |
287a8577 AH |
350 | spin_lock(&spin); |
351 | spin_unlock(&spin); | |
c2751817 MD |
352 | logtest_noargs(spin_beg); |
353 | for (count = ktr_testspincnt; count; --count) { | |
287a8577 AH |
354 | spin_lock(&spin); |
355 | spin_unlock(&spin); | |
d666840a MD |
356 | } |
357 | logtest_noargs(spin_end); | |
c2751817 MD |
358 | ktr_testspincnt = 0; |
359 | } | |
96328d40 MD |
360 | #endif |
361 | ||
362 | /* | |
363 | * Resynchronize the TSC | |
364 | */ | |
374133e3 MD |
365 | if (ktr_resynchronize == 0) |
366 | goto done; | |
367 | if ((cpu_feature & CPUID_TSC) == 0) | |
368 | return; | |
0b698dca | 369 | |
374133e3 | 370 | crit_enter(); |
f697b97d MD |
371 | lwkt_cpusync_init(&cs, smp_active_mask, ktr_resync_remote, |
372 | (void *)(intptr_t)mycpu->gd_cpuid); | |
373 | lwkt_cpusync_interlock(&cs); | |
374133e3 | 374 | ktr_sync_tsc = rdtsc(); |
f697b97d | 375 | lwkt_cpusync_deinterlock(&cs); |
374133e3 | 376 | crit_exit(); |
374133e3 MD |
377 | done: |
378 | callout_reset(&ktr_resync_callout, hz / 10, ktr_resync_callback, NULL); | |
379 | } | |
380 | ||
0b698dca | 381 | /* |
f697b97d MD |
382 | * The remote-end of the KTR synchronization protocol runs on all cpus. |
383 | * The one we run on the controlling cpu updates its tsc continuously | |
384 | * until the others have finished syncing (theoretically), but we don't | |
385 | * loop forever. | |
386 | * | |
387 | * This is a bit ad-hoc but we need to avoid livelocking inside an IPI | |
388 | * callback. rdtsc() is a synchronizing instruction (I think). | |
0b698dca | 389 | */ |
374133e3 | 390 | static void |
f697b97d | 391 | ktr_resync_remote(void *arg) |
374133e3 | 392 | { |
f697b97d MD |
393 | globaldata_t gd = mycpu; |
394 | int64_t delta; | |
395 | int i; | |
374133e3 | 396 | |
f697b97d MD |
397 | if (gd->gd_cpuid == (int)(intptr_t)arg) { |
398 | for (i = 0; i < 2000; ++i) | |
399 | ktr_sync_tsc = rdtsc(); | |
400 | } else { | |
401 | delta = rdtsc() - ktr_sync_tsc; | |
402 | if (tsc_offsets[gd->gd_cpuid] == 0) | |
403 | tsc_offsets[gd->gd_cpuid] = delta; | |
404 | tsc_offsets[gd->gd_cpuid] = | |
405 | (tsc_offsets[gd->gd_cpuid] * 7 + delta) / 8; | |
374133e3 | 406 | } |
374133e3 | 407 | } |
81540c2d | 408 | |
8cb417fa MD |
409 | #if KTR_TESTLOG |
410 | ||
72d379df MD |
411 | static |
412 | void | |
413 | ktr_pingpong_remote(void *dummy __unused) | |
414 | { | |
c2751817 MD |
415 | int other_cpu; |
416 | ||
72d379df | 417 | logtest_noargs(pingpong); |
c2751817 | 418 | other_cpu = 1 - mycpu->gd_cpuid; |
72d379df MD |
419 | if (ktr_testipicnt_remainder) { |
420 | --ktr_testipicnt_remainder; | |
c2751817 MD |
421 | lwkt_send_ipiq_bycpu(other_cpu, ktr_pingpong_remote, NULL); |
422 | } else { | |
423 | lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL); | |
424 | lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL); | |
425 | lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL); | |
426 | lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL); | |
427 | lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL); | |
72d379df MD |
428 | } |
429 | } | |
430 | ||
c2751817 MD |
431 | static |
432 | void | |
433 | ktr_pipeline_remote(void *dummy __unused) | |
434 | { | |
435 | logtest_noargs(pipeline); | |
436 | } | |
437 | ||
8cb417fa MD |
438 | #endif |
439 | ||
1918fc5c | 440 | #else /* !_RDTSC_SUPPORTED_ */ |
0b698dca MD |
441 | |
442 | /* | |
443 | * The resync callback for UP doesn't do anything other then run the test | |
444 | * log messages. If test logging is not enabled, don't bother resetting | |
445 | * the callout. | |
446 | */ | |
447 | static | |
448 | void | |
449 | ktr_resync_callback(void *dummy __unused) | |
450 | { | |
451 | #if KTR_TESTLOG | |
452 | /* | |
453 | * Test logging | |
454 | */ | |
455 | if (ktr_testlogcnt) { | |
456 | --ktr_testlogcnt; | |
457 | cpu_disable_intr(); | |
2fa6678b SW |
458 | KTR_LOG(testlog_charfmt, |
459 | (signed char)UCHAR_MAX, (signed char)UCHAR_MAX, | |
460 | (unsigned char)-1, (unsigned char)-1, | |
461 | (unsigned char)-1, (unsigned char)-1); | |
462 | KTR_LOG(testlog_shortfmt, | |
463 | (short)USHRT_MAX, (short)USHRT_MAX, | |
464 | (unsigned short)-1, (unsigned short)-1, | |
465 | (unsigned short)-1, (unsigned short)-1); | |
466 | KTR_LOG(testlog_longfmt, | |
467 | (long)ULONG_MAX, (long)ULONG_MAX, | |
468 | (unsigned long)-1, (unsigned long)-1, | |
469 | (unsigned long)-1, (unsigned long)-1); | |
470 | KTR_LOG(testlog_longlongfmt, | |
471 | (long long)ULLONG_MAX, (long long)ULLONG_MAX, | |
472 | (unsigned long long)-1, (unsigned long long)-1, | |
473 | (unsigned long long)-1, (unsigned long long)-1); | |
474 | KTR_LOG(testlog_intmaxfmt, | |
475 | (intmax_t)UINTMAX_MAX, (intmax_t)UINTMAX_MAX, | |
476 | (uintmax_t)-1, (uintmax_t)-1, | |
477 | (uintmax_t)-1, (uintmax_t)-1); | |
478 | KTR_LOG(testlog_ptrdifffmt, | |
479 | (ptrdiff_t)PTRDIFF_MAX, (ptrdiff_t)PTRDIFF_MAX); | |
480 | KTR_LOG(testlog_sizefmt, | |
481 | (ssize_t)SIZE_T_MAX, (ssize_t)SIZE_T_MAX, | |
482 | (size_t)-1, (size_t)-1, | |
483 | (size_t)-1, (size_t)-1); | |
0b698dca MD |
484 | cpu_enable_intr(); |
485 | } | |
486 | callout_reset(&ktr_resync_callout, hz / 10, ktr_resync_callback, NULL); | |
487 | #endif | |
488 | } | |
489 | ||
374133e3 | 490 | #endif |
81540c2d | 491 | |
0b698dca | 492 | /* |
5bf48697 AE |
493 | * Setup the next empty slot and return it to the caller to store the data |
494 | * directly. | |
0b698dca | 495 | */ |
5bf48697 AE |
496 | struct ktr_entry * |
497 | ktr_begin_write_entry(struct ktr_info *info, const char *file, int line) | |
81540c2d | 498 | { |
ddca1582 | 499 | struct ktr_cpu_core *kcpu; |
81540c2d | 500 | struct ktr_entry *entry; |
d3776285 MD |
501 | int cpu; |
502 | ||
503 | cpu = mycpu->gd_cpuid; | |
ddca1582 | 504 | kcpu = &ktr_cpu[cpu].core; |
ab1b4385 MD |
505 | if (panicstr) /* stop logging during panic */ |
506 | return NULL; | |
507 | if (kcpu->ktr_buf == NULL) /* too early in boot */ | |
5bf48697 | 508 | return NULL; |
b4cb74b5 SW |
509 | |
510 | crit_enter(); | |
62b18938 | 511 | entry = kcpu->ktr_buf + (kcpu->ktr_idx & ktr_entries_mask); |
ddca1582 | 512 | ++kcpu->ktr_idx; |
527fddf7 | 513 | #ifdef _RDTSC_SUPPORTED_ |
b4cb74b5 | 514 | if (cpu_feature & CPUID_TSC) { |
b4cb74b5 | 515 | entry->ktr_timestamp = rdtsc() - tsc_offsets[cpu]; |
527fddf7 MD |
516 | } else |
517 | #endif | |
518 | { | |
b4cb74b5 | 519 | entry->ktr_timestamp = get_approximate_time_t(); |
8e273a1d | 520 | } |
b4cb74b5 SW |
521 | entry->ktr_info = info; |
522 | entry->ktr_file = file; | |
523 | entry->ktr_line = line; | |
524 | crit_exit(); | |
5bf48697 AE |
525 | return entry; |
526 | } | |
527 | ||
528 | int | |
529 | ktr_finish_write_entry(struct ktr_info *info, struct ktr_entry *entry) | |
530 | { | |
b4cb74b5 SW |
531 | if (ktr_stacktrace) |
532 | cpu_ktr_caller(entry); | |
81540c2d | 533 | #ifdef KTR_VERBOSE |
d3776285 | 534 | if (ktr_verbose && info->kf_format) { |
5bf48697 | 535 | kprintf("cpu%d ", mycpu->gd_cpuid); |
81540c2d | 536 | if (ktr_verbose > 1) { |
6ea70f76 | 537 | kprintf("%s.%d\t", entry->ktr_file, entry->ktr_line); |
81540c2d | 538 | } |
5bf48697 | 539 | return !0; |
81540c2d EN |
540 | } |
541 | #endif | |
5bf48697 | 542 | return 0; |
d3776285 MD |
543 | } |
544 | ||
81540c2d EN |
545 | #ifdef DDB |
546 | ||
8e273a1d | 547 | #define NUM_LINES_PER_PAGE 19 |
81540c2d EN |
548 | |
549 | struct tstate { | |
550 | int cur; | |
551 | int first; | |
552 | }; | |
d3776285 | 553 | |
81540c2d | 554 | static int db_ktr_verbose; |
d3776285 | 555 | static int db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx); |
81540c2d EN |
556 | |
557 | DB_SHOW_COMMAND(ktr, db_ktr_all) | |
558 | { | |
ddca1582 | 559 | struct ktr_cpu_core *kcpu; |
8e273a1d EN |
560 | int a_flag = 0; |
561 | int c; | |
81540c2d | 562 | int nl = 0; |
8e273a1d EN |
563 | int i; |
564 | struct tstate tstate[MAXCPU]; | |
565 | int printcpu = -1; | |
566 | ||
567 | for(i = 0; i < ncpus; i++) { | |
ddca1582 | 568 | kcpu = &ktr_cpu[i].core; |
8e273a1d | 569 | tstate[i].first = -1; |
62b18938 | 570 | tstate[i].cur = (kcpu->ktr_idx - 1) & ktr_entries_mask; |
8e273a1d EN |
571 | } |
572 | db_ktr_verbose = 0; | |
573 | while ((c = *(modif++)) != '\0') { | |
574 | if (c == 'v') { | |
575 | db_ktr_verbose = 1; | |
576 | } | |
577 | else if (c == 'a') { | |
578 | a_flag = 1; | |
81540c2d | 579 | } |
8e273a1d EN |
580 | else if (c == 'c') { |
581 | printcpu = 0; | |
582 | while ((c = *(modif++)) != '\0') { | |
583 | if (isdigit(c)) { | |
584 | printcpu *= 10; | |
585 | printcpu += c - '0'; | |
586 | } | |
587 | else { | |
588 | modif++; | |
589 | break; | |
590 | } | |
591 | } | |
592 | modif--; | |
81540c2d EN |
593 | } |
594 | } | |
8e273a1d EN |
595 | if (printcpu > ncpus - 1) { |
596 | db_printf("Invalid cpu number\n"); | |
597 | return; | |
598 | } | |
599 | /* | |
ce7866b8 | 600 | * Loop throug all the buffers and print the content of them, sorted |
8e273a1d EN |
601 | * by the timestamp. |
602 | */ | |
603 | while (1) { | |
604 | int counter; | |
605 | u_int64_t highest_ts; | |
8e273a1d | 606 | struct ktr_entry *kp; |
ce7866b8 MD |
607 | int highest_cpu; |
608 | int c; | |
8e273a1d | 609 | |
ce7866b8 MD |
610 | if (a_flag == 1) { |
611 | c = cncheckc(); | |
612 | if (c != -1 && c != NOKEY) | |
613 | return; | |
614 | } | |
8e273a1d EN |
615 | highest_ts = 0; |
616 | highest_cpu = -1; | |
617 | /* | |
618 | * Find the lowest timestamp | |
619 | */ | |
620 | for (i = 0, counter = 0; i < ncpus; i++) { | |
ddca1582 MD |
621 | kcpu = &ktr_cpu[i].core; |
622 | if (kcpu->ktr_buf == NULL) | |
d3776285 | 623 | continue; |
8e273a1d EN |
624 | if (printcpu != -1 && printcpu != i) |
625 | continue; | |
626 | if (tstate[i].cur == -1) { | |
627 | counter++; | |
628 | if (counter == ncpus) { | |
629 | db_printf("--- End of trace buffer ---\n"); | |
630 | return; | |
631 | } | |
632 | continue; | |
633 | } | |
ddca1582 MD |
634 | if (kcpu->ktr_buf[tstate[i].cur].ktr_timestamp > highest_ts) { |
635 | highest_ts = kcpu->ktr_buf[tstate[i].cur].ktr_timestamp; | |
8e273a1d EN |
636 | highest_cpu = i; |
637 | } | |
638 | } | |
438c526f MD |
639 | if (highest_cpu < 0) { |
640 | db_printf("no KTR data available\n"); | |
641 | break; | |
642 | } | |
8e273a1d | 643 | i = highest_cpu; |
ddca1582 MD |
644 | kcpu = &ktr_cpu[i].core; |
645 | kp = &kcpu->ktr_buf[tstate[i].cur]; | |
8e273a1d EN |
646 | if (tstate[i].first == -1) |
647 | tstate[i].first = tstate[i].cur; | |
648 | if (--tstate[i].cur < 0) | |
62b18938 | 649 | tstate[i].cur = ktr_entries - 1; |
8e273a1d | 650 | if (tstate[i].first == tstate[i].cur) { |
d3776285 | 651 | db_mach_vtrace(i, kp, tstate[i].cur + 1); |
8e273a1d EN |
652 | tstate[i].cur = -1; |
653 | continue; | |
654 | } | |
ddca1582 | 655 | if (kcpu->ktr_buf[tstate[i].cur].ktr_info == NULL) |
8e273a1d EN |
656 | tstate[i].cur = -1; |
657 | if (db_more(&nl) == -1) | |
658 | break; | |
d3776285 | 659 | if (db_mach_vtrace(i, kp, tstate[i].cur + 1) == 0) |
8e273a1d EN |
660 | tstate[i].cur = -1; |
661 | } | |
81540c2d EN |
662 | } |
663 | ||
664 | static int | |
d3776285 | 665 | db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx) |
81540c2d | 666 | { |
d3776285 | 667 | if (kp->ktr_info == NULL) |
8e273a1d | 668 | return(0); |
d3776285 | 669 | db_printf("cpu%d ", cpu); |
8e273a1d | 670 | db_printf("%d: ", idx); |
81540c2d EN |
671 | if (db_ktr_verbose) { |
672 | db_printf("%10.10lld %s.%d\t", (long long)kp->ktr_timestamp, | |
673 | kp->ktr_file, kp->ktr_line); | |
674 | } | |
d3776285 | 675 | db_printf("%s\t", kp->ktr_info->kf_name); |
af6ff89e | 676 | db_printf("from(%p,%p) ", kp->ktr_caller1, kp->ktr_caller2); |
81540c2d EN |
677 | db_printf("\n"); |
678 | ||
8e273a1d | 679 | return(1); |
81540c2d EN |
680 | } |
681 | ||
682 | #endif /* DDB */ |