Source file src/runtime/runtime.go

     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  //
   221  //go:nosplit
   222  func writeErrStr(s string) {
   223  	write(2, unsafe.Pointer(unsafe.StringData(s)), int32(len(s)))
   224  }
   225  
   226  // auxv is populated on relevant platforms but defined here for all platforms
   227  // so x/sys/cpu can assume the getAuxv symbol exists without keeping its list
   228  // of auxv-using GOOS build tags in sync.
   229  //
   230  // It contains an even number of elements, (tag, value) pairs.
   231  var auxv []uintptr
   232  
   233  func getAuxv() []uintptr { return auxv } // accessed from x/sys/cpu; see issue 57336
   234  

View as plain text