diff --git a/go.mod b/go.mod index f5fc67b134..de444446e6 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282 github.com/hako/durafmt v0.0.0-20180520121703-7b7ae1e72ead github.com/huaweicloud/huaweicloud-sdk-go v1.0.26 - github.com/jaypipes/ghw v0.9.0 + github.com/jaypipes/ghw v0.9.1 github.com/jdcloud-api/jdcloud-sdk-go v1.55.0 github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c github.com/lestrrat-go/jwx v1.0.2 @@ -261,5 +261,6 @@ require ( replace ( github.com/go-logr/logr => github.com/go-logr/logr v0.4.0 + github.com/jaypipes/ghw => github.com/zexi/ghw v0.9.1 google.golang.org/grpc => google.golang.org/grpc v1.29.0 ) diff --git a/go.sum b/go.sum index f242369d03..f9779e4c4a 100644 --- a/go.sum +++ b/go.sum @@ -415,8 +415,6 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jaypipes/ghw v0.9.0 h1:TWF4wNIGtZcgDJaiNcFgby5BR8s2ixcUe0ydxNO2McY= -github.com/jaypipes/ghw v0.9.0/go.mod h1:dXMo19735vXOjpIBDyDYSp31sB2u4hrtRCMxInqQ64k= github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLRCuNDfk= github.com/jdcloud-api/jdcloud-sdk-go v1.55.0 h1:mzVj8r6fluEwjn8ogqtGfYW2qSIVUaEq0JAsvjCav3A= github.com/jdcloud-api/jdcloud-sdk-go v1.55.0/go.mod h1:UrKjuULIWLjHFlG6aSPunArE5QX57LftMmStAZJBEX8= @@ -711,6 +709,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zexi/ghw v0.9.1 h1:3PaJ22kRnqTsTJWpNLminGQcYrIT3FA4nz6h1R4E2mg= +github.com/zexi/ghw v0.9.1/go.mod h1:dXMo19735vXOjpIBDyDYSp31sB2u4hrtRCMxInqQ64k= go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU= diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 89056ef375..3e83ca2e68 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -4066,21 +4066,40 @@ func (self *SHost) PerformPing(ctx context.Context, userCred mcclient.TokenCrede } func (host *SHost) getHostLogicalCores() ([]int, error) { - topoObj, err := host.SysInfo.Get("topology") + cpuObj, err := host.SysInfo.Get("cpu_info") if err != nil { - return nil, errors.Wrap(err, "get topology from host sys_info") + return nil, errors.Wrap(err, "get cpu info from host sys_info") } - - hostTopo := new(hostapi.HostTopology) - if err := topoObj.Unmarshal(hostTopo); err != nil { - return nil, errors.Wrap(err, "Unmarshal host topology struct") + cpuInfo := new(hostapi.HostCPUInfo) + if err := cpuObj.Unmarshal(cpuInfo); err != nil { + return nil, errors.Wrap(err, "Unmarshal host cpu info struct") } // get host logical cores allCores := []int{} - for _, node := range hostTopo.Nodes { - for _, cores := range node.Cores { - allCores = append(allCores, cores.LogicalProcessors...) + + if len(cpuInfo.Processors) != 0 { + for _, p := range cpuInfo.Processors { + for _, core := range p.Cores { + allCores = append(allCores, core.LogicalProcessors...) + } + } + sort.Ints(allCores) + } else { + topoObj, err := host.SysInfo.Get("topology") + if err != nil { + return nil, errors.Wrap(err, "get topology from host sys_info") + } + + hostTopo := new(hostapi.HostTopology) + if err := topoObj.Unmarshal(hostTopo); err != nil { + return nil, errors.Wrap(err, "Unmarshal host topology struct") + } + + for _, node := range hostTopo.Nodes { + for _, cores := range node.Cores { + allCores = append(allCores, cores.LogicalProcessors...) + } } } return allCores, nil diff --git a/pkg/hostman/hostinfo/hostinfo.go b/pkg/hostman/hostinfo/hostinfo.go index 448b0aa522..e8eae5e72f 100644 --- a/pkg/hostman/hostinfo/hostinfo.go +++ b/pkg/hostman/hostinfo/hostinfo.go @@ -482,7 +482,12 @@ func (h *SHostInfo) detectHostInfo() error { if err != nil { return errors.Wrap(err, "Get hardware topology") } + cpuInfo, err := hardware.GetCPU() + if err != nil { + return errors.Wrap(err, "Get CPU info") + } h.sysinfo.Topology = topoInfo + h.sysinfo.CPUInfo = cpuInfo system_service.Init() if options.HostOptions.CheckSystemServices { diff --git a/pkg/hostman/hostinfo/hostinfohelper.go b/pkg/hostman/hostinfo/hostinfohelper.go index a54ee30beb..35a52d81ac 100644 --- a/pkg/hostman/hostinfo/hostinfohelper.go +++ b/pkg/hostman/hostinfo/hostinfohelper.go @@ -327,6 +327,7 @@ type SSysInfo struct { HugepageSizeKb int `json:"hugepage_size_kb"` Topology *hostapi.HostTopology `json:"topology"` + CPUInfo *hostapi.HostCPUInfo `json:"cpu_info"` } func StartDetachStorages(hs []jsonutils.JSONObject) { diff --git a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go index 44e4ced745..bb33e903ac 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "os" "path/filepath" + "regexp" "strconv" "strings" @@ -32,6 +33,24 @@ func (i *Info) load() error { return nil } +func ProcByID(procs []*Processor, id int) *Processor { + for pid := range procs { + if procs[pid].ID == id { + return procs[pid] + } + } + return nil +} + +func CoreByID(cores []*ProcessorCore, id int) *ProcessorCore { + for cid := range cores { + if cores[cid].Index == id { + return cores[cid] + } + } + return nil +} + func processorsGet(ctx *context.Context) []*Processor { procs := make([]*Processor, 0) paths := linuxpath.New(ctx) @@ -46,6 +65,7 @@ func processorsGet(ctx *context.Context) []*Processor { procAttrs := make([]map[string]string, 0) curProcAttrs := make(map[string]string) + // Parse /proc/cpuinfo scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) @@ -64,85 +84,69 @@ func processorsGet(ctx *context.Context) []*Processor { curProcAttrs[key] = value } - // Build a set of physical processor IDs which represent the physical - // package of the CPU - setPhysicalIDs := make(map[int]bool) - for _, attrs := range procAttrs { - pid, err := strconv.Atoi(attrs["physical id"]) - if err != nil { + // Iterate on /sys/devices/system/cpu/cpuN, not on /proc/cpuinfo + Entries, _ := ioutil.ReadDir(paths.SysDevicesSystemCPU) + for _, lcore := range Entries { + reg := regexp.MustCompile("^cpu([0-9]+)$") + if !reg.MatchString(lcore.Name()) { continue } - setPhysicalIDs[pid] = true - } - for pid := range setPhysicalIDs { - p := &Processor{ - ID: pid, - } - // The indexes into the array of attribute maps for each logical - // processor within the physical processor - lps := make([]int, 0) - for x := range procAttrs { - lppid, err := strconv.Atoi(procAttrs[x]["physical id"]) - if err != nil { - continue - } - if pid == lppid { - lps = append(lps, x) - } - } - first := procAttrs[lps[0]] - p.Model = first["model name"] - p.Vendor = first["vendor_id"] - numCores, err := strconv.Atoi(first["cpu cores"]) - if err != nil { + lcoreID, error := strconv.Atoi(lcore.Name()[3:]) // get "N" out of "cpuN" + if error != nil { continue } - p.NumCores = uint32(numCores) - numThreads, err := strconv.Atoi(first["siblings"]) - if err != nil { - continue - } - p.NumThreads = uint32(numThreads) - // The flags field is a space-separated list of CPU capabilities - p.Capabilities = strings.Split(first["flags"], " ") + // Fetch CPU ID + physIdPath := fmt.Sprintf( + "%s/cpu%d/topology/physical_package_id", + paths.SysDevicesSystemCPU, + lcoreID, + ) + cpuID := util.SafeIntFromFile(ctx, physIdPath) - cores := make([]*ProcessorCore, 0) - for _, lpidx := range lps { - lpid, err := strconv.Atoi(procAttrs[lpidx]["processor"]) - if err != nil { - continue + proc := ProcByID(procs, cpuID) + if proc == nil { + proc = &Processor{ID: cpuID} + // Assumes /proc/cpuinfo is in order of logical cpu id, then + // procAttrs[lcoreID] describes logical cpu `lcoreID`. + // Once got a more robust way of fetching the following info, + // can we drop /proc/cpuinfo. + if len(procAttrs[lcoreID]["flags"]) != 0 { // x86 + proc.Capabilities = strings.Split(procAttrs[lcoreID]["flags"], " ") + } else if len(procAttrs[lcoreID]["Features"]) != 0 { // ARM64 + proc.Capabilities = strings.Split(procAttrs[lcoreID]["Features"], " ") } - coreID, err := strconv.Atoi(procAttrs[lpidx]["core id"]) - if err != nil { - continue + if len(procAttrs[lcoreID]["model name"]) != 0 { + proc.Model = procAttrs[lcoreID]["model name"] + } else if len(procAttrs[lcoreID]["uarch"]) != 0 { // SiFive + proc.Model = procAttrs[lcoreID]["uarch"] } - var core *ProcessorCore - for _, c := range cores { - if c.ID == coreID { - c.LogicalProcessors = append( - c.LogicalProcessors, - lpid, - ) - c.NumThreads = uint32(len(c.LogicalProcessors)) - core = c - } - } - if core == nil { - coreLps := make([]int, 1) - coreLps[0] = lpid - core = &ProcessorCore{ - ID: coreID, - Index: len(cores), - NumThreads: 1, - LogicalProcessors: coreLps, - } - cores = append(cores, core) + if len(procAttrs[lcoreID]["vendor_id"]) != 0 { + proc.Vendor = procAttrs[lcoreID]["vendor_id"] + } else if len(procAttrs[lcoreID]["isa"]) != 0 { // RISCV64 + proc.Vendor = procAttrs[lcoreID]["isa"] } + procs = append(procs, proc) } - p.Cores = cores - procs = append(procs, p) + + // Fetch Core ID + coreIdPath := fmt.Sprintf( + "%s/cpu%d/topology/core_id", + paths.SysDevicesSystemCPU, + lcoreID, + ) + coreID := util.SafeIntFromFile(ctx, coreIdPath) + core := CoreByID(proc.Cores, coreID) + if core == nil { + core = &ProcessorCore{Index: coreID, NumThreads: 1} + proc.Cores = append(proc.Cores, core) + proc.NumCores += 1 + } else { + core.NumThreads += 1 + } + proc.NumThreads += 1 + core.LogicalProcessors = append(core.LogicalProcessors, lcoreID) } return procs } diff --git a/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go b/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go index c5967d6194..bbe81b64ef 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go @@ -64,6 +64,7 @@ type Paths struct { SysBlock string SysDevicesSystemNode string SysDevicesSystemMemory string + SysDevicesSystemCPU string SysBusPciDevices string SysClassDRM string SysClassDMI string @@ -84,6 +85,7 @@ func New(ctx *context.Context) *Paths { SysBlock: filepath.Join(ctx.Chroot, roots.Sys, "block"), SysDevicesSystemNode: filepath.Join(ctx.Chroot, roots.Sys, "devices", "system", "node"), SysDevicesSystemMemory: filepath.Join(ctx.Chroot, roots.Sys, "devices", "system", "memory"), + SysDevicesSystemCPU: filepath.Join(ctx.Chroot, roots.Sys, "devices", "system", "cpu"), SysBusPciDevices: filepath.Join(ctx.Chroot, roots.Sys, "bus", "pci", "devices"), SysClassDRM: filepath.Join(ctx.Chroot, roots.Sys, "class", "drm"), SysClassDMI: filepath.Join(ctx.Chroot, roots.Sys, "class", "dmi"), diff --git a/vendor/modules.txt b/vendor/modules.txt index 194e2ed3bc..0901d1e38d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -549,7 +549,7 @@ github.com/huaweicloud/huaweicloud-sdk-go/auth/aksk # github.com/imdario/mergo v0.3.6 ## explicit github.com/imdario/mergo -# github.com/jaypipes/ghw v0.9.0 +# github.com/jaypipes/ghw v0.9.1 => github.com/zexi/ghw v0.9.1 ## explicit; go 1.15 github.com/jaypipes/ghw/pkg/context github.com/jaypipes/ghw/pkg/cpu @@ -1494,4 +1494,5 @@ yunion.io/x/sqlchemy/backends/sqlite ## explicit; go 1.12 yunion.io/x/structarg # github.com/go-logr/logr => github.com/go-logr/logr v0.4.0 +# github.com/jaypipes/ghw => github.com/zexi/ghw v0.9.1 # google.golang.org/grpc => google.golang.org/grpc v1.29.0