Commit 41a4e2cc authored by Derek Carr's avatar Derek Carr

Scheduler support for hugepages

parent 1ec2a69d
...@@ -10,6 +10,7 @@ go_library( ...@@ -10,6 +10,7 @@ go_library(
srcs = ["qos.go"], srcs = ["qos.go"],
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/helper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
], ],
......
...@@ -22,11 +22,16 @@ import ( ...@@ -22,11 +22,16 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/helper"
) )
// supportedComputeResources is the list of compute resources for with QoS is supported. // supportedComputeResources is the list of compute resources for with QoS is supported.
var supportedQoSComputeResources = sets.NewString(string(api.ResourceCPU), string(api.ResourceMemory)) var supportedQoSComputeResources = sets.NewString(string(api.ResourceCPU), string(api.ResourceMemory))
func isSupportedQoSComputeResource(name api.ResourceName) bool {
return supportedQoSComputeResources.Has(string(name)) || helper.IsHugePageResourceName(name)
}
// GetPodQOS returns the QoS class of a pod. // GetPodQOS returns the QoS class of a pod.
// A pod is besteffort if none of its containers have specified any requests or limits. // A pod is besteffort if none of its containers have specified any requests or limits.
// A pod is guaranteed only when requests and limits are specified for all the containers and they are equal. // A pod is guaranteed only when requests and limits are specified for all the containers and they are equal.
...@@ -39,7 +44,7 @@ func GetPodQOS(pod *api.Pod) api.PodQOSClass { ...@@ -39,7 +44,7 @@ func GetPodQOS(pod *api.Pod) api.PodQOSClass {
for _, container := range pod.Spec.Containers { for _, container := range pod.Spec.Containers {
// process requests // process requests
for name, quantity := range container.Resources.Requests { for name, quantity := range container.Resources.Requests {
if !supportedQoSComputeResources.Has(string(name)) { if !isSupportedQoSComputeResource(name) {
continue continue
} }
if quantity.Cmp(zeroQuantity) == 1 { if quantity.Cmp(zeroQuantity) == 1 {
...@@ -55,7 +60,7 @@ func GetPodQOS(pod *api.Pod) api.PodQOSClass { ...@@ -55,7 +60,7 @@ func GetPodQOS(pod *api.Pod) api.PodQOSClass {
// process limits // process limits
qosLimitsFound := sets.NewString() qosLimitsFound := sets.NewString()
for name, quantity := range container.Resources.Limits { for name, quantity := range container.Resources.Limits {
if !supportedQoSComputeResources.Has(string(name)) { if !isSupportedQoSComputeResource(name) {
continue continue
} }
if quantity.Cmp(zeroQuantity) == 1 { if quantity.Cmp(zeroQuantity) == 1 {
......
...@@ -132,7 +132,7 @@ func TestGetPodQOS(t *testing.T) { ...@@ -132,7 +132,7 @@ func TestGetPodQOS(t *testing.T) {
}, },
{ {
pod: newPod("burstable-hugepages", []v1.Container{ pod: newPod("burstable-hugepages", []v1.Container{
newContainer("burstable", getResourceList("0", "0"), addResource("hugepages-2Mi", "1Gi", getResourceList("0", "0"))), newContainer("burstable", addResource("hugepages-2Mi", "1Gi", getResourceList("0", "0")), addResource("hugepages-2Mi", "1Gi", getResourceList("0", "0"))),
}), }),
expected: v1.PodQOSBurstable, expected: v1.PodQOSBurstable,
}, },
...@@ -147,7 +147,7 @@ func TestGetPodQOS(t *testing.T) { ...@@ -147,7 +147,7 @@ func TestGetPodQOS(t *testing.T) {
k8sv1.Convert_v1_Pod_To_api_Pod(testCase.pod, &pod, nil) k8sv1.Convert_v1_Pod_To_api_Pod(testCase.pod, &pod, nil)
if actual := qos.GetPodQOS(&pod); api.PodQOSClass(testCase.expected) != actual { if actual := qos.GetPodQOS(&pod); api.PodQOSClass(testCase.expected) != actual {
t.Errorf("[%d]: invalid qos pod %s, expected: %s, actual: %s", id, testCase.pod.Name, testCase.expected, actual) t.Errorf("[%d]: conversion invalid qos pod %s, expected: %s, actual: %s", id, testCase.pod.Name, testCase.expected, actual)
} }
} }
} }
......
...@@ -509,6 +509,12 @@ func GetResourceRequest(pod *v1.Pod) *schedulercache.Resource { ...@@ -509,6 +509,12 @@ func GetResourceRequest(pod *v1.Pod) *schedulercache.Resource {
result.SetExtended(rName, value) result.SetExtended(rName, value)
} }
} }
if v1helper.IsHugePageResourceName(rName) {
value := rQuantity.Value()
if value > result.HugePages[rName] {
result.SetHugePages(rName, value)
}
}
} }
} }
} }
...@@ -542,7 +548,12 @@ func PodFitsResources(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.No ...@@ -542,7 +548,12 @@ func PodFitsResources(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.No
// We couldn't parse metadata - fallback to computing it. // We couldn't parse metadata - fallback to computing it.
podRequest = GetResourceRequest(pod) podRequest = GetResourceRequest(pod)
} }
if podRequest.MilliCPU == 0 && podRequest.Memory == 0 && podRequest.NvidiaGPU == 0 && podRequest.EphemeralStorage == 0 && len(podRequest.ExtendedResources) == 0 { if podRequest.MilliCPU == 0 &&
podRequest.Memory == 0 &&
podRequest.NvidiaGPU == 0 &&
podRequest.EphemeralStorage == 0 &&
len(podRequest.ExtendedResources) == 0 &&
len(podRequest.HugePages) == 0 {
return len(predicateFails) == 0, predicateFails, nil return len(predicateFails) == 0, predicateFails, nil
} }
...@@ -567,6 +578,12 @@ func PodFitsResources(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.No ...@@ -567,6 +578,12 @@ func PodFitsResources(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.No
} }
} }
for rName, rQuant := range podRequest.HugePages {
if allocatable.HugePages[rName] < rQuant+nodeInfo.RequestedResource().HugePages[rName] {
predicateFails = append(predicateFails, NewInsufficientResourceError(rName, podRequest.HugePages[rName], nodeInfo.RequestedResource().HugePages[rName], allocatable.HugePages[rName]))
}
}
if glog.V(10) { if glog.V(10) {
if len(predicateFails) == 0 { if len(predicateFails) == 0 {
// We explicitly don't do glog.V(10).Infof() to avoid computing all the parameters if this is // We explicitly don't do glog.V(10).Infof() to avoid computing all the parameters if this is
......
...@@ -72,6 +72,7 @@ type Resource struct { ...@@ -72,6 +72,7 @@ type Resource struct {
// explicitly as int, to avoid conversions and improve performance. // explicitly as int, to avoid conversions and improve performance.
AllowedPodNumber int AllowedPodNumber int
ExtendedResources map[v1.ResourceName]int64 ExtendedResources map[v1.ResourceName]int64
HugePages map[v1.ResourceName]int64
} }
// New creates a Resource from ResourceList // New creates a Resource from ResourceList
...@@ -103,6 +104,9 @@ func (r *Resource) Add(rl v1.ResourceList) { ...@@ -103,6 +104,9 @@ func (r *Resource) Add(rl v1.ResourceList) {
if v1helper.IsExtendedResourceName(rName) { if v1helper.IsExtendedResourceName(rName) {
r.AddExtended(rName, rQuant.Value()) r.AddExtended(rName, rQuant.Value())
} }
if v1helper.IsHugePageResourceName(rName) {
r.AddHugePages(rName, rQuant.Value())
}
} }
} }
} }
...@@ -118,6 +122,9 @@ func (r *Resource) ResourceList() v1.ResourceList { ...@@ -118,6 +122,9 @@ func (r *Resource) ResourceList() v1.ResourceList {
for rName, rQuant := range r.ExtendedResources { for rName, rQuant := range r.ExtendedResources {
result[rName] = *resource.NewQuantity(rQuant, resource.DecimalSI) result[rName] = *resource.NewQuantity(rQuant, resource.DecimalSI)
} }
for rName, rQuant := range r.HugePages {
result[rName] = *resource.NewQuantity(rQuant, resource.BinarySI)
}
return result return result
} }
...@@ -135,6 +142,12 @@ func (r *Resource) Clone() *Resource { ...@@ -135,6 +142,12 @@ func (r *Resource) Clone() *Resource {
res.ExtendedResources[k] = v res.ExtendedResources[k] = v
} }
} }
if r.HugePages != nil {
res.HugePages = make(map[v1.ResourceName]int64)
for k, v := range r.HugePages {
res.HugePages[k] = v
}
}
return res return res
} }
...@@ -150,6 +163,18 @@ func (r *Resource) SetExtended(name v1.ResourceName, quantity int64) { ...@@ -150,6 +163,18 @@ func (r *Resource) SetExtended(name v1.ResourceName, quantity int64) {
r.ExtendedResources[name] = quantity r.ExtendedResources[name] = quantity
} }
func (r *Resource) AddHugePages(name v1.ResourceName, quantity int64) {
r.SetHugePages(name, r.HugePages[name]+quantity)
}
func (r *Resource) SetHugePages(name v1.ResourceName, quantity int64) {
// Lazily allocate hugepages resource map.
if r.HugePages == nil {
r.HugePages = map[v1.ResourceName]int64{}
}
r.HugePages[name] = quantity
}
// NewNodeInfo returns a ready to use empty NodeInfo object. // NewNodeInfo returns a ready to use empty NodeInfo object.
// If any pods are given in arguments, their information will be aggregated in // If any pods are given in arguments, their information will be aggregated in
// the returned object. // the returned object.
...@@ -307,6 +332,12 @@ func (n *NodeInfo) addPod(pod *v1.Pod) { ...@@ -307,6 +332,12 @@ func (n *NodeInfo) addPod(pod *v1.Pod) {
for rName, rQuant := range res.ExtendedResources { for rName, rQuant := range res.ExtendedResources {
n.requestedResource.ExtendedResources[rName] += rQuant n.requestedResource.ExtendedResources[rName] += rQuant
} }
if n.requestedResource.HugePages == nil && len(res.HugePages) > 0 {
n.requestedResource.HugePages = map[v1.ResourceName]int64{}
}
for rName, rQuant := range res.HugePages {
n.requestedResource.HugePages[rName] += rQuant
}
n.nonzeroRequest.MilliCPU += non0_cpu n.nonzeroRequest.MilliCPU += non0_cpu
n.nonzeroRequest.Memory += non0_mem n.nonzeroRequest.Memory += non0_mem
n.pods = append(n.pods, pod) n.pods = append(n.pods, pod)
...@@ -362,6 +393,12 @@ func (n *NodeInfo) removePod(pod *v1.Pod) error { ...@@ -362,6 +393,12 @@ func (n *NodeInfo) removePod(pod *v1.Pod) error {
for rName, rQuant := range res.ExtendedResources { for rName, rQuant := range res.ExtendedResources {
n.requestedResource.ExtendedResources[rName] -= rQuant n.requestedResource.ExtendedResources[rName] -= rQuant
} }
if len(res.HugePages) > 0 && n.requestedResource.HugePages == nil {
n.requestedResource.HugePages = map[v1.ResourceName]int64{}
}
for rName, rQuant := range res.HugePages {
n.requestedResource.HugePages[rName] -= rQuant
}
n.nonzeroRequest.MilliCPU -= non0_cpu n.nonzeroRequest.MilliCPU -= non0_cpu
n.nonzeroRequest.Memory -= non0_mem n.nonzeroRequest.Memory -= non0_mem
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment