...

Source file src/k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/numa_info.go

Documentation: k8s.io/kubernetes/pkg/kubelet/cm/topologymanager

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package topologymanager
    18  
    19  import (
    20  	"fmt"
    21  
    22  	cadvisorapi "github.com/google/cadvisor/info/v1"
    23  	"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
    24  )
    25  
    26  type NUMADistances map[int][]uint64
    27  
    28  type NUMAInfo struct {
    29  	Nodes         []int
    30  	NUMADistances NUMADistances
    31  }
    32  
    33  func NewNUMAInfo(topology []cadvisorapi.Node, opts PolicyOptions) (*NUMAInfo, error) {
    34  	var numaNodes []int
    35  	distances := map[int][]uint64{}
    36  	for _, node := range topology {
    37  		numaNodes = append(numaNodes, node.Id)
    38  
    39  		var nodeDistance []uint64
    40  		if opts.PreferClosestNUMA {
    41  			nodeDistance = node.Distances
    42  			if nodeDistance == nil {
    43  				return nil, fmt.Errorf("error getting NUMA distances from cadvisor")
    44  			}
    45  		}
    46  		distances[node.Id] = nodeDistance
    47  	}
    48  
    49  	numaInfo := &NUMAInfo{
    50  		Nodes:         numaNodes,
    51  		NUMADistances: distances,
    52  	}
    53  
    54  	return numaInfo, nil
    55  }
    56  
    57  func (n *NUMAInfo) Narrowest(m1 bitmask.BitMask, m2 bitmask.BitMask) bitmask.BitMask {
    58  	if m1.IsNarrowerThan(m2) {
    59  		return m1
    60  	}
    61  	return m2
    62  }
    63  
    64  func (n *NUMAInfo) Closest(m1 bitmask.BitMask, m2 bitmask.BitMask) bitmask.BitMask {
    65  	// If the length of both bitmasks aren't the same, choose the one that is narrowest.
    66  	if m1.Count() != m2.Count() {
    67  		return n.Narrowest(m1, m2)
    68  	}
    69  
    70  	m1Distance := n.NUMADistances.CalculateAverageFor(m1)
    71  	m2Distance := n.NUMADistances.CalculateAverageFor(m2)
    72  	// If average distance is the same, take bitmask with more lower-number bits set.
    73  	if m1Distance == m2Distance {
    74  		if m1.IsLessThan(m2) {
    75  			return m1
    76  		}
    77  		return m2
    78  	}
    79  
    80  	// Otherwise, return the bitmask with the shortest average distance between NUMA nodes.
    81  	if m1Distance < m2Distance {
    82  		return m1
    83  	}
    84  
    85  	return m2
    86  }
    87  
    88  func (n NUMAInfo) DefaultAffinityMask() bitmask.BitMask {
    89  	defaultAffinity, _ := bitmask.NewBitMask(n.Nodes...)
    90  	return defaultAffinity
    91  }
    92  
    93  func (d NUMADistances) CalculateAverageFor(bm bitmask.BitMask) float64 {
    94  	// This should never happen, but just in case make sure we do not divide by zero.
    95  	if bm.Count() == 0 {
    96  		return 0
    97  	}
    98  
    99  	var count float64 = 0
   100  	var sum float64 = 0
   101  	for _, node1 := range bm.GetBits() {
   102  		for _, node2 := range bm.GetBits() {
   103  			sum += float64(d[node1][node2])
   104  			count++
   105  		}
   106  	}
   107  
   108  	return sum / count
   109  }
   110  

View as plain text