Merge pull request #328 from jen20/solaris-cpu

cpu: Implement Solaris support for Info()
pull/330/head
shirou 8 years ago committed by GitHub
commit d4c8874c19

@ -1,4 +1,4 @@
// +build !darwin,!linux,!freebsd,!openbsd,!windows
// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows
package cpu
@ -15,7 +15,3 @@ func Times(percpu bool) ([]TimesStat, error) {
func Info() ([]InfoStat, error) {
return []InfoStat{}, common.ErrNotImplementedError
}
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
return []float64{}, common.ErrNotImplementedError
}

@ -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…
Cancel
Save