...

Source file src/github.com/shirou/gopsutil/cpu/cpu_solaris.go

Documentation: github.com/shirou/gopsutil/cpu

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

View as plain text