mirror of https://github.com/shirou/gopsutil
Merge pull request #328 from jen20/solaris-cpu
cpu: Implement Solaris support for Info()pull/330/head
commit
d4c8874c19
@ -0,0 +1,189 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
var ClocksPerSec = float64(128)
|
||||
|
||||
func init() {
|
||||
getconf, err := exec.LookPath("/usr/bin/getconf")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
out, err := invoke.Command(getconf, "CLK_TCK")
|
||||
// ignore errors
|
||||
if err == nil {
|
||||
i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
|
||||
if err == nil {
|
||||
ClocksPerSec = float64(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
return []TimesStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Info() ([]InfoStat, error) {
|
||||
psrInfo, err := exec.LookPath("/usr/sbin/psrinfo")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot find psrinfo: %s", err)
|
||||
}
|
||||
psrInfoOut, err := invoke.Command(psrInfo, "-p", "-v")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot execute psrinfo: %s", err)
|
||||
}
|
||||
|
||||
isaInfo, err := exec.LookPath("/usr/bin/isainfo")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot find isainfo: %s", err)
|
||||
}
|
||||
isaInfoOut, err := invoke.Command(isaInfo, "-b", "-v")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot execute isainfo: %s", err)
|
||||
}
|
||||
|
||||
procs, err := parseProcessorInfo(string(psrInfoOut))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing psrinfo output: %s", err)
|
||||
}
|
||||
|
||||
flags, err := parseISAInfo(string(isaInfoOut))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing isainfo output: %s", err)
|
||||
}
|
||||
|
||||
result := make([]InfoStat, 0, len(flags))
|
||||
for _, proc := range procs {
|
||||
procWithFlags := proc
|
||||
procWithFlags.Flags = flags
|
||||
result = append(result, procWithFlags)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
var flagsMatch = regexp.MustCompile(`[\w\.]+`)
|
||||
|
||||
func parseISAInfo(cmdOutput string) ([]string, error) {
|
||||
words := flagsMatch.FindAllString(cmdOutput, -1)
|
||||
|
||||
// Sanity check the output
|
||||
if len(words) < 4 || words[1] != "bit" || words[3] != "applications" {
|
||||
return nil, errors.New("Attempted to parse invalid isainfo output")
|
||||
}
|
||||
|
||||
flags := make([]string, len(words)-4)
|
||||
for i, val := range words[4:] {
|
||||
flags[i] = val
|
||||
}
|
||||
sort.Strings(flags)
|
||||
|
||||
return flags, nil
|
||||
}
|
||||
|
||||
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]*(.*)`)
|
||||
|
||||
const (
|
||||
psrNumCoresOffset = 1
|
||||
psrNumCoresHTOffset = 3
|
||||
psrNumHTOffset = 4
|
||||
psrVendorIDOffset = 5
|
||||
psrFamilyOffset = 7
|
||||
psrModelOffset = 8
|
||||
psrStepOffset = 9
|
||||
psrClockOffset = 10
|
||||
psrModelNameOffset = 11
|
||||
)
|
||||
|
||||
func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
|
||||
matches := psrInfoMatch.FindAllStringSubmatch(cmdOutput, -1)
|
||||
|
||||
var infoStatCount int32
|
||||
result := make([]InfoStat, 0, len(matches))
|
||||
for physicalIndex, physicalCPU := range matches {
|
||||
var step int32
|
||||
var clock float64
|
||||
|
||||
if physicalCPU[psrStepOffset] != "" {
|
||||
stepParsed, err := strconv.ParseInt(physicalCPU[psrStepOffset], 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse value %q for step as 32-bit integer: %s", physicalCPU[9], err)
|
||||
}
|
||||
step = int32(stepParsed)
|
||||
}
|
||||
|
||||
if physicalCPU[psrClockOffset] != "" {
|
||||
clockParsed, err := strconv.ParseInt(physicalCPU[psrClockOffset], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse value %q for clock as 32-bit integer: %s", physicalCPU[10], err)
|
||||
}
|
||||
clock = float64(clockParsed)
|
||||
}
|
||||
|
||||
var err error
|
||||
var numCores int64
|
||||
var numHT int64
|
||||
switch {
|
||||
case physicalCPU[psrNumCoresOffset] != "":
|
||||
numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresOffset], 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[1], err)
|
||||
}
|
||||
|
||||
for i := 0; i < int(numCores); i++ {
|
||||
result = append(result, InfoStat{
|
||||
CPU: infoStatCount,
|
||||
PhysicalID: strconv.Itoa(physicalIndex),
|
||||
CoreID: strconv.Itoa(i),
|
||||
Cores: 1,
|
||||
VendorID: physicalCPU[psrVendorIDOffset],
|
||||
ModelName: physicalCPU[psrModelNameOffset],
|
||||
Family: physicalCPU[psrFamilyOffset],
|
||||
Model: physicalCPU[psrModelOffset],
|
||||
Stepping: step,
|
||||
Mhz: clock,
|
||||
})
|
||||
infoStatCount++
|
||||
}
|
||||
case physicalCPU[psrNumCoresHTOffset] != "":
|
||||
numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresHTOffset], 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[3], err)
|
||||
}
|
||||
|
||||
numHT, err = strconv.ParseInt(physicalCPU[psrNumHTOffset], 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse value %q for hyperthread count as 32-bit integer: %s", physicalCPU[4], err)
|
||||
}
|
||||
|
||||
for i := 0; i < int(numCores); i++ {
|
||||
result = append(result, InfoStat{
|
||||
CPU: infoStatCount,
|
||||
PhysicalID: strconv.Itoa(physicalIndex),
|
||||
CoreID: strconv.Itoa(i),
|
||||
Cores: int32(numHT) / int32(numCores),
|
||||
VendorID: physicalCPU[psrVendorIDOffset],
|
||||
ModelName: physicalCPU[psrModelNameOffset],
|
||||
Family: physicalCPU[psrFamilyOffset],
|
||||
Model: physicalCPU[psrModelOffset],
|
||||
Stepping: step,
|
||||
Mhz: clock,
|
||||
})
|
||||
infoStatCount++
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("Values for cores with and without hyperthreading are both set")
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseISAInfo(t *testing.T) {
|
||||
cases := []struct {
|
||||
filename string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
"1cpu_1core_isainfo.txt",
|
||||
[]string{"rdseed", "adx", "avx2", "fma", "bmi2", "bmi1", "rdrand", "f16c", "vmx",
|
||||
"avx", "xsave", "pclmulqdq", "aes", "movbe", "sse4.2", "sse4.1", "ssse3", "popcnt",
|
||||
"tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8",
|
||||
"tsc", "fpu"},
|
||||
},
|
||||
{
|
||||
"2cpu_1core_isainfo.txt",
|
||||
[]string{"rdseed", "adx", "avx2", "fma", "bmi2", "bmi1", "rdrand", "f16c", "vmx",
|
||||
"avx", "xsave", "pclmulqdq", "aes", "movbe", "sse4.2", "sse4.1", "ssse3", "popcnt",
|
||||
"tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8",
|
||||
"tsc", "fpu"},
|
||||
},
|
||||
{
|
||||
"2cpu_8core_isainfo.txt",
|
||||
[]string{"vmx", "avx", "xsave", "pclmulqdq", "aes", "sse4.2", "sse4.1", "ssse3", "popcnt",
|
||||
"tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8",
|
||||
"tsc", "fpu"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
content, err := ioutil.ReadFile(filepath.Join("expected", "solaris", tc.filename))
|
||||
if err != nil {
|
||||
t.Errorf("cannot read test case: %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(tc.expected)
|
||||
|
||||
flags, err := parseISAInfo(string(content))
|
||||
if err != nil {
|
||||
t.Fatalf("parseISAInfo: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tc.expected, flags) {
|
||||
t.Fatalf("Bad flags\nExpected: %v\n Actual: %v", tc.expected, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseProcessorInfo(t *testing.T) {
|
||||
cases := []struct {
|
||||
filename string
|
||||
expected []InfoStat
|
||||
}{
|
||||
{
|
||||
"1cpu_1core_psrinfo.txt",
|
||||
[]InfoStat{
|
||||
{CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "0", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312},
|
||||
},
|
||||
},
|
||||
{
|
||||
"2cpu_1core_psrinfo.txt",
|
||||
[]InfoStat{
|
||||
{CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "0", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312},
|
||||
{CPU: 1, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "1", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312},
|
||||
},
|
||||
},
|
||||
{
|
||||
"2cpu_8core_psrinfo.txt",
|
||||
[]InfoStat{
|
||||
{CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "0", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 1, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "1", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 2, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "2", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 3, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "3", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 4, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "4", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 5, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "5", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 6, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "6", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 7, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "7", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 8, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "0", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 9, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "1", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 10, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "2", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 11, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "3", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 12, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "4", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 13, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "5", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 14, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "6", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 15, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "7", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
content, err := ioutil.ReadFile(filepath.Join("expected", "solaris", tc.filename))
|
||||
if err != nil {
|
||||
t.Errorf("cannot read test case: %s", err)
|
||||
}
|
||||
|
||||
cpus, err := parseProcessorInfo(string(content))
|
||||
|
||||
if !reflect.DeepEqual(tc.expected, cpus) {
|
||||
t.Fatalf("Bad Processor Info\nExpected: %v\n Actual: %v", tc.expected, cpus)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
64-bit amd64 applications
|
||||
rdseed adx avx2 fma bmi2 bmi1 rdrand f16c vmx avx xsave pclmulqdq
|
||||
aes movbe sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr
|
||||
mmx cmov amd_sysc cx8 tsc fpu
|
@ -0,0 +1,3 @@
|
||||
The physical processor has 1 virtual processor (0)
|
||||
x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz)
|
||||
Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz
|
@ -0,0 +1,4 @@
|
||||
64-bit amd64 applications
|
||||
rdseed adx avx2 fma bmi2 bmi1 rdrand f16c vmx avx xsave pclmulqdq
|
||||
aes movbe sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr
|
||||
mmx cmov amd_sysc cx8 tsc fpu
|
@ -0,0 +1,6 @@
|
||||
The physical processor has 1 virtual processor (0)
|
||||
x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz)
|
||||
Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz
|
||||
The physical processor has 1 virtual processor (1)
|
||||
x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz)
|
||||
Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz
|
@ -0,0 +1,3 @@
|
||||
64-bit amd64 applications
|
||||
vmx avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16
|
||||
sse3 sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpu
|
@ -0,0 +1,22 @@
|
||||
The physical processor has 8 cores and 16 virtual processors (0-7 16-23)
|
||||
The core has 2 virtual processors (0 16)
|
||||
The core has 2 virtual processors (1 17)
|
||||
The core has 2 virtual processors (2 18)
|
||||
The core has 2 virtual processors (3 19)
|
||||
The core has 2 virtual processors (4 20)
|
||||
The core has 2 virtual processors (5 21)
|
||||
The core has 2 virtual processors (6 22)
|
||||
The core has 2 virtual processors (7 23)
|
||||
x86 (GenuineIntel 206D7 family 6 model 45 step 7 clock 2600 MHz)
|
||||
Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz
|
||||
The physical processor has 8 cores and 16 virtual processors (8-15 24-31)
|
||||
The core has 2 virtual processors (8 24)
|
||||
The core has 2 virtual processors (9 25)
|
||||
The core has 2 virtual processors (10 26)
|
||||
The core has 2 virtual processors (11 27)
|
||||
The core has 2 virtual processors (12 28)
|
||||
The core has 2 virtual processors (13 29)
|
||||
The core has 2 virtual processors (14 30)
|
||||
The core has 2 virtual processors (15 31)
|
||||
x86 (GenuineIntel 206D7 family 6 model 45 step 7 clock 2600 MHz)
|
||||
Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz
|
Loading…
Reference in New Issue