github.com/boomhut/fiber/v2@v2.0.0-20230603160335-b65c856e57d3/internal/gopsutil/cpu/cpu_solaris.go (about) 1 package cpu 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "os/exec" 8 "regexp" 9 "runtime" 10 "sort" 11 "strconv" 12 "strings" 13 ) 14 15 var ClocksPerSec = float64(128) 16 17 func init() { 18 getconf, err := exec.LookPath("getconf") 19 if err != nil { 20 return 21 } 22 out, err := invoke.Command(getconf, "CLK_TCK") 23 // ignore errors 24 if err == nil { 25 i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64) 26 if err == nil { 27 ClocksPerSec = float64(i) 28 } 29 } 30 } 31 32 // sum all values in a float64 map with float64 keys 33 func msum(x map[float64]float64) float64 { 34 total := 0.0 35 for _, y := range x { 36 total += y 37 } 38 return total 39 } 40 41 func Times(percpu bool) ([]TimesStat, error) { 42 return TimesWithContext(context.Background(), percpu) 43 } 44 45 func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { 46 kstatSys, err := exec.LookPath("kstat") 47 if err != nil { 48 return nil, fmt.Errorf("cannot find kstat: %s", err) 49 } 50 cpu := make(map[float64]float64) 51 idle := make(map[float64]float64) 52 user := make(map[float64]float64) 53 kern := make(map[float64]float64) 54 iowt := make(map[float64]float64) 55 //swap := make(map[float64]float64) 56 kstatSysOut, err := invoke.CommandWithContext(ctx, kstatSys, "-p", "cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/") 57 if err != nil { 58 return nil, fmt.Errorf("cannot execute kstat: %s", err) 59 } 60 re := regexp.MustCompile(`[:\s]+`) 61 for _, line := range strings.Split(string(kstatSysOut), "\n") { 62 fields := re.Split(line, -1) 63 if fields[0] != "cpu_stat" { 64 continue 65 } 66 cpuNumber, err := strconv.ParseFloat(fields[1], 64) 67 if err != nil { 68 return nil, fmt.Errorf("cannot parse cpu number: %s", err) 69 } 70 cpu[cpuNumber] = cpuNumber 71 switch fields[3] { 72 case "idle": 73 idle[cpuNumber], err = strconv.ParseFloat(fields[4], 64) 74 if err != nil { 75 return nil, fmt.Errorf("cannot parse idle: %s", err) 76 } 77 case "user": 78 user[cpuNumber], err = strconv.ParseFloat(fields[4], 64) 79 if err != nil { 80 return nil, fmt.Errorf("cannot parse user: %s", err) 81 } 82 case "kernel": 83 kern[cpuNumber], err = strconv.ParseFloat(fields[4], 64) 84 if err != nil { 85 return nil, fmt.Errorf("cannot parse kernel: %s", err) 86 } 87 case "iowait": 88 iowt[cpuNumber], err = strconv.ParseFloat(fields[4], 64) 89 if err != nil { 90 return nil, fmt.Errorf("cannot parse iowait: %s", err) 91 } 92 //not sure how this translates, don't report, add to kernel, something else? 93 /*case "swap": 94 swap[cpuNumber], err = strconv.ParseFloat(fields[4], 64) 95 if err != nil { 96 return nil, fmt.Errorf("cannot parse swap: %s", err) 97 } */ 98 } 99 } 100 ret := make([]TimesStat, 0, len(cpu)) 101 if percpu { 102 for _, c := range cpu { 103 ct := &TimesStat{ 104 CPU: fmt.Sprintf("cpu%d", int(cpu[c])), 105 Idle: idle[c] / ClocksPerSec, 106 User: user[c] / ClocksPerSec, 107 System: kern[c] / ClocksPerSec, 108 Iowait: iowt[c] / ClocksPerSec, 109 } 110 ret = append(ret, *ct) 111 } 112 } else { 113 ct := &TimesStat{ 114 CPU: "cpu-total", 115 Idle: msum(idle) / ClocksPerSec, 116 User: msum(user) / ClocksPerSec, 117 System: msum(kern) / ClocksPerSec, 118 Iowait: msum(iowt) / ClocksPerSec, 119 } 120 ret = append(ret, *ct) 121 } 122 return ret, nil 123 } 124 125 func Info() ([]InfoStat, error) { 126 return InfoWithContext(context.Background()) 127 } 128 129 func InfoWithContext(ctx context.Context) ([]InfoStat, error) { 130 psrInfo, err := exec.LookPath("psrinfo") 131 if err != nil { 132 return nil, fmt.Errorf("cannot find psrinfo: %s", err) 133 } 134 psrInfoOut, err := invoke.CommandWithContext(ctx, psrInfo, "-p", "-v") 135 if err != nil { 136 return nil, fmt.Errorf("cannot execute psrinfo: %s", err) 137 } 138 139 isaInfo, err := exec.LookPath("isainfo") 140 if err != nil { 141 return nil, fmt.Errorf("cannot find isainfo: %s", err) 142 } 143 isaInfoOut, err := invoke.CommandWithContext(ctx, isaInfo, "-b", "-v") 144 if err != nil { 145 return nil, fmt.Errorf("cannot execute isainfo: %s", err) 146 } 147 148 procs, err := parseProcessorInfo(string(psrInfoOut)) 149 if err != nil { 150 return nil, fmt.Errorf("error parsing psrinfo output: %s", err) 151 } 152 153 flags, err := parseISAInfo(string(isaInfoOut)) 154 if err != nil { 155 return nil, fmt.Errorf("error parsing isainfo output: %s", err) 156 } 157 158 result := make([]InfoStat, 0, len(flags)) 159 for _, proc := range procs { 160 procWithFlags := proc 161 procWithFlags.Flags = flags 162 result = append(result, procWithFlags) 163 } 164 165 return result, nil 166 } 167 168 var flagsMatch = regexp.MustCompile(`[\w\.]+`) 169 170 func parseISAInfo(cmdOutput string) ([]string, error) { 171 words := flagsMatch.FindAllString(cmdOutput, -1) 172 173 // Sanity check the output 174 if len(words) < 4 || words[1] != "bit" || words[3] != "applications" { 175 return nil, errors.New("attempted to parse invalid isainfo output") 176 } 177 178 flags := make([]string, len(words)-4) 179 for i, val := range words[4:] { 180 flags[i] = val 181 } 182 sort.Strings(flags) 183 184 return flags, nil 185 } 186 187 var psrInfoMatch = regexp.MustCompile(`The physical processor has (?:([\d]+) virtual processor \(([\d]+)\)|([\d]+) cores and ([\d]+) virtual processors[^\n]+)\n(?:\s+ The core has.+\n)*\s+.+ \((\w+) ([\S]+) family (.+) model (.+) step (.+) clock (.+) MHz\)\n[\s]*(.*)`) 188 189 const ( 190 psrNumCoresOffset = 1 191 psrNumCoresHTOffset = 3 192 psrNumHTOffset = 4 193 psrVendorIDOffset = 5 194 psrFamilyOffset = 7 195 psrModelOffset = 8 196 psrStepOffset = 9 197 psrClockOffset = 10 198 psrModelNameOffset = 11 199 ) 200 201 func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) { 202 matches := psrInfoMatch.FindAllStringSubmatch(cmdOutput, -1) 203 204 var infoStatCount int32 205 result := make([]InfoStat, 0, len(matches)) 206 for physicalIndex, physicalCPU := range matches { 207 var step int32 208 var clock float64 209 210 if physicalCPU[psrStepOffset] != "" { 211 stepParsed, err := strconv.ParseInt(physicalCPU[psrStepOffset], 10, 32) 212 if err != nil { 213 return nil, fmt.Errorf("cannot parse value %q for step as 32-bit integer: %s", physicalCPU[9], err) 214 } 215 step = int32(stepParsed) 216 } 217 218 if physicalCPU[psrClockOffset] != "" { 219 clockParsed, err := strconv.ParseInt(physicalCPU[psrClockOffset], 10, 64) 220 if err != nil { 221 return nil, fmt.Errorf("cannot parse value %q for clock as 32-bit integer: %s", physicalCPU[10], err) 222 } 223 clock = float64(clockParsed) 224 } 225 226 var err error 227 var numCores int64 228 var numHT int64 229 switch { 230 case physicalCPU[psrNumCoresOffset] != "": 231 numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresOffset], 10, 32) 232 if err != nil { 233 return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[1], err) 234 } 235 236 for i := 0; i < int(numCores); i++ { 237 result = append(result, InfoStat{ 238 CPU: infoStatCount, 239 PhysicalID: strconv.Itoa(physicalIndex), 240 CoreID: strconv.Itoa(i), 241 Cores: 1, 242 VendorID: physicalCPU[psrVendorIDOffset], 243 ModelName: physicalCPU[psrModelNameOffset], 244 Family: physicalCPU[psrFamilyOffset], 245 Model: physicalCPU[psrModelOffset], 246 Stepping: step, 247 Mhz: clock, 248 }) 249 infoStatCount++ 250 } 251 case physicalCPU[psrNumCoresHTOffset] != "": 252 numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresHTOffset], 10, 32) 253 if err != nil { 254 return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[3], err) 255 } 256 257 numHT, err = strconv.ParseInt(physicalCPU[psrNumHTOffset], 10, 32) 258 if err != nil { 259 return nil, fmt.Errorf("cannot parse value %q for hyperthread count as 32-bit integer: %s", physicalCPU[4], err) 260 } 261 262 for i := 0; i < int(numCores); i++ { 263 result = append(result, InfoStat{ 264 CPU: infoStatCount, 265 PhysicalID: strconv.Itoa(physicalIndex), 266 CoreID: strconv.Itoa(i), 267 Cores: int32(numHT) / int32(numCores), 268 VendorID: physicalCPU[psrVendorIDOffset], 269 ModelName: physicalCPU[psrModelNameOffset], 270 Family: physicalCPU[psrFamilyOffset], 271 Model: physicalCPU[psrModelOffset], 272 Stepping: step, 273 Mhz: clock, 274 }) 275 infoStatCount++ 276 } 277 default: 278 return nil, errors.New("values for cores with and without hyperthreading are both set") 279 } 280 } 281 return result, nil 282 } 283 284 func CountsWithContext(ctx context.Context, logical bool) (int, error) { 285 return runtime.NumCPU(), nil 286 }