in pkg/trimaran/targetloadpacking/targetloadpacking.go [174:257]
func (pl *TargetLoadPacking) Score(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
if err != nil {
return framework.MinNodeScore, framework.NewStatus(framework.Error, fmt.Sprintf("getting node %q from Snapshot: %v", nodeName, err))
}
// copy value lest updateMetrics() updates it and to avoid locking for rest of the function
pl.mu.RLock()
metrics := pl.metrics
pl.mu.RUnlock()
// This means the node is new (no metrics yet) or metrics are unavailable due to 404 or 500
if _, ok := metrics.Data.NodeMetricsMap[nodeName]; !ok {
klog.V(6).Infof("unable to find metrics for node %v", nodeName)
// Avoid the node by scoring minimum
return framework.MinNodeScore, nil
//TODO(aqadeer): If this happens for a long time, fall back to allocation based packing. This could mean maintaining failure state across cycles if scheduler doesn't provide this state
}
var curPodCPUUsage int64
for _, container := range pod.Spec.Containers {
curPodCPUUsage += PredictUtilisation(&container)
}
klog.V(6).Infof("predicted utilization for pod %v: %v", pod.Name, curPodCPUUsage)
if pod.Spec.Overhead != nil {
curPodCPUUsage += pod.Spec.Overhead.Cpu().MilliValue()
}
var nodeCPUUtilPercent float64
var cpuMetricFound bool
for _, metric := range metrics.Data.NodeMetricsMap[nodeName].Metrics {
if metric.Type == watcher.CPU {
if metric.Operator == watcher.Average || metric.Operator == watcher.Latest {
nodeCPUUtilPercent = metric.Value
cpuMetricFound = true
}
}
}
if !cpuMetricFound {
klog.Errorf("cpu metric not found for node %v in node metrics %v", nodeName, metrics.Data.NodeMetricsMap[nodeName].Metrics)
return framework.MinNodeScore, nil
}
nodeCPUCapMillis := float64(nodeInfo.Node().Status.Capacity.Cpu().MilliValue())
nodeCPUUtilMillis := (nodeCPUUtilPercent / 100) * nodeCPUCapMillis
klog.V(6).Infof("node %v CPU Utilization (millicores): %v, Capacity: %v", nodeName, nodeCPUUtilMillis, nodeCPUCapMillis)
var missingCPUUtilMillis int64 = 0
pl.eventHandler.RLock()
for _, info := range pl.eventHandler.ScheduledPodsCache[nodeName] {
// If the time stamp of the scheduled pod is outside fetched metrics window, or it is within metrics reporting interval seconds, we predict util.
// Note that the second condition doesn't guarantee metrics for that pod are not reported yet as the 0 <= t <= 2*metricsAgentReportingIntervalSeconds
// t = metricsAgentReportingIntervalSeconds is taken as average case and it doesn't hurt us much if we are
// counting metrics twice in case actual t is less than metricsAgentReportingIntervalSeconds
if info.Timestamp.Unix() > metrics.Window.End || info.Timestamp.Unix() <= metrics.Window.End &&
(metrics.Window.End-info.Timestamp.Unix()) < metricsAgentReportingIntervalSeconds {
for _, container := range info.Pod.Spec.Containers {
missingCPUUtilMillis += PredictUtilisation(&container)
}
missingCPUUtilMillis += info.Pod.Spec.Overhead.Cpu().MilliValue()
klog.V(6).Infof("missing utilization for pod %v : %v", info.Pod.Name, missingCPUUtilMillis)
}
}
pl.eventHandler.RUnlock()
klog.V(6).Infof("missing utilization for node %v : %v", nodeName, missingCPUUtilMillis)
var predictedCPUUsage float64
if nodeCPUCapMillis != 0 {
predictedCPUUsage = 100 * (nodeCPUUtilMillis + float64(curPodCPUUsage) + float64(missingCPUUtilMillis)) / nodeCPUCapMillis
}
if predictedCPUUsage > float64(hostTargetUtilizationPercent) {
if predictedCPUUsage > 100 {
return framework.MinNodeScore, framework.NewStatus(framework.Success, "")
}
penalisedScore := int64(math.Round(50 * (100 - predictedCPUUsage) / (100 - float64(hostTargetUtilizationPercent))))
klog.V(6).Infof("penalised score for host %v: %v", nodeName, penalisedScore)
return penalisedScore, framework.NewStatus(framework.Success, "")
}
score := int64(math.Round((100-float64(hostTargetUtilizationPercent))*
predictedCPUUsage/float64(hostTargetUtilizationPercent) + float64(hostTargetUtilizationPercent)))
klog.V(6).Infof("score for host %v: %v", nodeName, score)
return score, framework.NewStatus(framework.Success, "")
}