github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/runtime/runtime.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 import ( 8 "runtime/internal/atomic" 9 "unsafe" 10 ) 11 12 //go:generate go run wincallback.go 13 //go:generate go run mkduff.go 14 //go:generate go run mkfastlog2table.go 15 //go:generate go run mklockrank.go -o lockrank.go 16 17 var ticks ticksType 18 19 type ticksType struct { 20 // lock protects access to start* and val. 21 lock mutex 22 startTicks int64 23 startTime int64 24 val atomic.Int64 25 } 26 27 // init initializes ticks to maximize the chance that we have a good ticksPerSecond reference. 28 // 29 // Must not run concurrently with ticksPerSecond. 30 func (t *ticksType) init() { 31 lock(&ticks.lock) 32 t.startTime = nanotime() 33 t.startTicks = cputicks() 34 unlock(&ticks.lock) 35 } 36 37 // minTimeForTicksPerSecond is the minimum elapsed time we require to consider our ticksPerSecond 38 // measurement to be of decent enough quality for profiling. 39 // 40 // There's a linear relationship here between minimum time and error from the true value. 41 // The error from the true ticks-per-second in a linux/amd64 VM seems to be: 42 // - 1 ms -> ~0.02% error 43 // - 5 ms -> ~0.004% error 44 // - 10 ms -> ~0.002% error 45 // - 50 ms -> ~0.0003% error 46 // - 100 ms -> ~0.0001% error 47 // 48 // We're willing to take 0.004% error here, because ticksPerSecond is intended to be used for 49 // converting durations, not timestamps. Durations are usually going to be much larger, and so 50 // the tiny error doesn't matter. The error is definitely going to be a problem when trying to 51 // use this for timestamps, as it'll make those timestamps much less likely to line up. 52 const minTimeForTicksPerSecond = 5_000_000*(1-osHasLowResClockInt) + 100_000_000*osHasLowResClockInt 53 54 // ticksPerSecond returns a conversion rate between the cputicks clock and the nanotime clock. 55 // 56 // Note: Clocks are hard. Using this as an actual conversion rate for timestamps is ill-advised 57 // and should be avoided when possible. Use only for durations, where a tiny error term isn't going 58 // to make a meaningful difference in even a 1ms duration. If an accurate timestamp is needed, 59 // use nanotime instead. (The entire Windows platform is a broad exception to this rule, where nanotime 60 // produces timestamps on such a coarse granularity that the error from this conversion is actually 61 // preferable.) 62 // 63 // The strategy for computing the conversion rate is to write down nanotime and cputicks as 64 // early in process startup as possible. From then, we just need to wait until we get values 65 // from nanotime that we can use (some platforms have a really coarse system time granularity). 66 // We require some amount of time to pass to ensure that the conversion rate is fairly accurate 67 // in aggregate. But because we compute this rate lazily, there's a pretty good chance a decent 68 // amount of time has passed by the time we get here. 69 // 70 // Must be called from a normal goroutine context (running regular goroutine with a P). 71 // 72 // Called by runtime/pprof in addition to runtime code. 73 // 74 // TODO(mknyszek): This doesn't account for things like CPU frequency scaling. Consider 75 // a more sophisticated and general approach in the future. 76 func ticksPerSecond() int64 { 77 // Get the conversion rate if we've already computed it. 78 r := ticks.val.Load() 79 if r != 0 { 80 return r 81 } 82 83 // Compute the conversion rate. 84 for { 85 lock(&ticks.lock) 86 r = ticks.val.Load() 87 if r != 0 { 88 unlock(&ticks.lock) 89 return r 90 } 91 92 // Grab the current time in both clocks. 93 nowTime := nanotime() 94 nowTicks := cputicks() 95 96 // See if we can use these times. 97 if nowTicks > ticks.startTicks && nowTime-ticks.startTime > minTimeForTicksPerSecond { 98 // Perform the calculation with floats. We don't want to risk overflow. 99 r = int64(float64(nowTicks-ticks.startTicks) * 1e9 / float64(nowTime-ticks.startTime)) 100 if r == 0 { 101 // Zero is both a sentinel value and it would be bad if callers used this as 102 // a divisor. We tried out best, so just make it 1. 103 r++ 104 } 105 ticks.val.Store(r) 106 unlock(&ticks.lock) 107 break 108 } 109 unlock(&ticks.lock) 110 111 // Sleep in one millisecond increments until we have a reliable time. 112 timeSleep(1_000_000) 113 } 114 return r 115 } 116 117 var envs []string 118 var argslice []string 119 120 //go:linkname syscall_runtime_envs syscall.runtime_envs 121 func syscall_runtime_envs() []string { return append([]string{}, envs...) } 122 123 //go:linkname syscall_Getpagesize syscall.Getpagesize 124 func syscall_Getpagesize() int { return int(physPageSize) } 125 126 //go:linkname os_runtime_args os.runtime_args 127 func os_runtime_args() []string { return append([]string{}, argslice...) } 128 129 //go:linkname syscall_Exit syscall.Exit 130 //go:nosplit 131 func syscall_Exit(code int) { 132 exit(int32(code)) 133 } 134 135 var godebugDefault string 136 var godebugUpdate atomic.Pointer[func(string, string)] 137 var godebugEnv atomic.Pointer[string] // set by parsedebugvars 138 var godebugNewIncNonDefault atomic.Pointer[func(string) func()] 139 140 //go:linkname godebug_setUpdate internal/godebug.setUpdate 141 func godebug_setUpdate(update func(string, string)) { 142 p := new(func(string, string)) 143 *p = update 144 godebugUpdate.Store(p) 145 godebugNotify(false) 146 } 147 148 //go:linkname godebug_setNewIncNonDefault internal/godebug.setNewIncNonDefault 149 func godebug_setNewIncNonDefault(newIncNonDefault func(string) func()) { 150 p := new(func(string) func()) 151 *p = newIncNonDefault 152 godebugNewIncNonDefault.Store(p) 153 } 154 155 // A godebugInc provides access to internal/godebug's IncNonDefault function 156 // for a given GODEBUG setting. 157 // Calls before internal/godebug registers itself are dropped on the floor. 158 type godebugInc struct { 159 name string 160 inc atomic.Pointer[func()] 161 } 162 163 func (g *godebugInc) IncNonDefault() { 164 inc := g.inc.Load() 165 if inc == nil { 166 newInc := godebugNewIncNonDefault.Load() 167 if newInc == nil { 168 return 169 } 170 inc = new(func()) 171 *inc = (*newInc)(g.name) 172 if raceenabled { 173 racereleasemerge(unsafe.Pointer(&g.inc)) 174 } 175 if !g.inc.CompareAndSwap(nil, inc) { 176 inc = g.inc.Load() 177 } 178 } 179 if raceenabled { 180 raceacquire(unsafe.Pointer(&g.inc)) 181 } 182 (*inc)() 183 } 184 185 func godebugNotify(envChanged bool) { 186 update := godebugUpdate.Load() 187 var env string 188 if p := godebugEnv.Load(); p != nil { 189 env = *p 190 } 191 if envChanged { 192 reparsedebugvars(env) 193 } 194 if update != nil { 195 (*update)(godebugDefault, env) 196 } 197 } 198 199 //go:linkname syscall_runtimeSetenv syscall.runtimeSetenv 200 func syscall_runtimeSetenv(key, value string) { 201 setenv_c(key, value) 202 if key == "GODEBUG" { 203 p := new(string) 204 *p = value 205 godebugEnv.Store(p) 206 godebugNotify(true) 207 } 208 } 209 210 //go:linkname syscall_runtimeUnsetenv syscall.runtimeUnsetenv 211 func syscall_runtimeUnsetenv(key string) { 212 unsetenv_c(key) 213 if key == "GODEBUG" { 214 godebugEnv.Store(nil) 215 godebugNotify(true) 216 } 217 } 218 219 // writeErrStr writes a string to descriptor 2. 220 // If SetCrashOutput(f) was called, it also writes to f. 221 // 222 //go:nosplit 223 func writeErrStr(s string) { 224 writeErrData(unsafe.StringData(s), int32(len(s))) 225 } 226 227 // writeErrData is the common parts of writeErr{,Str}. 228 // 229 //go:nosplit 230 func writeErrData(data *byte, n int32) { 231 write(2, unsafe.Pointer(data), n) 232 233 // If crashing, print a copy to the SetCrashOutput fd. 234 gp := getg() 235 if gp != nil && gp.m.dying > 0 || 236 gp == nil && panicking.Load() > 0 { 237 if fd := crashFD.Load(); fd != ^uintptr(0) { 238 write(fd, unsafe.Pointer(data), n) 239 } 240 } 241 } 242 243 // crashFD is an optional file descriptor to use for fatal panics, as 244 // set by debug.SetCrashOutput (see #42888). If it is a valid fd (not 245 // all ones), writeErr and related functions write to it in addition 246 // to standard error. 247 // 248 // Initialized to -1 in schedinit. 249 var crashFD atomic.Uintptr 250 251 //go:linkname setCrashFD 252 func setCrashFD(fd uintptr) uintptr { 253 // Don't change the crash FD if a crash is already in progress. 254 // 255 // Unlike the case below, this is not required for correctness, but it 256 // is generally nicer to have all of the crash output go to the same 257 // place rather than getting split across two different FDs. 258 if panicking.Load() > 0 { 259 return ^uintptr(0) 260 } 261 262 old := crashFD.Swap(fd) 263 264 // If we are panicking, don't return the old FD to runtime/debug for 265 // closing. writeErrData may have already read the old FD from crashFD 266 // before the swap and closing it would cause the write to be lost [1]. 267 // The old FD will never be closed, but we are about to crash anyway. 268 // 269 // On the writeErrData thread, panicking.Add(1) happens-before 270 // crashFD.Load() [2]. 271 // 272 // On this thread, swapping old FD for new in crashFD happens-before 273 // panicking.Load() > 0. 274 // 275 // Therefore, if panicking.Load() == 0 here (old FD will be closed), it 276 // is impossible for the writeErrData thread to observe 277 // crashFD.Load() == old FD. 278 // 279 // [1] Or, if really unlucky, another concurrent open could reuse the 280 // FD, sending the write into an unrelated file. 281 // 282 // [2] If gp != nil, it occurs when incrementing gp.m.dying in 283 // startpanic_m. If gp == nil, we read panicking.Load() > 0, so an Add 284 // must have happened-before. 285 if panicking.Load() > 0 { 286 return ^uintptr(0) 287 } 288 return old 289 } 290 291 // auxv is populated on relevant platforms but defined here for all platforms 292 // so x/sys/cpu can assume the getAuxv symbol exists without keeping its list 293 // of auxv-using GOOS build tags in sync. 294 // 295 // It contains an even number of elements, (tag, value) pairs. 296 var auxv []uintptr 297 298 func getAuxv() []uintptr { return auxv } // accessed from x/sys/cpu; see issue 57336