-
Notifications
You must be signed in to change notification settings - Fork 794
feat(device-plugin): support CDI-only NVIDIA accelerators (GB10) #2087
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
tittuvarghese
wants to merge
3
commits into
Project-HAMi:master
from
tittuvarghese:feat/nvidia-gb10-device-plugin
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| # NVIDIA GB10 (Grace-Blackwell iGPU) Support | ||
|
|
||
| ## Introduction | ||
|
|
||
| The NVIDIA GB10 (Grace-Blackwell "superchip", as shipped in the DGX Spark) is an | ||
| **integrated GPU** that shares unified LPDDR5X memory with the Grace CPU over a | ||
| coherent NVLink-C2C link. It differs from a discrete GPU in two ways that affect | ||
| HAMi's device plugin: | ||
|
|
||
| 1. **No dedicated framebuffer.** `nvmlDeviceGetMemoryInfo()` returns | ||
| `ERROR_NOT_SUPPORTED` because there is no fixed device-local memory pool to | ||
| report — the "GPU memory" is system memory allocated dynamically. | ||
| 2. **CDI-only exposure.** The device is provisioned through the NVIDIA Container | ||
| Toolkit's [CDI](https://github.com/cncf-tags/container-device-interface) | ||
| mechanism. It is described by an on-node CDI spec | ||
| (`/var/run/cdi/k8s.device-plugin.nvidia.com-gpu.json`) and is **not** | ||
| enumerable via NVML inside the device-plugin container. | ||
|
|
||
| Because HAMi's device plugin historically discovered devices only through NVML, | ||
| on a GB10 node `ResolvePlatform()` returns `unknown` and the plugin exits with: | ||
|
|
||
| ```text | ||
| factory.go] Incompatible strategy detected auto | ||
| main.go] error starting plugins: ... failed to construct resource managers: | ||
| invalid device discovery strategy | ||
| ``` | ||
|
|
||
| To support these accelerators, the NVIDIA device plugin can discover GPUs | ||
| directly from the node's CDI specs (no NVML required) using the `cdi` | ||
| device-discovery strategy. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - The **NVIDIA GPU Operator** (or NVIDIA Container Toolkit) is installed and has | ||
| generated the CDI spec at `/var/run/cdi/k8s.device-plugin.nvidia.com-gpu.json`. | ||
| You can verify the node's own device plugin advertises `nvidia.com/gpu` and | ||
| that GPU Feature Discovery has labelled the node, e.g. | ||
| `nvidia.com/gpu.product=NVIDIA-GB10`. | ||
| - The node carries the label HAMi's device-plugin DaemonSet selects on | ||
| (`gpu=on` by default): | ||
|
|
||
| ```bash | ||
| kubectl label node <gb10-node> gpu=on | ||
| ``` | ||
|
|
||
| - The kernel's inotify limits are high enough for the plugin's filesystem | ||
| watcher. Busy nodes can exhaust the default `fs.inotify.max_user_instances` | ||
| (128), which makes the plugin fail at start-up with | ||
| `couldn't initialize inotify: too many open files`. Raise it persistently: | ||
|
|
||
| ```bash | ||
| # /etc/sysctl.d/99-hami-inotify.conf | ||
| fs.inotify.max_user_instances = 8192 | ||
| fs.inotify.max_user_watches = 524288 | ||
| ``` | ||
|
|
||
| ```bash | ||
| sudo sysctl --system | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| Set the following on the NVIDIA device plugin (Helm `values.yaml`): | ||
|
|
||
| ```yaml | ||
| devicePlugin: | ||
| # Discover devices from the on-node CDI specs instead of via NVML. | ||
| deviceDiscoveryStrategy: "cdi" | ||
| # Inject the device through CDI (matches the NVIDIA GPU Operator plugin). | ||
| deviceListStrategy: "cdi-annotations,cdi-cri" | ||
| # Unified memory (in MiB) HAMi should treat as schedulable per GPU. NVML | ||
| # cannot report it on a unified-memory GPU, so it is a policy value — set it | ||
| # at or below the node's total unified memory, leaving headroom for the OS. | ||
| # See the note below for deriving it from the node (the example is not a | ||
| # direct GiB conversion). | ||
| preConfiguredDeviceMemory: 122566 | ||
| # Optional. Device type recorded for scheduling/`use-gputype`. | ||
| # Defaults to "NVIDIA-GB10" when empty. | ||
| preConfiguredDeviceType: "NVIDIA-GB10" | ||
| ``` | ||
|
|
||
| Notes: | ||
|
|
||
| - `deviceDiscoveryStrategy` also accepts `auto` (the default), which falls back | ||
| to `cdi` automatically when no NVML/Tegra platform is detected **and** a CDI | ||
| device-list strategy is active and CDI specs are present. Setting it to `cdi` | ||
| explicitly is recommended for clarity on GB10 nodes. | ||
| - `preConfiguredDeviceMemory` is a scheduling **policy** value — how much unified | ||
| memory HAMi treats as schedulable per GPU — interpreted as MiB (HAMi multiplies | ||
| it by 1024×1024 to get bytes). It is **not** a hardware GPU-memory readout: on a | ||
| unified-memory device the memory is shared with the CPU/OS. The example | ||
| `122566` is **this DGX Spark's total system memory as reported by Kubernetes**, | ||
| not a direct GiB conversion (120 GiB would be 122880 MiB): | ||
|
|
||
| ```bash | ||
| kubectl get node <gb10-node> -o jsonpath='{.status.capacity.memory}' | ||
| # 125506464Ki -> 125506464 / 1024 = 122566 MiB (~119.7 GiB) | ||
| ``` | ||
|
|
||
| Choose a value at or below this, leaving headroom for the OS. | ||
| It can be overridden per node via `nodeConfiguration.config` (`preconfigureddevicememory`). | ||
| - `preConfiguredDeviceType` can be overridden per node via `preconfigureddevicetype`. | ||
|
tittuvarghese marked this conversation as resolved.
|
||
|
|
||
| ## How it works | ||
|
|
||
| 1. **Discovery** — the plugin reads the CDI specs under `/etc/cdi` and | ||
| `/var/run/cdi`, enumerating GPU devices for vendor | ||
| `k8s.device-plugin.nvidia.com`, class `gpu` (the `all` meta-device is | ||
| excluded). Each CDI device becomes a schedulable GPU keyed by its CDI device | ||
| name (a GPU UUID). | ||
| 2. **Registration** — because NVML is unavailable, per-GPU memory and type come | ||
| from `preConfiguredDeviceMemory` / `preConfiguredDeviceType` instead of being | ||
| queried from the driver. | ||
| 3. **Allocation** — on `Allocate`, the plugin emits the CDI device reference | ||
| (`k8s.device-plugin.nvidia.com/gpu=<uuid>`) via the `cdi-annotations` / | ||
| `cdi-cri` device-list strategy, so containerd injects the device. HAMi's | ||
| memory/core limiting (libvgpu) is applied on top as usual. | ||
|
|
||
| ## Limitations | ||
|
|
||
| - Because there is no per-device NVML data, **all** GPUs discovered in `cdi` | ||
| mode share the same `preConfiguredDeviceMemory` and `preConfiguredDeviceType`. | ||
| This targets homogeneous CDI-only nodes (e.g. a single-GB10 DGX Spark). | ||
| - Health checks and MIG are not available in `cdi` mode (both require NVML). | ||
| - GPU topology scoring (`ENABLE_TOPOLOGY_SCORE`) is skipped in `cdi` mode: it | ||
| computes pairwise P2P/NVLink scores via NVML, which is unavailable and | ||
| meaningless for a single CDI-only iGPU. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| /* | ||
| Copyright 2024 The HAMi Authors. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| */ | ||
|
|
||
| package cdi | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/NVIDIA/go-nvlib/pkg/nvlib/info" | ||
| spec "github.com/NVIDIA/k8s-device-plugin/api/config/v1" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // fakeInfo is a minimal info.Interface used to drive the New() branches. | ||
| type fakeInfo struct { | ||
| platform info.Platform | ||
| hasNVML bool | ||
| } | ||
|
|
||
| func (f fakeInfo) ResolvePlatform() info.Platform { return f.platform } | ||
| func (f fakeInfo) HasDXCore() (bool, string) { return false, "" } | ||
| func (f fakeInfo) HasNvml() (bool, string) { return f.hasNVML, "" } | ||
| func (f fakeInfo) HasTegraFiles() (bool, string) { return false, "" } | ||
| func (f fakeInfo) HasAnIntegratedGPU() (bool, string) { return false, "" } | ||
|
|
||
| func mustStrategies(t *testing.T, s ...string) spec.DeviceListStrategies { | ||
| t.Helper() | ||
| ds, err := spec.NewDeviceListStrategies(s) | ||
| require.NoError(t, err) | ||
| return ds | ||
| } | ||
|
|
||
| // When no CDI device-list strategy is enabled, New returns the null handler, | ||
| // whose QualifiedName yields an empty string. | ||
| func TestNew_NoCDIEnabled_ReturnsNull(t *testing.T) { | ||
| h, err := New(fakeInfo{hasNVML: false}, nil, nil, | ||
| WithDeviceListStrategies(mustStrategies(t, "envvar"))) | ||
| require.NoError(t, err) | ||
| require.Empty(t, h.QualifiedName("gpu", "0")) | ||
| require.NoError(t, h.CreateSpecFile()) | ||
| } | ||
|
|
||
| // When a CDI device-list strategy is requested but NVML is unavailable (the | ||
| // GB10 / CDI-only case), New returns the external handler that can still build | ||
| // qualified device names for injection. | ||
| func TestNew_NoNVML_CDIEnabled_ReturnsExternal(t *testing.T) { | ||
| h, err := New(fakeInfo{hasNVML: false}, nil, nil, | ||
| WithDeviceListStrategies(mustStrategies(t, "cdi-annotations", "cdi-cri")), | ||
| WithVendor(DefaultVendor)) | ||
| require.NoError(t, err) | ||
| require.Equal(t, DefaultVendor+"/gpu=GPU-abc", h.QualifiedName("gpu", "GPU-abc")) | ||
| require.NoError(t, h.CreateSpecFile()) | ||
| require.Empty(t, h.AdditionalDevices()) | ||
| } | ||
|
|
||
| // The external handler falls back to DefaultVendor when no vendor is set. | ||
| func TestNew_NoNVML_DefaultVendor(t *testing.T) { | ||
| h, err := New(fakeInfo{hasNVML: false}, nil, nil, | ||
| WithDeviceListStrategies(mustStrategies(t, "cdi-cri"))) | ||
| require.NoError(t, err) | ||
| require.Equal(t, DefaultVendor+"/gpu=0", h.QualifiedName("gpu", "0")) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| /* | ||
| Copyright 2024 The HAMi Authors. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| */ | ||
|
|
||
| package cdi | ||
|
|
||
| import ( | ||
| cdiparser "tags.cncf.io/container-device-interface/pkg/parser" | ||
| ) | ||
|
|
||
| // DefaultVendor is the CDI vendor used by the NVIDIA device plugin. It matches | ||
| // the vendor of the CDI specs generated by the NVIDIA Container Toolkit / | ||
| // GPU Operator (e.g. /var/run/cdi/k8s.device-plugin.nvidia.com-gpu.json). | ||
| const DefaultVendor = "k8s.device-plugin.nvidia.com" | ||
|
|
||
| // externalHandler is a CDI handler for nodes where the accelerator is exposed | ||
| // only through externally-managed CDI specs and NVML is not available to the | ||
| // device plugin. This is the case for CDI-only accelerators such as the GB10 | ||
| // (Grace-Blackwell iGPU), whose device is described by a CDI spec generated by | ||
| // the NVIDIA Container Toolkit rather than being enumerable via NVML. | ||
| // | ||
| // It can construct qualified CDI device names for injection but does not | ||
| // generate CDI spec files itself (the spec is provided by the node). | ||
| type externalHandler struct { | ||
| vendor string | ||
| } | ||
|
|
||
| var _ Interface = &externalHandler{} | ||
|
|
||
| // newExternalHandler returns a CDI handler that references externally-managed | ||
| // CDI specs. An empty vendor defaults to DefaultVendor. | ||
| func newExternalHandler(vendor string) Interface { | ||
| if vendor == "" { | ||
| vendor = DefaultVendor | ||
| } | ||
| return &externalHandler{vendor: vendor} | ||
| } | ||
|
|
||
| // CreateSpecFile is a no-op: the CDI spec is managed externally on the node. | ||
| func (h *externalHandler) CreateSpecFile() error { | ||
| return nil | ||
| } | ||
|
|
||
| // QualifiedName constructs a CDI qualified device name for the specified | ||
| // resources. It assumes the id matches a device name present in the | ||
| // externally-managed CDI spec. | ||
| func (h *externalHandler) QualifiedName(class string, id string) string { | ||
| return cdiparser.QualifiedName(h.vendor, class, id) | ||
| } | ||
|
|
||
| // AdditionalDevices returns no additional devices for externally-managed specs. | ||
| func (h *externalHandler) AdditionalDevices() []string { | ||
| return nil | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.