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
}