Skip to content

Conversation

@GongHeng2017
Copy link
Contributor

@GongHeng2017 GongHeng2017 commented Dec 1, 2025

-- Add to to adjust the special platform to show memory size.

Log: fix issue
Bug: https://pms.uniontech.com/bug-view-342533.html

Summary by Sourcery

Adjust device generator selection and GPU info pre-caching on custom platforms based on the presence of a PCI graphics card.

Bug Fixes:

  • Ensure memory and GPU-related information is correctly handled on custom platforms with or without PCI graphics cards.

Enhancements:

  • Add a thread-safe helper to detect the presence of PCI graphics cards using lspci and reuse its result across the application.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 1, 2025

Reviewer's Guide

This PR adds a thread-safe helper to detect the presence of a PCI graphics card via lspci and uses it to select the appropriate device generator on custom platforms and to conditionally pre-cache GPU info, fixing missing memory size reporting on certain special platforms.

Sequence diagram for DeviceFactory::getDeviceGenerator with PCI graphics detection

sequenceDiagram
    participant Client
    participant DeviceFactory
    participant CommonTools
    participant HWGenerator
    participant ArmGenerator
    participant CustomGenerator

    Client->>DeviceFactory: getDeviceGenerator()
    activate DeviceFactory
    alt type is HW
        DeviceFactory->>HWGenerator: create
        DeviceFactory-->>Client: HWGenerator instance
    else type is PGUX
        DeviceFactory->>HWGenerator: create
        DeviceFactory-->>Client: HWGenerator instance
    else type is CustomType
        DeviceFactory->>CommonTools: hasPciGraphicsCard()
        activate CommonTools
        CommonTools->>CommonTools: run lspci via QProcess
        CommonTools-->>DeviceFactory: bool hasPci
        deactivate CommonTools
        alt hasPci == true
            DeviceFactory->>ArmGenerator: create
            DeviceFactory-->>Client: ArmGenerator instance
        else hasPci == false
            DeviceFactory->>CustomGenerator: create
            DeviceFactory-->>Client: CustomGenerator instance
        end
    else other type
        DeviceFactory->>HWGenerator: create
        DeviceFactory-->>Client: HWGenerator instance
    end
    deactivate DeviceFactory
Loading

Class diagram for CommonTools PCI graphics detection and DeviceFactory generator selection

classDiagram
    class CommonTools {
        <<QObject>>
        +static QString getGpuInfoCommandFromDConfig()
        +static QString preGenerateGpuInfo()
        +static bool hasPciGraphicsCard()
        -static bool getGpuBaseInfo(QMap~QString,QString~ &mapInfo)
    }

    class DeviceFactory {
        +static DeviceGenerator* getDeviceGenerator()
    }

    class DeviceGenerator {
    }

    class HWGenerator {
    }

    class ArmGenerator {
    }

    class CustomGenerator {
    }

    DeviceFactory ..> DeviceGenerator : creates
    DeviceFactory ..> HWGenerator : may create
    DeviceFactory ..> ArmGenerator : may create
    DeviceFactory ..> CustomGenerator : may create
    DeviceFactory ..> CommonTools : uses hasPciGraphicsCard

    HWGenerator --|> DeviceGenerator
    ArmGenerator --|> DeviceGenerator
    CustomGenerator --|> DeviceGenerator

    CommonTools ..> QProcess : uses
    CommonTools ..> QMutex : uses
    CommonTools ..> QMutexLocker : uses
Loading

Flow diagram for main startup GPU info pre-generation with PCI detection

flowchart TD
    A[start_main] --> B[Check specialComType]
    B -->|specialComType == kCustomType| C[Call CommonTools_hasPciGraphicsCard]
    B -->|specialComType != kCustomType| E[Skip_preGenerateGpuInfo]

    C --> D{hasPciGraphicsCard == false}
    D -->|true| F[Call CommonTools_preGenerateGpuInfo]
    D -->|false| E

    F --> G[Continue_application_startup]
    E --> G
Loading

File-Level Changes

Change Details Files
Introduce a reusable, thread-safe helper to detect whether the system has a PCI graphics card using lspci.
  • Add QMutex and QMutexLocker includes to support thread-safe static state initialization.
  • Implement CommonTools::hasPciGraphicsCard() using a cached static result protected by a mutex.
  • Invoke the lspci command with appropriate arguments, enforce a 5-second timeout, and log failures or timeouts via qCritical.
  • Determine presence of a PCI GPU by checking whether lspci output (for class 0300) is non-empty.
deepin-devicemanager/src/Tool/commontools.cpp
deepin-devicemanager/src/Tool/commontools.h
Use PCI GPU detection to choose between ArmGenerator and CustomGenerator for the "CustomType" platform.
  • Include commontools.h in DeviceFactory.cpp to use the new helper.
  • Change DeviceFactory::getDeviceGenerator() so that for type == "CustomType", it selects ArmGenerator when a PCI graphics card is present and CustomGenerator otherwise.
deepin-devicemanager/src/GenerateDevice/DeviceFactory.cpp
Limit pre-generation of GPU info on special custom machines to those without PCI graphics cards.
  • Update the main() startup path to only call CommonTools::preGenerateGpuInfo() when the special machine type is CustomType and no PCI graphics card is detected.
deepin-devicemanager/src/main.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • The hasPciGraphicsCard() implementation blocks synchronously for up to 5 seconds via QProcess::waitForFinished, which may freeze the main/UI thread where it’s used (e.g., in main.cpp and DeviceFactory); consider either running this check off the UI thread or reducing/handling the timeout more defensively.
  • In hasPciGraphicsCard(), the critical log message on non‑zero exit code has a typo (lspic instead of lspci) and does not include readAllStandardError(), which would make diagnosing failures easier.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `hasPciGraphicsCard()` implementation blocks synchronously for up to 5 seconds via `QProcess::waitForFinished`, which may freeze the main/UI thread where it’s used (e.g., in `main.cpp` and `DeviceFactory`); consider either running this check off the UI thread or reducing/handling the timeout more defensively.
- In `hasPciGraphicsCard()`, the critical log message on non‑zero exit code has a typo (`lspic` instead of `lspci`) and does not include `readAllStandardError()`, which would make diagnosing failures easier.

## Individual Comments

### Comment 1
<location> `deepin-devicemanager/src/Tool/commontools.cpp:309-318` </location>
<code_context>
     return (gpuBaseInfo + gpuMemInfo);
 }

+bool CommonTools::hasPciGraphicsCard()
+{
+    static bool result = false;
+    static bool initialized = false;
+    static QMutex mutex;
+
+    QMutexLocker locker(&mutex);
+
+    if (!initialized) {
+        QProcess process;
+        process.setProgram("lspci");
+        process.setArguments(QStringList() << "-v" << "-d" << "::0300");
+        process.start();
+        if (!process.waitForFinished(5000)) {
+            qCritical() << "Exec lspci time out!";
+            result = false;
</code_context>

<issue_to_address>
**suggestion:** Handle QProcess start failures and distinguish them from timeouts/normal non-zero exits.

Right now we only check `waitForFinished(5000)` and `exitCode()`. If `lspci` fails to start (missing binary, permissions, etc.), `waitForFinished` may still return `true`, and `exitCode()` can be misleading/undefined. Please handle `process.start()`/`waitForStarted()` and inspect `process.error()` (e.g. treat `QProcess::FailedToStart` as a hard failure and log it) so start failures are distinguished from timeouts and normal non-zero exits.

Suggested implementation:

```cpp
bool CommonTools::hasPciGraphicsCard()
{
    static bool result = false;
    static bool initialized = false;
    static QMutex mutex;

    QMutexLocker locker(&mutex);

    if (!initialized) {
        QProcess process;
        process.setProgram("lspci");
        process.setArguments(QStringList() << "-v" << "-d" << "::0300");

        process.start();

        // Distinguish start failures from timeouts and normal exits
        if (!process.waitForStarted(1000)) {
            if (process.error() == QProcess::FailedToStart) {
                qCritical() << "Failed to start lspci:" << process.errorString();
            } else {
                qCritical() << "Starting lspci timed out or failed:" << process.errorString();
            }
            result = false;
        } else if (!process.waitForFinished(5000)) {
            qCritical() << "Exec lspci time out!";
            result = false;
        } else if (process.exitStatus() != QProcess::NormalExit) {
            qCritical() << "Exec lspci crashed or exited abnormally, status:" << process.exitStatus()
                        << ", error:" << process.errorString();
            result = false;
        } else if (process.exitCode() != 0) {
            qCritical() << "Failed to exec lspci, code:" << process.exitCode();
            result = false;
        } else {
            QString output = process.readAllStandardOutput();
            result = !output.trimmed().isEmpty();
        }

        initialized = true;
    }


```

1. Ensure the `hasPciGraphicsCard()` function ends with `return result;` (not visible in the snippet). If it does not, add `return result;` at the end of the function.
2. If the project’s logging style prefers `qWarning()` for some non-fatal conditions (e.g. timeouts vs. hard failures), you may want to adjust the `qCritical()` calls accordingly to match existing conventions in the rest of `commontools.cpp`.
</issue_to_address>

### Comment 2
<location> `deepin-devicemanager/src/Tool/commontools.cpp:325-327` </location>
<code_context>
+        if (!process.waitForFinished(5000)) {
+            qCritical() << "Exec lspci time out!";
+            result = false;
+        } else if (process.exitCode() != 0) {
+            qCritical() << "Failed to exec lspic, code : " << process.exitCode();
+            result = false;
+        } else {
</code_context>

<issue_to_address>
**nitpick (typo):** Fix the `lspci` log message typo to aid debugging.

The log currently says `"Failed to exec lspic"`, which doesn’t match the `lspci` command being run and can hinder log searches. Please correct the message to use `lspci`.

```suggestion
        } else if (process.exitCode() != 0) {
            qCritical() << "Failed to exec lspci, code : " << process.exitCode();
            result = false;
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: GongHeng2017, lzwind

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

-- Add to to adjust the special platform to show memory size.

Log: fix issue
Bug: https://pms.uniontech.com/bug-view-342533.html
@GongHeng2017 GongHeng2017 force-pushed the 202512011123-eagle-fix branch from 618686d to 26a36d4 Compare December 1, 2025 07:56
@deepin-ci-robot
Copy link

deepin pr auto review

我来对这段代码进行审查和分析:

  1. 代码逻辑审查:
  • 在DeviceFactory.cpp中,对CustomType类型的处理增加了PCI显卡检测逻辑,这是一个合理的改进,可以根据硬件特性选择合适的生成器。
  • hasPciGraphicsCard()函数使用了静态变量和互斥锁来确保线程安全和性能优化,这是一个好的设计。
  • main.cpp中的条件判断也相应更新,避免了不必要的GPU信息预生成。
  1. 代码质量建议:
  • hasPciGraphicsCard()函数中的错误处理可以更完善。目前只是设置result为false,但应该记录更详细的错误信息。
  • 建议在DeviceFactory.cpp中添加注释说明为什么CustomType需要特殊处理PCI显卡的情况。
  • QProcess的5秒超时时间可能需要根据实际情况调整或配置化。
  1. 代码性能优化:
  • hasPciGraphicsCard()函数使用了静态变量缓存结果,避免了重复执行lspci命令,这是一个很好的性能优化。
  • 使用了QMutex确保线程安全,但考虑到这是一个只读操作,可以考虑使用QReadWriteLock来提高并发性能。
  1. 代码安全建议:
  • 在执行lspci命令时,建议对命令参数进行验证,虽然当前参数是硬编码的。
  • process.readAllStandardOutput()的结果最好进行大小限制,防止输出过大导致内存问题。
  • 建议添加对lspci命令是否存在进行检查。

具体改进建议:

  1. 在hasPciGraphicsCard()函数中添加更详细的错误日志:
} else if (process.exitCode() != 0) {
    QString error = process.readAllStandardError();
    qCritical() << "Failed to exec lspci, code : " << process.exitCode() 
                << "error: " << error;
    result = false;
}
  1. 添加命令存在性检查:
QProcess which;
which.setProgram("which");
which.setArguments(QStringList() << "lspci");
which.start();
if (!which.waitForFinished(1000) || which.exitCode() != 0) {
    qCritical() << "lspci command not found";
    return false;
}
  1. 考虑使用QReadWriteLock替代QMutex:
static QReadWriteLock lock;
QReadLocker readLocker(&lock);
if (initialized) {
    return result;
}
readLocker.unlock();
QWriteLocker writeLocker(&lock);
if (!initialized) {  // 双重检查
    // ... 执行检测逻辑
}
  1. 在DeviceFactory.cpp中添加注释说明:
else if (type == "CustomType") {
    // 对于定制类型,需要检查是否为PCI显卡平台
    // 如果是PCI显卡平台,使用ARM生成器;否则使用自定义生成器
    if (CommonTools::hasPciGraphicsCard()) {
        generator = new ArmGenerator();
    } else {
        generator = new CustomGenerator();
    }
}

这些改进将使代码更加健壮、安全和高效。

@GongHeng2017
Copy link
Contributor Author

/merge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Dec 1, 2025

This pr cannot be merged! (status: unstable)

@GongHeng2017
Copy link
Contributor Author

/forcemerge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Dec 1, 2025

This pr force merged! (status: unstable)

@deepin-bot deepin-bot bot merged commit c444291 into linuxdeepin:develop/eagle Dec 1, 2025
16 of 18 checks passed
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