k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/common/network/worker_pod_info.go (about)

     1  /*
     2  Copyright 2021 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 network
    18  
    19  import (
    20  	"container/heap"
    21  	"fmt"
    22  
    23  	"k8s.io/klog/v2"
    24  )
    25  
    26  // workerNodeInfo represents node in heap
    27  type workerNodeInfo struct {
    28  	nodeName     string
    29  	numberOfPods int
    30  }
    31  
    32  type nodeHeap []*workerNodeInfo
    33  
    34  func (nh nodeHeap) Len() int { return len(nh) }
    35  func (nh nodeHeap) Less(i, j int) bool {
    36  	return nh[i].numberOfPods > nh[j].numberOfPods
    37  }
    38  
    39  func (nh nodeHeap) Swap(i, j int) {
    40  	nh[i], nh[j] = nh[j], nh[i]
    41  }
    42  
    43  func (nh *nodeHeap) Push(x interface{}) {
    44  	*nh = append(*nh, x.(*workerNodeInfo))
    45  }
    46  
    47  func (nh *nodeHeap) Pop() interface{} {
    48  	old := *nh
    49  	n := len(old)
    50  	x := old[n-1]
    51  	*nh = old[0 : n-1]
    52  	return x
    53  }
    54  
    55  // workerPodData represents details of pods running on worker node
    56  type workerPodData struct {
    57  	podName    string
    58  	workerNode string
    59  	podIP      string
    60  }
    61  
    62  type podList []workerPodData
    63  
    64  func (l *podList) Pop() (*workerPodData, error) {
    65  	if len(*l) == 0 {
    66  		return nil, fmt.Errorf("empty pod list")
    67  	}
    68  	lastElement := (*l)[len(*l)-1]
    69  	*l = (*l)[:len(*l)-1]
    70  	return &lastElement, nil
    71  }
    72  
    73  // podPair represents source-destination worker pod pair.
    74  type podPair struct {
    75  	index              int
    76  	sourcePodName      string
    77  	sourcePodIP        string
    78  	destinationPodName string
    79  	destinationPodIP   string
    80  }
    81  
    82  func newPodPair(index int, sourcePod, destinationPod *workerPodData) podPair {
    83  	return podPair{
    84  		index:              index,
    85  		sourcePodName:      sourcePod.podName,
    86  		sourcePodIP:        sourcePod.podIP,
    87  		destinationPodName: destinationPod.podName,
    88  		destinationPodIP:   destinationPod.podIP,
    89  	}
    90  }
    91  
    92  type workerPodInfo struct {
    93  	workerPodMap map[string]podList
    94  }
    95  
    96  func (wp *workerPodInfo) formUniquePodPair() []podPair {
    97  	nh := make(nodeHeap, 0, len(wp.workerPodMap))
    98  	podPairList := make([]podPair, 0)
    99  	for key, value := range wp.workerPodMap {
   100  		nh = append(nh, &workerNodeInfo{nodeName: key, numberOfPods: len(value)})
   101  	}
   102  	heap.Init(&nh)
   103  	for i := 0; nh.Len() > 1; i++ {
   104  		firstNode := heap.Pop(&nh).(*workerNodeInfo)
   105  		secondNode := heap.Pop(&nh).(*workerNodeInfo)
   106  		if firstNode.numberOfPods > 1 {
   107  			heap.Push(&nh, &workerNodeInfo{nodeName: firstNode.nodeName, numberOfPods: firstNode.numberOfPods - 1})
   108  		}
   109  		if secondNode.numberOfPods > 1 {
   110  			heap.Push(&nh, &workerNodeInfo{nodeName: secondNode.nodeName, numberOfPods: secondNode.numberOfPods - 1})
   111  		}
   112  
   113  		sourcePod, err1 := wp.pop(firstNode.nodeName)
   114  		destinationPod, err2 := wp.pop(secondNode.nodeName)
   115  		if err1 != nil || err2 != nil {
   116  			klog.Errorf("error in popping pods. err1: %v, err2: %v", err1, err2)
   117  			continue
   118  		}
   119  		podPairList = append(podPairList, newPodPair(i, sourcePod, destinationPod))
   120  	}
   121  	return podPairList
   122  }
   123  
   124  func (wp *workerPodInfo) pop(nodeName string) (*workerPodData, error) {
   125  	podList, ok := wp.workerPodMap[nodeName]
   126  	if !ok {
   127  		return nil, fmt.Errorf("worker node %s is removed", nodeName)
   128  	}
   129  	pod, err := podList.Pop()
   130  	if err != nil {
   131  		delete(wp.workerPodMap, nodeName)
   132  		return nil, err
   133  	}
   134  	wp.workerPodMap[nodeName] = podList
   135  	return pod, nil
   136  }