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