github.com/boomhut/fiber/v2@v2.0.0-20230603160335-b65c856e57d3/internal/gopsutil/cpu/cpu_dragonfly.go (about) 1 package cpu 2 3 import ( 4 "context" 5 "fmt" 6 "os/exec" 7 "reflect" 8 "regexp" 9 "runtime" 10 "strconv" 11 "strings" 12 "unsafe" 13 14 "github.com/boomhut/fiber/v2/internal/gopsutil/common" 15 "golang.org/x/sys/unix" 16 ) 17 18 var ClocksPerSec = float64(128) 19 var cpuMatch = regexp.MustCompile(`^CPU:`) 20 var originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`) 21 var featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`) 22 var featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) 23 var cpuEnd = regexp.MustCompile(`^Trying to mount root`) 24 var cpuTimesSize int 25 var emptyTimes cpuTimes 26 27 func init() { 28 getconf, err := exec.LookPath("getconf") 29 if err != nil { 30 return 31 } 32 out, err := invoke.Command(getconf, "CLK_TCK") 33 // ignore errors 34 if err == nil { 35 i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64) 36 if err == nil { 37 ClocksPerSec = float64(i) 38 } 39 } 40 } 41 42 func timeStat(name string, t *cpuTimes) *TimesStat { 43 return &TimesStat{ 44 User: float64(t.User) / ClocksPerSec, 45 Nice: float64(t.Nice) / ClocksPerSec, 46 System: float64(t.Sys) / ClocksPerSec, 47 Idle: float64(t.Idle) / ClocksPerSec, 48 Irq: float64(t.Intr) / ClocksPerSec, 49 CPU: name, 50 } 51 } 52 53 func Times(percpu bool) ([]TimesStat, error) { 54 return TimesWithContext(context.Background(), percpu) 55 } 56 57 func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { 58 if percpu { 59 buf, err := unix.SysctlRaw("kern.cp_times") 60 if err != nil { 61 return nil, err 62 } 63 64 // We can't do this in init due to the conflict with cpu.init() 65 if cpuTimesSize == 0 { 66 cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size()) 67 } 68 69 ncpus := len(buf) / cpuTimesSize 70 ret := make([]TimesStat, 0, ncpus) 71 for i := 0; i < ncpus; i++ { 72 times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize])) 73 if *times == emptyTimes { 74 // CPU not present 75 continue 76 } 77 ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times)) 78 } 79 return ret, nil 80 } 81 82 buf, err := unix.SysctlRaw("kern.cp_time") 83 if err != nil { 84 return nil, err 85 } 86 87 times := (*cpuTimes)(unsafe.Pointer(&buf[0])) 88 return []TimesStat{*timeStat("cpu-total", times)}, nil 89 } 90 91 // Returns only one InfoStat on DragonflyBSD. The information regarding core 92 // count, however is accurate and it is assumed that all InfoStat attributes 93 // are the same across CPUs. 94 func Info() ([]InfoStat, error) { 95 return InfoWithContext(context.Background()) 96 } 97 98 func InfoWithContext(ctx context.Context) ([]InfoStat, error) { 99 const dmesgBoot = "/var/run/dmesg.boot" 100 101 c, err := parseDmesgBoot(dmesgBoot) 102 if err != nil { 103 return nil, err 104 } 105 106 var u32 uint32 107 if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil { 108 return nil, err 109 } 110 c.Mhz = float64(u32) 111 112 var num int 113 var buf string 114 if buf, err = unix.Sysctl("hw.cpu_topology.tree"); err != nil { 115 return nil, err 116 } 117 num = strings.Count(buf, "CHIP") 118 c.Cores = int32(strings.Count(string(buf), "CORE") / num) 119 120 if c.ModelName, err = unix.Sysctl("hw.model"); err != nil { 121 return nil, err 122 } 123 124 ret := make([]InfoStat, num) 125 for i := 0; i < num; i++ { 126 ret[i] = c 127 } 128 129 return ret, nil 130 } 131 132 func parseDmesgBoot(fileName string) (InfoStat, error) { 133 c := InfoStat{} 134 lines, _ := common.ReadLines(fileName) 135 for _, line := range lines { 136 if matches := cpuEnd.FindStringSubmatch(line); matches != nil { 137 break 138 } else if matches := originMatch.FindStringSubmatch(line); matches != nil { 139 c.VendorID = matches[1] 140 t, err := strconv.ParseInt(matches[2], 10, 32) 141 if err != nil { 142 return c, fmt.Errorf("unable to parse DragonflyBSD CPU stepping information from %q: %v", line, err) 143 } 144 c.Stepping = int32(t) 145 } else if matches := featuresMatch.FindStringSubmatch(line); matches != nil { 146 for _, v := range strings.Split(matches[1], ",") { 147 c.Flags = append(c.Flags, strings.ToLower(v)) 148 } 149 } else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil { 150 for _, v := range strings.Split(matches[1], ",") { 151 c.Flags = append(c.Flags, strings.ToLower(v)) 152 } 153 } 154 } 155 156 return c, nil 157 } 158 159 func CountsWithContext(ctx context.Context, logical bool) (int, error) { 160 return runtime.NumCPU(), nil 161 }