Skip to content

feat: auto-detect NVIDIA GPU via CDI#1658

Merged
dengbo11 merged 1 commit into
OpenAtom-Linyaps:masterfrom
reddevillg:cdi_nvidia
May 14, 2026
Merged

feat: auto-detect NVIDIA GPU via CDI#1658
dengbo11 merged 1 commit into
OpenAtom-Linyaps:masterfrom
reddevillg:cdi_nvidia

Conversation

@reddevillg

Copy link
Copy Markdown
Collaborator

When no CDI devices are explicitly specified, automatically detect nvidia.com/gpu=all and use it for GPU support, skipping the legacy detectDrivers() call.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request updates the CDI device retrieval logic to support returning all available devices when no specific devices are requested and introduces auto-detection for NVIDIA CDI devices in the CLI. When an NVIDIA CDI device is detected, the legacy driver detection is bypassed. Feedback indicates a logic flaw where the nvidiaCdiFound flag is not set when a user manually specifies NVIDIA devices, which incorrectly triggers the legacy driver detection path.

Comment thread libs/linglong/src/linglong/cli/cli.cpp Outdated
@codecov

codecov Bot commented May 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
libs/linglong/src/linglong/cli/cli.cpp 0.00% 16 Missing ⚠️
Files with missing lines Coverage Δ
libs/linglong/src/linglong/cli/cli.cpp 1.68% <0.00%> (-0.02%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@reddevillg

Copy link
Copy Markdown
Collaborator Author

/gemini review

@reddevillg reddevillg marked this pull request as draft May 13, 2026 08:40

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request updates the getCDIDevices function to support retrieving all available CDI devices when no specific devices are provided and introduces automatic NVIDIA CDI device detection in the CLI. A significant logic flaw was identified in the CLI implementation where the check for manually specified NVIDIA devices is nested inside a block that only executes when the device list is empty, which prevents the flag from being correctly set and causes legacy driver detection to be triggered incorrectly.

Comment thread libs/linglong/src/linglong/cli/cli.cpp Outdated
When no CDI devices are explicitly specified, automatically detect
nvidia.com/gpu=all and use it for GPU support, skipping the legacy
detectDrivers() call.

Signed-off-by: reddevillg <reddevillg@gmail.com>
@reddevillg

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces auto-detection for NVIDIA CDI devices and updates the getCDIDevices function to support retrieving all available devices when no specific list is provided. The review feedback highlights several logic improvements: the auto-detection criteria should be less restrictive to allow for other CDI devices, auto-detected devices should be merged with user-provided ones rather than being mutually exclusive, and logging levels should be adjusted to reduce noise. Additionally, a minor simplification for string formatting in the CDI library was suggested.

});
std::optional<std::vector<api::types::v1::CdiDeviceEntry>> autoDetectedCdiDevices;

if (!nvidiaCdiFound && options.cdiDevices.empty()) {

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.

high

The condition options.cdiDevices.empty() is too restrictive. If a user provides other CDI devices (e.g., for storage or other accelerators), auto-detection of the NVIDIA GPU via CDI will be skipped, and the code will fall back to the legacy detectDrivers() call. This contradicts the goal of moving towards CDI-based device management. The check should ideally only be !nvidiaCdiFound.

    if (!nvidiaCdiFound) {

fmt::join(specDirs, ", ")));
std::string devicesStr;
if (devices) {
devicesStr = fmt::format("{}", fmt::join(*devices, ", "));

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.

medium

The use of fmt::format here is redundant because fmt::join already returns a formattable object. You can simplify this to fmt::to_string or just pass the join object directly to the outer fmt::format call.

Suggested change
devicesStr = fmt::format("{}", fmt::join(*devices, ", "));
devicesStr = fmt::to_string(fmt::join(*devices, ", "));

auto allCdiDevices = cdi::getCDIDevices(options.cdiSpecDir, std::nullopt);
if (allCdiDevices) {
for (const auto &device : *allCdiDevices) {
LogD("{}={} detected", device.kind, device.name);

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.

medium

Logging every detected CDI device at LogD level during auto-detection might be too noisy on systems with many CDI specifications. Consider changing this to LINGLONG_TRACE or only logging when the specific NVIDIA device is found.

                LINGLONG_TRACE(fmt::format("{}={} detected", device.kind, device.name));

Comment on lines +655 to +656
} else if (autoDetectedCdiDevices) {
opts.cdiDevices = std::move(*autoDetectedCdiDevices);

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.

medium

If options.cdiDevices is not empty, the autoDetectedCdiDevices are currently ignored. If the user provided other CDI devices but we also auto-detected an NVIDIA GPU, both should probably be included in opts.cdiDevices. The current logic forces an 'either-or' scenario which might not be what the user expects.

@reddevillg reddevillg marked this pull request as ready for review May 13, 2026 09:03
@reddevillg reddevillg requested a review from dengbo11 May 13, 2026 09:03
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的Git Diff。本次修改的主要目的是将CDI(Container Device Interface)设备的获取方式从“仅限指定列表”扩展为“支持获取全部设备(通过std::optional)”,并在CLI层实现了NVIDIA GPU的自动检测与注入逻辑,以替代原有的detectDrivers硬检测。

整体来看,修改思路清晰,逻辑基本自洽。但在代码性能、逻辑严谨性、代码安全与质量方面,有一些值得注意和改进的地方。以下是详细的审查意见:

1. 逻辑严谨性

问题:NVIDIA自动检测逻辑存在漏洞
cli.cpp 中,判断是否需要自动检测的逻辑如下:

if (!nvidiaCdiFound && options.cdiDevices.empty()) { ... }

这里的意图是:如果用户没有指定任何CDI设备,且没有显式指定nvidia设备,则尝试自动检测。
但是,nvidiaCdiFound 的初始推断是基于 options.cdiDevices 的:

bool nvidiaCdiFound = std::any_of(options.cdiDevices.begin(), options.cdiDevices.end(), ...);

如果 options.cdiDevices 不为空(例如用户指定了 vendor.com/fpga),此时 nvidiaCdiFound 为 false,且 options.cdiDevices.empty() 也为 false。这会导致跳过自动检测,进而继续执行 detectDrivers()
改进建议: 如果业务意图是“只要用户显式指定了CDI设备,就完全信任用户,不再进行任何自动检测/驱动探测”,那么当前逻辑是没问题的。但如果意图是“只要用户没有显式指定nvidia,就需要自动检测nvidia”,则需要修改判断条件。假设前者是正确意图,建议增加注释说明;否则需调整条件。

2. 代码性能

问题:std::optional<std::vector> 作为函数参数和返回值引发的深拷贝
cdi.hcdi.cpp 中:

utils::error::Result<std::vector<api::types::v1::CdiDeviceEntry>> getCDIDevices(
  const std::vector<std::string> &specDirs, const std::optional<std::vector<std::string>> &devices)

std::optional<std::vector<T>> 作为一个整体对象,在传参时即便是常引用,在构造或返回时也极易触发 std::vector 的深拷贝。同样,在 cli.cpp 中:

auto allCdiDevices = cdi::getCDIDevices(options.cdiSpecDir, std::nullopt);

改进建议:

  1. 参数层面: 表示“可选列表”更符合C++习惯且性能更好的做法是传递空列表(即 const std::vector<std::string> &devices,如果 devices.empty() 则视为获取全部),或者使用 std::span。如果必须区分“未提供”和“提供空列表”,可以使用 std::optional<std::vector<...>>,但建议按常引用传递(当前已做到)。
  2. 返回值层面: utils::error::Result 内部包含了 std::vector,在 cli.cpp 中调用后,后续有 autoDetectedCdiDevices = std::vector<...>{ device } 这样的赋值,会引发多次 vector 的拷贝/移动。建议尽量使用 std::moveemplace_back 来优化。

3. 代码安全

问题:getuid() 的使用缺乏头文件引用与错误检查
cli.cpp 中:

auto userContainerDir = std::filesystem::path{ "/run/linglong" } / std::to_string(getuid());

getuid() 是 POSIX 系统调用,需要包含 <unistd.h>。虽然这不在 diff 上下文中,但需确保已包含。此外,在极端安全场景下,应考虑 getuid() 返回值的合理性(虽然正常不会失败)。
改进建议: 确保已包含 <unistd.h>。如果项目跨平台,需注意这是平台相关代码。

4. 代码质量与可读性

问题一:自动检测代码块过长,且职责混杂
cli.cpprun 方法中,插入了长达20行的自动检测逻辑,使得原本的 detectDrivers() 调用变得臃肿,且混合了遍历、日志、状态判断和变量赋值。
改进建议: 将自动检测逻辑提取为一个独立的私有成员函数,例如 std::optional<api::types::v1::CdiDeviceEntry> Cli::tryAutoDetectNvidiaCdi(...),这样 run 方法会更加清晰。

问题二:硬编码的字符串常量
"nvidia.com/gpu""all" 在代码中作为魔术字符串出现。

return d.find("nvidia.com/gpu") != std::string::npos;
// ...
if (device.kind == "nvidia.com/gpu" && device.name == "all") {

改进建议: 将这些字符串提取为常量或 constexpr std::string_view,避免拼写错误,并方便未来统一修改。

constexpr std::string_view NVIDIA_GPU_KIND = "nvidia.com/gpu";
constexpr std::string_view ALL_DEVICES_NAME = "all";

问题三:cdi.cpp 中的重复代码
cdi.cpp 中,当 !devices 时,有一段构建 CdiDeviceEntry 的逻辑:

result.emplace_back(api::types::v1::CdiDeviceEntry{
  .kind = spec.spec.kind,
  .name = dev.name,
  .spec = api::types::v1::CdiSpec{ .checksum = spec.checksum, .path = spec.path.string() },
});

这段逻辑与下方 for (const auto &deviceStr : *devices) 循环内部的构建逻辑极有可能是重复的。
改进建议: 审查下方的循环,如果构建 CdiDeviceEntry 的逻辑一致,建议提取为一个 lambda 或辅助函数,减少代码重复。


综合改进后的代码示例

基于上述意见,以下是对 cli.cpp 相关逻辑的重构建议:

// 在 cli.h 或 cli.cpp 开头定义常量
constexpr std::string_view NVIDIA_GPU_KIND = "nvidia.com/gpu";
constexpr std::string_view ALL_DEVICES_NAME = "all";

// 提取出的自动检测函数
std::optional<api::types::v1::CdiDeviceEntry> Cli::tryAutoDetectNvidiaCdi(const std::vector<std::string> &specDirs) {
    auto allCdiDevices = cdi::getCDIDevices(specDirs, std::nullopt);
    if (!allCdiDevices) {
        return std::nullopt;
    }
    
    for (const auto &device : *allCdiDevices) {
        LogD("{}={} detected", device.kind, device.name);
        if (device.kind == NVIDIA_GPU_KIND && device.name == ALL_DEVICES_NAME) {
            return device; // 直接返回找到的设备,避免多余的拷贝
        }
    }
    return std::nullopt;
}

int Cli::run(const RunOptions &options)
{
    LINGLONG_TRACE("command run");

    // 判断用户是否显式指定了 nvidia 设备
    bool nvidiaCdiFound = std::any_of(options.cdiDevices.cbegin(), options.cdiDevices.cend(), 
        [](const std::string &d) {
            return d.find(NVIDIA_GPU_KIND) != std::string::npos;
        }
    );

    std::optional<api::types::v1::CdiDeviceEntry> autoDetectedCdiDevice;

    // 仅当用户未显式指定任何 CDI 设备时,才尝试自动检测
    if (!nvidiaCdiFound && options.cdiDevices.empty()) {
        autoDetectedCdiDevice = tryAutoDetectNvidiaCdi(options.cdiSpecDir);
        if (autoDetectedCdiDevice) {
            nvidiaCdiFound = true;
        }
    }

    // 如果没有找到任何 nvidia CDI 配置,回退到旧的驱动检测逻辑
    if (!nvidiaCdiFound) {
        detectDrivers();
    }

    auto userContainerDir = std::filesystem::path{ "/run/linglong" } / std::to_string(getuid());
    // ... 保持后续逻辑不变 ...

    // 在赋值处使用移动语义提升性能
    } else if (autoDetectedCdiDevice) {
        opts.cdiDevices = std::vector<api::types::v1::CdiDeviceEntry>{ std::move(*autoDetectedCdiDevice) };
    }
}

对于 cdi.cpp 的修改建议:

// cdi.cpp 中提取构建 CdiDeviceEntry 的逻辑(假设下方循环也有类似代码)
auto buildEntry = [](const ParsedSpec& spec, const auto& dev) {
    return api::types::v1::CdiDeviceEntry{
        .kind = spec.spec.kind,
        .name = dev.name,
        .spec = api::types::v1::CdiSpec{
            .checksum = spec.checksum,
            .path = spec.path.string(),
        },
    };
};

if (!devices) {
    for (const auto &spec : specs) {
        for (const auto &dev : spec.spec.devices) {
            result.emplace_back(buildEntry(spec, dev));
        }
    }
    return result;
}

for (const auto &deviceStr : *devices) {
    // ... 查找逻辑 ...
    // 使用 buildEntry 替代手写构造
    result.emplace_back(buildEntry(spec, dev));
}

希望这些审查意见和重构建议对你有所帮助!如果有任何疑问,欢迎随时提问。

@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengbo11, reddevillg

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@dengbo11 dengbo11 merged commit 235d593 into OpenAtom-Linyaps:master May 14, 2026
16 of 17 checks passed
@reddevillg reddevillg deleted the cdi_nvidia branch May 14, 2026 07:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants