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 51 indefinite_init(indefinite_info_t *info, const char *ident, char now, char type) 52 { 53 info->ident = ident; 54 info->secs = 0; 55 info->count = 0; 56 info->reported = now; 57 58 if (tsc_frequency) { 59 info->type = type; 60 /* info->base = rdtsc(); (see indefinite_check()) */ 61 } else { 62 info->type = 0; 63 info->base = 0; 64 } 65 if (now && info->ident) { 66 mycpu->gd_cnt.v_lock_name[0] = info->type; 67 strncpy(mycpu->gd_cnt.v_lock_name + 1, info->ident, 68 sizeof(mycpu->gd_cnt.v_lock_name) - 2); 69 } 70 } 71 72 /* 73 * Update the state during any loop, record collision time in microseconds. 74 */ 75 static __inline int 76 indefinite_check(indefinite_info_t *info) 77 { 78 tsc_uclock_t delta; 79 const char *str; 80 int doreport; 81 82 #ifdef _KERNEL_VIRTUAL 83 vkernel_yield(); 84 #else 85 cpu_pause(); 86 #endif 87 if (info->type == 0) 88 return FALSE; 89 if (info->count == INDEF_INFO_START) { /* start recording time */ 90 if (indefinite_uses_rdtsc) 91 info->base = rdtsc(); 92 else 93 info->base = ticks; 94 if (info->reported == 0 && info->ident) { 95 mycpu->gd_cnt.v_lock_name[0] = info->type; 96 strncpy(mycpu->gd_cnt.v_lock_name + 1, info->ident, 97 sizeof(mycpu->gd_cnt.v_lock_name) - 2); 98 info->reported = 1; 99 } 100 } 101 if ((++info->count & 127) != 127) 102 return FALSE; 103 info->count = 128; 104 if (indefinite_uses_rdtsc) 105 delta = rdtsc() - info->base; 106 else 107 delta = ticks - info->base; 108 109 #if defined(INVARIANTS) 110 if (lock_test_mode > 0) { 111 --lock_test_mode; 112 print_backtrace(8); 113 } 114 #endif 115 116 /* 117 * Ignore minor one-second interval error accumulation in 118 * favor of ensuring that info->base is fully synchronized. 119 */ 120 doreport = 0; 121 if (indefinite_uses_rdtsc) { 122 if (delta >= tsc_frequency) { 123 info->secs += delta / tsc_frequency; 124 info->base += delta; 125 mycpu->gd_cnt.v_lock_colls += 1000000U; 126 doreport = 1; 127 } 128 } else { 129 if (delta >= hz) { 130 info->secs += delta / hz; 131 info->base += delta; 132 mycpu->gd_cnt.v_lock_colls += 1000000U; 133 doreport = 1; 134 } 135 } 136 if (doreport) { 137 switch(info->type) { 138 case 's': 139 str = "spin_lock_sh"; 140 break; 141 case 'S': 142 str = "spin_lock_ex"; 143 break; 144 case 'm': 145 str = "mutex_sh"; 146 break; 147 case 'M': 148 str = "mutex_ex"; 149 break; 150 case 'l': 151 str = "lock_sh"; 152 break; 153 case 'L': 154 str = "lock_ex"; 155 break; 156 case 't': 157 str = "token"; 158 break; 159 default: 160 str = "lock(?)"; 161 break; 162 } 163 kprintf("%s: %s, indefinite wait (%d secs)!\n", 164 str, info->ident, info->secs); 165 if (panicstr) 166 return TRUE; 167 #if defined(INVARIANTS) 168 if (lock_test_mode) { 169 print_backtrace(-1); 170 return TRUE; 171 } 172 #endif 173 #if defined(INVARIANTS) 174 if (info->secs == 11 && 175 (info->type == 's' || info->type == 'S')) { 176 print_backtrace(-1); 177 } 178 #endif 179 if (info->secs == 60 && 180 (info->type == 's' || info->type == 'S')) { 181 panic("%s: %s, indefinite wait!", str, info->ident); 182 } 183 184 } 185 return FALSE; 186 } 187 188 /* 189 * Finalize the state, record collision time in microseconds if 190 * we got past the initial load. 191 */ 192 static __inline void 193 indefinite_done(indefinite_info_t *info) 194 { 195 tsc_uclock_t delta; 196 globaldata_t gd; 197 198 if (info->type && info->count > INDEF_INFO_START) { 199 gd = mycpu; 200 if (indefinite_uses_rdtsc) { 201 delta = rdtsc() - info->base; 202 delta = delta * 1000000U / tsc_frequency; 203 gd->gd_cnt.v_lock_colls += delta; 204 } else { 205 delta = ticks - info->base; 206 delta = delta * 1000000U / hz; 207 gd->gd_cnt.v_lock_colls += delta; 208 } 209 } 210 info->type = 0; 211 } 212 213 #endif 214