Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 47 additions & 23 deletions pkg/device/metax/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ const (
MetaxGPUCommonWord = "Metax-GPU"
MetaxAnnotationLoss = "metax-tech.com/gpu.topology.losses"
MetaxAnnotationScore = "metax-tech.com/gpu.topology.scores"

// metaxTopologyLossBase converts a topology "loss" (where lower is better)
// onto the same "higher is better" scale as the scores annotation, via
// metaxTopologyLossBase - loss. It must stay larger than the largest loss a
// node can publish so the converted score remains positive.
metaxTopologyLossBase = 2000
)

var (
Expand Down Expand Up @@ -165,54 +171,72 @@ func (dev *MetaxDevices) customFilterRule(allocated *device.PodDevices, request
return true
}

func parseMetaxAnnos(annos string, index int) float32 {
// parseMetaxAnnos parses a Metax topology annotation (a JSON object mapping a
// requested device count to a topology value) and returns the value for index
// together with whether it was found. A missing annotation entry, malformed
// JSON, or an index that is absent from the map all yield (0, false) so callers
// can distinguish "no usable topology data" from a genuine value of zero.
func parseMetaxAnnos(annos string, index int) (float32, bool) {
scoreMap := map[int]int{}
err := json.Unmarshal([]byte(annos), &scoreMap)
if err != nil {
klog.Warningf("annos[%s] Unmarshal failed, %v", annos, err)
return 0
return 0, false
}

res, ok := scoreMap[index]
if !ok {
klog.Warningf("scoreMap[%v] not contains [%d]", scoreMap, index)
return 0
return 0, false
}

return float32(res)
return float32(res), true
}

// ScoreNode returns a policy-independent score for the node following a
// "higher score is a better node" convention. The shared scheduler policy layer
// is responsible for weighting this score and adapting it to the active
// scheduling policy (for example, inverting it under the Spread policy).
//
// Metax publishes two topology annotations for the requested device count: a
// "scores" map where higher is better and a "losses" map where lower is better.
// The scores annotation is used directly; when it is absent or does not carry a
// usable value for the requested count, the losses annotation is converted onto
// the same "higher is better" scale. This keeps a node's topology preference
// effective regardless of which of the two annotations it publishes. A node
// that advertises no usable topology data scores a neutral 0 so it never
// outranks a node that does.
func (dev *MetaxDevices) ScoreNode(node *corev1.Node, podDevices device.PodSingleDevice, previous []*device.DeviceUsage, policy string) float32 {
sum := 0
for _, dev := range podDevices {
sum += len(dev)
}

res := float32(0)
if policy == string(util.NodeSchedulerPolicyBinpack) {
lossAnno, ok := node.Annotations[MetaxAnnotationLoss]
if ok {
// it's preferred to select the node with lower loss
loss := parseMetaxAnnos(lossAnno, sum)
res = 2000 - loss

klog.InfoS("Detected annotations", "policy", policy, "key", MetaxAnnotationLoss, "value", lossAnno, "requesting", sum, "extract", loss)
if scoreAnno, ok := node.Annotations[MetaxAnnotationScore]; ok {
// it's preferred to select the node with higher score
if score, found := parseMetaxAnnos(scoreAnno, sum); found {
klog.InfoS("Detected annotations", "key", MetaxAnnotationScore, "value", scoreAnno, "requesting", sum, "extract", score)
return score
}
} else if policy == string(util.NodeSchedulerPolicySpread) {
scoreAnno, ok := node.Annotations[MetaxAnnotationScore]
if ok {
// it's preferred to select the node with higher score
// But we have to give it a smaller value because of Spread policy
score := parseMetaxAnnos(scoreAnno, sum)
res = 2000 - score

klog.InfoS("Detected annotations", "policy", policy, "key", MetaxAnnotationScore, "value", scoreAnno, "requesting", sum, "extract", score)
}

if lossAnno, ok := node.Annotations[MetaxAnnotationLoss]; ok {
// it's preferred to select the node with lower loss, so convert the
// loss onto a "higher is better" scale.
if loss, found := parseMetaxAnnos(lossAnno, sum); found {
klog.InfoS("Detected annotations", "key", MetaxAnnotationLoss, "value", lossAnno, "requesting", sum, "extract", loss)
return metaxTopologyLossBase - loss
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return res
return 0
}

// PolicyNeutralScore marks MetaxDevices as returning a policy-independent score
// from ScoreNode, so the shared scheduler policy layer owns the weighting and
// Spread-policy sign inversion.
func (dev *MetaxDevices) PolicyNeutralScore() {}

func (dev *MetaxDevices) AddResourceUsage(pod *corev1.Pod, n *device.DeviceUsage, ctr *device.ContainerDevice) error {
n.Used++
n.Usedcores += ctr.Usedcores
Expand Down
Loading
Loading