123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package topology
- import (
- "fmt"
- cadvisorapi "github.com/google/cadvisor/info/v1"
- "k8s.io/klog"
- "k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
- )
- // CPUDetails is a map from CPU ID to Core ID and Socket ID.
- type CPUDetails map[int]CPUInfo
- // CPUTopology contains details of node cpu, where :
- // CPU - logical CPU, cadvisor - thread
- // Core - physical CPU, cadvisor - Core
- // Socket - socket, cadvisor - Node
- type CPUTopology struct {
- NumCPUs int
- NumCores int
- NumSockets int
- CPUDetails CPUDetails
- }
- // CPUsPerCore returns the number of logical CPUs are associated with
- // each core.
- func (topo *CPUTopology) CPUsPerCore() int {
- if topo.NumCores == 0 {
- return 0
- }
- return topo.NumCPUs / topo.NumCores
- }
- // CPUsPerSocket returns the number of logical CPUs are associated with
- // each socket.
- func (topo *CPUTopology) CPUsPerSocket() int {
- if topo.NumSockets == 0 {
- return 0
- }
- return topo.NumCPUs / topo.NumSockets
- }
- // CPUInfo contains the socket and core IDs associated with a CPU.
- type CPUInfo struct {
- SocketID int
- CoreID int
- }
- // KeepOnly returns a new CPUDetails object with only the supplied cpus.
- func (d CPUDetails) KeepOnly(cpus cpuset.CPUSet) CPUDetails {
- result := CPUDetails{}
- for cpu, info := range d {
- if cpus.Contains(cpu) {
- result[cpu] = info
- }
- }
- return result
- }
- // Sockets returns all of the socket IDs associated with the CPUs in this
- // CPUDetails.
- func (d CPUDetails) Sockets() cpuset.CPUSet {
- b := cpuset.NewBuilder()
- for _, info := range d {
- b.Add(info.SocketID)
- }
- return b.Result()
- }
- // CPUsInSocket returns all of the logical CPU IDs associated with the
- // given socket ID in this CPUDetails.
- func (d CPUDetails) CPUsInSocket(id int) cpuset.CPUSet {
- b := cpuset.NewBuilder()
- for cpu, info := range d {
- if info.SocketID == id {
- b.Add(cpu)
- }
- }
- return b.Result()
- }
- // Cores returns all of the core IDs associated with the CPUs in this
- // CPUDetails.
- func (d CPUDetails) Cores() cpuset.CPUSet {
- b := cpuset.NewBuilder()
- for _, info := range d {
- b.Add(info.CoreID)
- }
- return b.Result()
- }
- // CoresInSocket returns all of the core IDs associated with the given
- // socket ID in this CPUDetails.
- func (d CPUDetails) CoresInSocket(id int) cpuset.CPUSet {
- b := cpuset.NewBuilder()
- for _, info := range d {
- if info.SocketID == id {
- b.Add(info.CoreID)
- }
- }
- return b.Result()
- }
- // CPUs returns all of the logical CPU IDs in this CPUDetails.
- func (d CPUDetails) CPUs() cpuset.CPUSet {
- b := cpuset.NewBuilder()
- for cpuID := range d {
- b.Add(cpuID)
- }
- return b.Result()
- }
- // CPUsInCore returns all of the logical CPU IDs associated with the
- // given core ID in this CPUDetails.
- func (d CPUDetails) CPUsInCore(id int) cpuset.CPUSet {
- b := cpuset.NewBuilder()
- for cpu, info := range d {
- if info.CoreID == id {
- b.Add(cpu)
- }
- }
- return b.Result()
- }
- // Discover returns CPUTopology based on cadvisor node info
- func Discover(machineInfo *cadvisorapi.MachineInfo) (*CPUTopology, error) {
- if machineInfo.NumCores == 0 {
- return nil, fmt.Errorf("could not detect number of cpus")
- }
- CPUDetails := CPUDetails{}
- numPhysicalCores := 0
- for _, socket := range machineInfo.Topology {
- numPhysicalCores += len(socket.Cores)
- for _, core := range socket.Cores {
- if coreID, err := getUniqueCoreID(core.Threads); err == nil {
- for _, cpu := range core.Threads {
- CPUDetails[cpu] = CPUInfo{
- CoreID: coreID,
- SocketID: socket.Id,
- }
- }
- } else {
- klog.Errorf("could not get unique coreID for socket: %d core %d threads: %v",
- socket.Id, core.Id, core.Threads)
- return nil, err
- }
- }
- }
- return &CPUTopology{
- NumCPUs: machineInfo.NumCores,
- NumSockets: len(machineInfo.Topology),
- NumCores: numPhysicalCores,
- CPUDetails: CPUDetails,
- }, nil
- }
- // getUniqueCoreID computes coreId as the lowest cpuID
- // for a given Threads []int slice. This will assure that coreID's are
- // platform unique (opposite to what cAdvisor reports - socket unique)
- func getUniqueCoreID(threads []int) (coreID int, err error) {
- if len(threads) == 0 {
- return 0, fmt.Errorf("no cpus provided")
- }
- if len(threads) != cpuset.NewCPUSet(threads...).Size() {
- return 0, fmt.Errorf("cpus provided are not unique")
- }
- min := threads[0]
- for _, thread := range threads[1:] {
- if thread < min {
- min = thread
- }
- }
- return min, nil
- }
|