1// Copyright 2019 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 5package runtime 6 7import ( 8 "unsafe" 9) 10 11// Return the minimum value seen for the zone CPU cap, or 0 if no cap is 12// detected. 13func getcpucap() uint64 { 14 // The resource control block is an opaque object whose size is only 15 // known to libc. In practice, given the contents, it is unlikely to 16 // grow beyond 8KB so we'll use a static buffer of that size here. 17 const rblkmaxsize = 8 * 1024 18 if rctlblk_size() > rblkmaxsize { 19 return 0 20 } 21 22 // The "zone.cpu-cap" resource control, as described in 23 // resource_controls(5), "sets a limit on the amount of CPU time that 24 // can be used by a zone. The unit used is the percentage of a single 25 // CPU that can be used by all user threads in a zone, expressed as an 26 // integer." A C string of the name must be passed to getrctl(2). 27 name := []byte("zone.cpu-cap\x00") 28 29 // To iterate over the list of values for a particular resource 30 // control, we need two blocks: one for the previously read value and 31 // one for the next value. 32 var rblk0 [rblkmaxsize]byte 33 var rblk1 [rblkmaxsize]byte 34 rblk := &rblk0[0] 35 rblkprev := &rblk1[0] 36 37 var flag uint32 = _RCTL_FIRST 38 var capval uint64 = 0 39 40 for { 41 if getrctl(unsafe.Pointer(&name[0]), unsafe.Pointer(rblkprev), unsafe.Pointer(rblk), flag) != 0 { 42 // The end of the sequence is reported as an ENOENT 43 // failure, but determining the CPU cap is not critical 44 // here. We'll treat any failure as if it were the end 45 // of sequence. 46 break 47 } 48 49 lflags := rctlblk_get_local_flags(unsafe.Pointer(rblk)) 50 action := rctlblk_get_local_action(unsafe.Pointer(rblk), 0) 51 if (lflags&_RCTL_LOCAL_MAXIMAL) == 0 && action == _RCTL_LOCAL_DENY { 52 // This is a finite (not maximal) value representing a 53 // cap (deny) action. 54 v := rctlblk_get_value(unsafe.Pointer(rblk)) 55 if capval == 0 || capval > v { 56 capval = v 57 } 58 } 59 60 // Swap the blocks around so that we can fetch the next value 61 t := rblk 62 rblk = rblkprev 63 rblkprev = t 64 flag = _RCTL_NEXT 65 } 66 67 return capval 68} 69 70func getncpu() int32 { 71 n := int32(sysconf(__SC_NPROCESSORS_ONLN)) 72 if n < 1 { 73 return 1 74 } 75 76 if cents := int32(getcpucap()); cents > 0 { 77 // Convert from a percentage of CPUs to a number of CPUs, 78 // rounding up to make use of a fractional CPU 79 // e.g., 336% becomes 4 CPUs 80 ncap := (cents + 99) / 100 81 if ncap < n { 82 return ncap 83 } 84 } 85 86 return n 87} 88 89//extern getrctl 90func getrctl(controlname, oldbuf, newbuf unsafe.Pointer, flags uint32) int32 91 92//extern rctlblk_get_local_action 93func rctlblk_get_local_action(buf, signalp unsafe.Pointer) uint32 94 95//extern rctlblk_get_local_flags 96func rctlblk_get_local_flags(buf unsafe.Pointer) uint32 97 98//extern rctlblk_get_value 99func rctlblk_get_value(buf unsafe.Pointer) uint64 100 101//extern rctlblk_size 102func rclblk_size() uintptr 103