Skip to content

Commit

Permalink
gpu: display all gpus by default and let user pick active gpu
Browse files Browse the repository at this point in the history
if user has dual gpu setup and wants to select only one gpu,
he can use either pci_dev or gpu_list

if both pci_dev and gpu_list are specified, use only gpu_list
and print a warning

since some code still relies on active gpu like fps logging,
throttling and vram graph, make user be able to
select active gpu. if no gpu is active, pick last from list
of available gpus.
  • Loading branch information
17314642 committed Dec 15, 2024
1 parent 33c0530 commit f5d7c0c
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 34 deletions.
7 changes: 5 additions & 2 deletions data/MangoHud.conf
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,12 @@ text_outline
# battery_color=FF9078
# network_color=E07B85

### Specify GPU with PCI bus ID for AMDGPU and NVML stats
### Specify GPU with PCI bus ID
### Set to 'domain:bus:slot.function'
# pci_dev=0:0a:0.0
### Example:
### $ lspci | grep A770
### 03:00.0 VGA compatible controller: Intel Corporation DG2 [Arc A770] (rev 08)
# pci_dev=0000:03:00.0

### Blacklist
# blacklist=
Expand Down
58 changes: 46 additions & 12 deletions src/gpu.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "gpu.h"
#include <cstdint>
#include <inttypes.h>
#include <memory>
#include <functional>
Expand All @@ -22,16 +23,17 @@ GPUS::GPUS(overlay_params* params) : params(params) {
std::vector<std::string> gpu_entries;

for (const auto& entry : fs::directory_iterator("/sys/class/drm")) {
if (entry.is_directory()) {
std::string node_name = entry.path().filename().string();

// Check if the directory is a render node (e.g., renderD128, renderD129, etc.)
if (node_name.find("renderD") == 0 && node_name.length() > 7) {
// Ensure the rest of the string after "renderD" is numeric
std::string render_number = node_name.substr(7);
if (std::all_of(render_number.begin(), render_number.end(), ::isdigit)) {
gpu_entries.push_back(node_name); // Store the render entry
}
if (!entry.is_directory())
continue;

std::string node_name = entry.path().filename().string();

// Check if the directory is a render node (e.g., renderD128, renderD129, etc.)
if (node_name.find("renderD") == 0 && node_name.length() > 7) {
// Ensure the rest of the string after "renderD" is numeric
std::string render_number = node_name.substr(7);
if (std::all_of(render_number.begin(), render_number.end(), ::isdigit)) {
gpu_entries.push_back(node_name); // Store the render entry
}
}
}
Expand All @@ -44,6 +46,8 @@ GPUS::GPUS(overlay_params* params) : params(params) {
});

// Now process the sorted GPU entries
uint8_t idx = 0, total_active = 0;

for (const auto& node_name : gpu_entries) {
std::string path = "/sys/class/drm/" + node_name;
std::string device_address = get_pci_device_address(path); // Store the result
Expand All @@ -56,18 +60,48 @@ GPUS::GPUS(overlay_params* params) : params(params) {
} catch(...) {
SPDLOG_ERROR("stoul failed on: {}", "/sys/bus/pci/devices/" + device_address + "/vendor");
}

try {
device_id = std::stoul(read_line("/sys/bus/pci/devices/" + device_address + "/device"), nullptr, 16);
} catch (...) {
SPDLOG_ERROR("stoul failed on: {}", "/sys/bus/pci/devices/" + device_address + "/device");
}

std::shared_ptr<GPU> ptr = std::make_shared<GPU>(node_name, vendor_id, device_id, pci_dev);

if (params->gpu_list.size() == 1 && params->gpu_list[0] == idx++)
ptr->is_active = true;

if (!params->pci_dev.empty() && pci_dev == params->pci_dev)
ptr->is_active = true;

available_gpus.emplace_back(ptr);

SPDLOG_INFO("GPU Found: node_name: {}, vendor_id: {:x} device_id: {:x} pci_dev: {}", node_name, vendor_id, device_id, pci_dev);

if (ptr->is_active) {
SPDLOG_INFO("Set {} as active GPU (id={:x}:{:x} pci_dev={})", node_name, vendor_id, device_id, pci_dev);
total_active++;
}
}

if (total_active < 2)
return;

for (auto& gpu : available_gpus) {
if (!gpu->is_active)
continue;

SPDLOG_WARN(
"You have more than 1 active GPU, check if you use both pci_dev "
"and gpu_list. If you use fps logging, MangoHud will log only "
"this GPU: name = {}, vendor = {:x}, pci_dev = {}",
gpu->name, gpu->vendor_id, gpu->pci_dev
);

break;
}

}

std::string GPU::is_i915_or_xe() {
Expand Down Expand Up @@ -120,7 +154,7 @@ std::string GPUS::get_pci_device_address(const std::string& drm_card_path) {

int GPU::index_in_selected_gpus() {
auto selected_gpus = gpus->selected_gpus();
auto it = std::find_if(selected_gpus.begin(), selected_gpus.end(),
auto it = std::find_if(selected_gpus.begin(), selected_gpus.end(),
[this](const std::shared_ptr<GPU>& gpu) {
return gpu.get() == this;
});
Expand Down
49 changes: 30 additions & 19 deletions src/gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class GPU {
std::unique_ptr<NVIDIA> nvidia = nullptr;
std::unique_ptr<AMDGPU> amdgpu = nullptr;
std::unique_ptr<GPU_fdinfo> fdinfo = nullptr;
bool is_active;
bool is_active = false;
std::string pci_dev;
uint32_t vendor_id;
uint32_t vendor_id = 0;

GPU(std::string name, uint32_t vendor_id, uint32_t device_id, const char* pci_dev)
: name(name), pci_dev(pci_dev), vendor_id(vendor_id), device_id(device_id) {
Expand Down Expand Up @@ -136,18 +136,17 @@ class GPUS {
}

std::shared_ptr<GPU> active_gpu() {
if (!available_gpus.empty()){
for (auto gpu : available_gpus) {
if (gpu->is_active) {
return gpu;
}
}
}
// if no GPU is marked as active, just set it to the first one
if (available_gpus.size() > 0)
return available_gpus.front();
else
if (available_gpus.empty())
return nullptr;

for (auto gpu : available_gpus) {
if (gpu->is_active)
return gpu;
}

// if no GPU is marked as active, just set it to the last one
// because integrated gpus are usually first
return available_gpus.back();
}

void update_throttling() {
Expand All @@ -165,18 +164,30 @@ class GPUS {
std::vector<std::shared_ptr<GPU>> selected_gpus() {
std::lock_guard<std::mutex> lock(mutex);
std::vector<std::shared_ptr<GPU>> vec;

if (params->gpu_list.empty() && params->pci_dev.empty())
return available_gpus;

if (!params->gpu_list.empty()) {
for (unsigned index : params->gpu_list) {
if (index < available_gpus.size()) {
if (available_gpus[index])
vec.push_back(available_gpus[index]);
}
}
}

return vec;
}

if (!params->pci_dev.empty()) {
for (auto &gpu : available_gpus) {
if (gpu->pci_dev == params->pci_dev) {
vec.push_back(gpu);
return vec;
}
}
// if the user hasn't selected any GPUs, we use the active one
} else {
if (active_gpu())
vec.push_back(active_gpu());


return vec;
}

return vec;
Expand Down
2 changes: 1 addition & 1 deletion src/gpu_fdinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#ifdef TEST_ONLY
#include <../src/mesa/util/os_time.h>
#else
#include <mesa/util/os_time.h>
#include "mesa/util/os_time.h"
#endif

#include "gpu_metrics_util.h"
Expand Down
7 changes: 7 additions & 0 deletions src/overlay_params.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,13 @@ parse_overlay_config(struct overlay_params *params,
if (HUDElements.net)
HUDElements.net->should_reset = true;

if (!params->gpu_list.empty() && !params->pci_dev.empty()) {
SPDLOG_WARN(
"You have specified both gpu_list and pci_dev, "
"ignoring pci_dev."
);
}

{
std::lock_guard<std::mutex> lock(config_mtx);
config_ready = true;
Expand Down

0 comments on commit f5d7c0c

Please sign in to comment.