Skip to content
Open
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
65 changes: 57 additions & 8 deletions docs/developers/scheduling.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,46 +132,95 @@ In `Spread` policy, `Node2` is selected.

![HAMi GPU scheduler policy diagram, comparing Binpack and Spread scores on each card](/img/docs/common/developers/scheduling/gpu-scheduler-policy-demo.png)

#### Per-Pod device scoring weights

By default, HAMi gives equal influence to predicted virtual-device slot, device-core, and device-memory utilization when it scores a physical device. To change that balance for one workload, add the `hami.io/device-scoring-weights` annotation to the Pod:

```yaml
apiVersion: v1
kind: Pod
metadata:
name: memory-weighted-gpu-pod
annotations:
hami.io/device-scoring-weights: "slot=1,core=1,memory=3"
Comment thread
mesutoezdil marked this conversation as resolved.
Comment thread
mesutoezdil marked this conversation as resolved.
Comment thread
mesutoezdil marked this conversation as resolved.
spec:
containers:
- name: workload
image: ubuntu:22.04
command: ["bash", "-c", "sleep 86400"]
resources:
limits:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checked against pkg/scheduler/policy/gpu_policy.go:217-220 and util.Weight is 10, so the three term formula and the 7.75 and 18.75 figures are right.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yess, thanks for verifying as well

nvidia.com/gpu: 1
nvidia.com/gpumem-percentage: 40
```

HAMi predicts each candidate device's utilization after placing the request, then calculates its device score as follows:

```text
score = 10 * (
Comment thread
mesutoezdil marked this conversation as resolved.
slotWeight * predictedSlotUtilization +
coreWeight * predictedCoreUtilization +
memoryWeight * predictedMemoryUtilization
)
```

The annotation must contain the `slot`, `core`, and `memory` keys. Each value must be a non-negative integer, and at least one value must be greater than zero. Key order and surrounding whitespace do not matter. If the annotation is absent, HAMi uses `slot=1,core=1,memory=1`, which preserves the default scoring behavior. When the admission webhook is enabled, invalid annotations are rejected when a Pod requesting a HAMi-managed resource is created. If admission validation is unavailable, the scheduler rejects the scheduling attempt and the Pod remains unschedulable until the annotation is corrected.

For example, consider two candidate GPUs after accounting for a Pod that requests one vGPU and 40% device memory:

| Device | Predicted slot utilization | Predicted core utilization | Predicted memory utilization |
| ------ | -------------------------: | -------------------------: | ---------------------------: |
| GPU A | 0.2 | 0.9 | 0.5 |
| GPU B | 0.8 | 0.1 | 0.6 |

With the default `1:1:1` weights, GPU A scores `16` and GPU B scores `15`, so `binpack` prefers GPU A. With `slot=1,core=1,memory=3`, GPU A scores `26` and GPU B scores `27`, so `binpack` prefers GPU B. Under `spread`, the lower score is preferred instead.

The annotation changes only the utilization score used to order candidate devices. It does not bypass device fit or capacity checks, mutex rules, NUMA or topology constraints, or vendor-specific `Fit` behavior. These constraints keep their existing precedence; when topology candidates are otherwise tied, their utilization-score ordering can act as the tie-breaker.

#### Binpack

Binpack mainly focuses on the computing power and video memory usage of each card. The more it is used, the higher the score.
Binpack prefers the card with the higher device-utilization score. The following default-weight example assumes each card has ten virtual-device slots and no slot is currently in use:

```text
score: ((request.core + used.core) / allocatable.core + (request.mem + used.mem) / allocatable.mem)) * 10
score: ((request.slot + used.slot) / allocatable.slot +
Comment thread
mesutoezdil marked this conversation as resolved.
(request.core + used.core) / allocatable.core +
(request.mem + used.mem) / allocatable.mem) * 10
```

1. Binpack scoring information for GPU 1 is as follows

```text
GPU1 Score: ((20+10)/100 + (1000+2000)/8000)) * 10 = 6.75
GPU1 Score: ((1+0)/10 + (20+10)/100 + (1000+2000)/8000) * 10 = 7.75

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the current implementation, shouldn’t used.slot also be at least 1, for example (1+1)/10?

https://github.com/Project-HAMi/HAMi/blob/b5ec6b143a322e33a7ace339dff840cccb2e55ac/pkg/scheduler/scheduler.go#L808-L812

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code uses max(udevice.Slots, 1) for each existing allocation, so used.slot cannot be 0 here.

```

1. Binpack scoring information for GPU 2 is as follows

```text
GPU2 Score: ((20+70)/100 + (1000+6000)/8000)) * 10 = 17.75
GPU2 Score: ((1+0)/10 + (20+70)/100 + (1000+6000)/8000) * 10 = 18.75
```

In `Binpack` policy, `GPU2` is selected.

#### Spread

Spread mainly focuses on the computing power and video memory usage of each card. The less it is used, the higher the score.
Spread prefers the card with the lower device-utilization score. Using the same default-weight example:

```text
score: ((request.core + used.core) / allocatable.core + (request.mem + used.mem) / allocatable.mem)) * 10
score: ((request.slot + used.slot) / allocatable.slot +
(request.core + used.core) / allocatable.core +
(request.mem + used.mem) / allocatable.mem) * 10
```

1. Spread scoring information for GPU 1 is as follows

```text
GPU1 Score: ((20+10)/100 + (1000+2000)/8000)) * 10 = 6.75
GPU1 Score: ((1+0)/10 + (20+10)/100 + (1000+2000)/8000) * 10 = 7.75
```

1. Spread scoring information for GPU 2 is as follows

```text
GPU2 Score: ((20+70)/100 + (1000+6000)/8000)) * 10 = 17.75
GPU2 Score: ((1+0)/10 + (20+70)/100 + (1000+6000)/8000) * 10 = 18.75
```

In `Spread` policy, `GPU1` is selected.
Expand Down
1 change: 1 addition & 0 deletions docs/userguide/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ helm install hami hami-charts/hami --set devicePlugin.deviceMemoryScaling=5 -n k
| `nvidia.com/use-gputype` | String | If set, devices allocated by this pod MUST be one of the types defined in this string. | `"Tesla V100-PCIE-32GB, NVIDIA A10"` |
| `hami.io/node-scheduler-policy` | String | GPU node scheduling policy: `"binpack"` allocates the pod to used GPU nodes for execution. `"spread"` allocates the pod to different GPU nodes for execution. | `"binpack"` or `"spread"` |
| `hami.io/gpu-scheduler-policy` | String | GPU scheduling policy: `"binpack"` allocates the pod to the same GPU card for execution. `"spread"` allocates the pod to different GPU cards for execution. `"mutex"` allocates the pod only to a GPU card with no other workloads, giving it exclusive use of that card. | `"binpack"`, `"spread"` or `"mutex"` |
| `hami.io/device-scoring-weights` | String | Relative weights of virtual-device slot, device-core, and device-memory utilization in physical-device scoring. All three weights are required, must be non-negative integers, and at least one must be positive. | `"slot=1,core=1,memory=3"` |
| `nvidia.com/vgpu-mode` | String | The type of vGPU instance this pod wishes to use. | `"hami-core"` or `"mig"` |

## Container Configs: Env
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,46 +133,95 @@ Node2 score: ((1+2)/4) * 10= 7.5

![HAMi GPU 调度策略示意图,展示在单卡上的 Binpack 与 Spread 评分对比](/img/docs/common/developers/scheduling/gpu-scheduler-policy-demo.png)

#### 每个 Pod 的设备评分权重

默认情况下,HAMi 在计算物理设备得分时,会让预测的虚拟设备槽位、设备核心和设备显存利用率具有相同的影响。若要为某个工作负载调整它们的相对影响,可为 Pod 添加 `hami.io/device-scoring-weights` 注解:

```yaml
apiVersion: v1
kind: Pod
metadata:
name: memory-weighted-gpu-pod
annotations:
hami.io/device-scoring-weights: "slot=1,core=1,memory=3"
spec:
containers:
- name: workload
image: ubuntu:22.04
command: ["bash", "-c", "sleep 86400"]
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem-percentage: 40
```

HAMi 会预测在放置请求后每个候选设备的利用率,然后按以下公式计算设备得分:

```text
score = 10 * (
slotWeight * predictedSlotUtilization +
coreWeight * predictedCoreUtilization +
memoryWeight * predictedMemoryUtilization
)
```

注解必须包含 `slot`、`core` 和 `memory` 三个键。每个值都必须是非负整数,并且至少有一个值大于零。键的顺序以及两侧的空格不会影响解析。如果未设置该注解,HAMi 将使用 `slot=1,core=1,memory=1`,从而保持默认评分行为。启用准入 Webhook 后,如果请求 HAMi 管理资源的 Pod 包含无效注解,则会在创建时被拒绝。如果准入验证不可用,调度器会拒绝此次调度尝试,Pod 将保持不可调度状态,直到该注解被修正。

例如,假设一个 Pod 请求 1 个 vGPU 和 40% 的设备显存,并且在计入该请求后有两个候选 GPU:

| 设备 | 预测槽位利用率 | 预测核心利用率 | 预测显存利用率 |
| ----- | -------------: | -------------: | -------------: |
| GPU A | 0.2 | 0.9 | 0.5 |
| GPU B | 0.8 | 0.1 | 0.6 |

使用默认的 `1:1:1` 权重时,GPU A 得分为 `16`,GPU B 得分为 `15`,因此 `binpack` 会优先选择 GPU A。使用 `slot=1,core=1,memory=3` 时,GPU A 得分为 `26`,GPU B 得分为 `27`,因此 `binpack` 会优先选择 GPU B。在 `spread` 策略下,则会优先选择得分较低的设备。

该注解只会改变用于排序候选设备的利用率得分。它不会绕过设备适配或容量检查、mutex 规则、NUMA 或拓扑约束,也不会改变厂商特定的 `Fit` 行为。这些约束仍保留现有的优先级;当拓扑候选项在其他方面相同时,可以使用利用率得分顺序作为决胜条件。

#### Binpack

Binpack 主要关注每张卡的计算能力和显存使用情况。使用越多,得分越高。
Binpack 优先选择设备利用率得分较高的卡。以下默认权重示例假设每张卡有 10 个虚拟设备槽位,并且当前没有槽位被使用:

```text
score: ((request.core + used.core) / allocatable.core + (request.mem + used.mem) / allocatable.mem)) * 10
score: ((request.slot + used.slot) / allocatable.slot +
(request.core + used.core) / allocatable.core +
(request.mem + used.mem) / allocatable.mem) * 10
```

1. GPU1 的 Binpack 评分信息如下

```text
GPU1 Score: ((20+10)/100 + (1000+2000)/8000)) * 10 = 6.75
GPU1 Score: ((1+0)/10 + (20+10)/100 + (1000+2000)/8000) * 10 = 7.75
```

1. GPU2 的 Binpack 评分信息如下

```text
GPU2 Score: ((20+70)/100 + (1000+6000)/8000)) * 10 = 17.75
GPU2 Score: ((1+0)/10 + (20+70)/100 + (1000+6000)/8000) * 10 = 18.75
```

因此,在 `Binpack` 策略中我们可以选择 `GPU2`。

#### Spread

Spread 主要关注每张卡的计算能力和显存使用情况。使用越少,得分越高。
Spread 优先选择设备利用率得分较低的卡。使用相同的默认权重示例:

```text
score: ((request.core + used.core) / allocatable.core + (request.mem + used.mem) / allocatable.mem)) * 10
score: ((request.slot + used.slot) / allocatable.slot +
(request.core + used.core) / allocatable.core +
(request.mem + used.mem) / allocatable.mem) * 10
```

1. GPU1 的 Spread 评分信息如下

```text
GPU1 Score: ((20+10)/100 + (1000+2000)/8000)) * 10 = 6.75
GPU1 Score: ((1+0)/10 + (20+10)/100 + (1000+2000)/8000) * 10 = 7.75
```

1. GPU2 的 Spread 评分信息如下

```text
GPU2 Score: ((20+70)/100 + (1000+6000)/8000)) * 10 = 17.75
GPU2 Score: ((1+0)/10 + (20+70)/100 + (1000+6000)/8000) * 10 = 18.75
```

因此,在 `Spread` 策略中我们可以选择 `GPU1`。
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ helm install hami hami-charts/hami --set devicePlugin.deviceMemoryScaling=5 -n k
| `nvidia.com/use-gputype` | 字符串 | 如果设置了此字段,则该 Pod 分配的设备**必须**是此字符串中定义的 GPU 类型之一。 | `"Tesla V100-PCIE-32GB, NVIDIA A10"` |
| `hami.io/node-scheduler-policy` | 字符串 | GPU 节点调度策略:`"binpack"` 表示将 Pod 分配到已有负载的 GPU 节点上执行,`"spread"` 表示分配到不同的 GPU 节点上执行。 | `"binpack"` 或 `"spread"` |
| `hami.io/gpu-scheduler-policy` | 字符串 | GPU 卡调度策略:`"binpack"` 表示将 Pod 分配到同一块 GPU 卡上执行,`"spread"` 表示分配到不同的 GPU 卡上执行。 | `"binpack"` 或 `"spread"` |
| `hami.io/device-scoring-weights` | 字符串 | 物理设备评分中虚拟设备槽位、设备核心和设备显存利用率的相对权重。必须提供全部三个权重,值必须为非负整数,并且至少有一个权重大于零。 | `"slot=1,core=1,memory=3"` |
| `nvidia.com/vgpu-mode` | 字符串 | 指定该 Pod 希望使用的 vGPU 实例类型。 | `"hami-core"` 或 `"mig"` |

## 容器配置:环境变量
Expand Down