func()

in pkg/controllers/provisioning/binpacking/packer.go [161:192]


func (p *Packer) packWithLargestPod(unpackedPods []*v1.Pod, packables []*Packable) (*Packing, []*v1.Pod) {
	bestPackedPods := []*v1.Pod{}
	bestInstances := []cloudprovider.InstanceType{}
	remainingPods := unpackedPods

	// Try to pack the largest instance type to get an upper bound on efficiency
	maxPodsPacked := len(packables[len(packables)-1].DeepCopy().Pack(unpackedPods).packed)
	if maxPodsPacked == 0 {
		return &Packing{Pods: [][]*v1.Pod{bestPackedPods}, InstanceTypeOptions: bestInstances}, remainingPods
	}

	for i, packable := range packables {
		// check how many pods we can fit with the available capacity
		if result := packable.Pack(unpackedPods); len(result.packed) == maxPodsPacked {
			// Add all packable nodes that have more resources than this one
			// Trim the bestInstances so that provisioning APIs in cloud providers are not overwhelmed by the number of instance type options
			// For example, the AWS EC2 Fleet API only allows the request to be 145kb which equates to about 130 instance type options.
			for j := i; j < len(packables) && j-i < MaxInstanceTypes; j++ {
				// packable nodes are sorted lexicographically according to the order of [CPU, memory]
				// It may result in cases where an instance type may have larger index value when it has more CPU but fewer memory
				// Need to exclude instance type with smaller memory and fewer pods
				if packables[i].Memory().Cmp(*packables[j].Memory()) <= 0 && packables[i].Pods().Cmp(*packables[j].Pods()) <= 0 {
					bestInstances = append(bestInstances, packables[j])
				}
			}
			bestPackedPods = result.packed
			remainingPods = result.unpacked
			break
		}
	}
	return &Packing{Pods: [][]*v1.Pod{bestPackedPods}, InstanceTypeOptions: bestInstances, NodeQuantity: 1}, remainingPods
}