Fix GPU detection for NVIDIA and AMD; improve model name retrieval and memory reporting in gpu.zig. Update changelog version
All checks were successful
PikaOS Package Build & Release (amd64-v3) / build (push) Successful in 53s

This commit is contained in:
ferreo 2024-11-30 20:06:19 +00:00
parent f118503903
commit 21e4af01c5
3 changed files with 136 additions and 60 deletions

View File

@ -1 +1 @@
3 1

View File

@ -1,4 +1,4 @@
pikafetch (0.1.0-101pika3) pika; urgency=medium pikafetch (0.1.0-101pika4) pika; urgency=medium
* Initial release. * Initial release.

View File

@ -96,7 +96,7 @@ pub fn getGPUInfo(allocator: mem.Allocator) ![][]const u8 {
} }
}, },
VendorId.AMD, VendorId.AMD_2 => { VendorId.AMD, VendorId.AMD_2 => {
if (try detectAMDGPU(allocator, entry.name)) |gpu| { if (try detectAMDGPU(allocator, entry.name, vendor_id)) |gpu| {
try gpus.append(gpu); try gpus.append(gpu);
continue; continue;
} }
@ -124,67 +124,128 @@ pub fn getGPUInfo(allocator: mem.Allocator) ![][]const u8 {
} }
fn detectNvidiaGPU(allocator: mem.Allocator, card_name: []const u8) !?[]const u8 { fn detectNvidiaGPU(allocator: mem.Allocator, card_name: []const u8) !?[]const u8 {
// First try to get device ID for PCI lookup
const device_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/device", .{card_name});
defer allocator.free(device_path);
const device_file = fs.openFileAbsolute(device_path, .{}) catch return null;
defer device_file.close();
var device_buf: [32]u8 = undefined;
const device_len = device_file.readAll(&device_buf) catch return null;
const device_str = mem.trim(u8, device_buf[0..device_len], "\n\r \t0x");
const device_id = std.fmt.parseInt(u32, device_str, 16) catch return null;
// Try /proc/driver/nvidia first
const proc_path = try allocPrint(allocator, "/proc/driver/nvidia/gpus/{s}/information", .{card_name}); const proc_path = try allocPrint(allocator, "/proc/driver/nvidia/gpus/{s}/information", .{card_name});
defer allocator.free(proc_path); defer allocator.free(proc_path);
const info_file = fs.openFileAbsolute(proc_path, .{}) catch return null;
defer info_file.close();
var buf: [1024]u8 = undefined;
const bytes_read = info_file.readAll(&buf) catch return null;
const content = buf[0..bytes_read];
var model_name: ?[]const u8 = null; var model_name: ?[]const u8 = null;
var vbios_version: ?[]const u8 = null; var vbios_version: ?[]const u8 = null;
var memory_size: ?u64 = null; var memory_size: ?u64 = null;
var lines = mem.split(u8, content, "\n"); // Try to read from nvidia proc
while (lines.next()) |line| { const info_file = fs.openFileAbsolute(proc_path, .{}) catch null;
if (mem.indexOf(u8, line, "Model:")) |_| { if (info_file) |file| {
const start = mem.indexOf(u8, line, ":").? + 1; defer file.close();
model_name = mem.trim(u8, line[start..], " \t\r\n"); var buf: [1024]u8 = undefined;
} else if (mem.indexOf(u8, line, "Video BIOS:")) |_| { const bytes_read = file.readAll(&buf) catch 0;
const start = mem.indexOf(u8, line, ":").? + 1; if (bytes_read > 0) {
vbios_version = mem.trim(u8, line[start..], " \t\r\n"); const content = buf[0..bytes_read];
} else if (mem.indexOf(u8, line, "Video Memory:")) |_| {
const start = mem.indexOf(u8, line, ":").? + 1; var lines = mem.split(u8, content, "\n");
const mem_str = mem.trim(u8, line[start..], " \t\r\nMB"); while (lines.next()) |line| {
memory_size = std.fmt.parseInt(u64, mem_str, 10) catch null; if (mem.indexOf(u8, line, "Model:")) |_| {
const start = mem.indexOf(u8, line, ":").? + 1;
model_name = mem.trim(u8, line[start..], " \t\r\n");
} else if (mem.indexOf(u8, line, "Video BIOS:")) |_| {
const start = mem.indexOf(u8, line, ":").? + 1;
vbios_version = mem.trim(u8, line[start..], " \t\r\n");
} else if (mem.indexOf(u8, line, "Video Memory:")) |_| {
const start = mem.indexOf(u8, line, ":").? + 1;
const mem_str = mem.trim(u8, line[start..], " \t\r\nMB");
memory_size = std.fmt.parseInt(u64, mem_str, 10) catch null;
}
}
} }
} }
if (model_name) |model| { // If we couldn't get model name from nvidia proc, try product name
const gpu_info = GPUInfo{ if (model_name == null) {
.vendor = "NVIDIA", const product_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/product_name", .{card_name});
.model = model, defer allocator.free(product_path);
.driver = vbios_version,
.memory = memory_size, const product_file = fs.openFileAbsolute(product_path, .{}) catch null;
}; if (product_file) |file| {
const formatted = try gpu_info.format(allocator); defer file.close();
return formatted; var product_buf: [256]u8 = undefined;
const len = file.readAll(&product_buf) catch 0;
if (len > 0) {
model_name = mem.trim(u8, product_buf[0..len], "\n\r \t");
}
}
} }
return null; // If still no model name, try PCI lookup
if (model_name == null) {
model_name = if (findPCIName(VendorId.NVIDIA, device_id)) |name|
name
else
try allocPrint(allocator, "NVIDIA GPU (0x{x:0>4})", .{device_id});
}
// Get driver info if not already found from nvidia proc
if (vbios_version == null) {
const driver_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/driver", .{card_name});
defer allocator.free(driver_path);
vbios_version = blk: {
var dir_handle = fs.openDirAbsolute(driver_path, .{}) catch break :blk null;
defer dir_handle.close();
var path_buf: [256]u8 = undefined;
const path = dir_handle.readLink("driver", &path_buf) catch break :blk null;
break :blk std.fs.path.basename(path);
};
}
const gpu_info = GPUInfo{
.vendor = "NVIDIA",
.model = model_name.?, // Safe because we always set it above
.driver = vbios_version,
.memory = memory_size,
};
const formatted = try gpu_info.format(allocator);
return formatted;
} }
fn detectAMDGPU(allocator: mem.Allocator, card_name: []const u8) !?[]const u8 { fn detectAMDGPU(allocator: mem.Allocator, card_name: []const u8, vendor_id: u32) !?[]const u8 {
const product_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/product_name", .{card_name}); // Get device ID
defer allocator.free(product_path); const device_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/device", .{card_name});
defer allocator.free(device_path);
var product_name: []const u8 = undefined; const device_file = fs.openFileAbsolute(device_path, .{}) catch return null;
if (fs.openFileAbsolute(product_path, .{})) |product_file| { defer device_file.close();
defer product_file.close();
var product_buf: [256]u8 = undefined;
const product_len = product_file.readAll(&product_buf) catch return null;
product_name = mem.trim(u8, product_buf[0..product_len], "\n\r \t");
} else |_| {
return null;
}
const driver_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/driver", .{card_name}); var device_buf: [32]u8 = undefined;
defer allocator.free(driver_path); const device_len = device_file.readAll(&device_buf) catch return null;
const device_str = mem.trim(u8, device_buf[0..device_len], "\n\r \t0x");
const device_id = std.fmt.parseInt(u32, device_str, 16) catch return null;
// Get model name from PCI database
const model_name = if (findPCIName(vendor_id, device_id)) |name|
name
else
try allocPrint(allocator, "GPU (0x{x:0>4})", .{device_id});
// Get driver info
const driver = blk: { const driver = blk: {
const driver_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/driver", .{card_name});
defer allocator.free(driver_path);
var dir_handle = fs.openDirAbsolute(driver_path, .{}) catch break :blk null; var dir_handle = fs.openDirAbsolute(driver_path, .{}) catch break :blk null;
defer dir_handle.close(); defer dir_handle.close();
@ -193,11 +254,27 @@ fn detectAMDGPU(allocator: mem.Allocator, card_name: []const u8) !?[]const u8 {
break :blk std.fs.path.basename(path); break :blk std.fs.path.basename(path);
}; };
// Get VRAM info
var memory: ?u64 = null;
const vram_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/mem_info_vram_total", .{card_name});
defer allocator.free(vram_path);
if (fs.openFileAbsolute(vram_path, .{})) |vram_file| {
defer vram_file.close();
var vram_buf: [32]u8 = undefined;
if (vram_file.readAll(&vram_buf)) |len| {
const vram_str = mem.trim(u8, vram_buf[0..len], "\n\r \t");
if (std.fmt.parseInt(u64, vram_str, 10)) |vram_bytes| {
memory = vram_bytes / (1024 * 1024); // Convert to MB
} else |_| {}
} else |_| {}
} else |_| {}
const gpu_info = GPUInfo{ const gpu_info = GPUInfo{
.vendor = "AMD", .vendor = "AMD",
.model = product_name, .model = model_name,
.driver = driver, .driver = driver,
.memory = null, .memory = memory,
}; };
const formatted = try gpu_info.format(allocator); const formatted = try gpu_info.format(allocator);
@ -247,26 +324,25 @@ fn findPCIName(vendor_id: u32, device_id: u32) ?[]const u8 {
var current_vendor: ?u32 = null; var current_vendor: ?u32 = null;
while (lines.next()) |line| { while (lines.next()) |line| {
const trimmed = mem.trim(u8, line, " \t\r"); const trimmed = mem.trim(u8, line, " \r\n");
if (trimmed.len == 0 or trimmed[0] == '#') continue; if (trimmed.len == 0 or trimmed[0] == '#') continue;
// Check if this is a vendor line (no tabs at start) // Count leading tabs
if (trimmed[0] != '\t') { const tab_count = for (trimmed, 0..) |c, i| {
// Parse vendor ID if (c != '\t') break @as(usize, @intCast(i));
} else trimmed.len;
// No tabs = vendor line
if (tab_count == 0) {
const space_idx = mem.indexOf(u8, trimmed, " ") orelse continue; const space_idx = mem.indexOf(u8, trimmed, " ") orelse continue;
const vendor_str = trimmed[0..space_idx]; const vendor_str = trimmed[0..space_idx];
current_vendor = std.fmt.parseInt(u32, vendor_str, 16) catch continue; current_vendor = std.fmt.parseInt(u32, vendor_str, 16) catch continue;
continue; continue;
} }
// If we found our vendor, look for the device // One tab = device line
if (current_vendor) |vendor| { if (tab_count == 1 and current_vendor != null and current_vendor.? == vendor_id) {
if (vendor != vendor_id) continue; const device_line = trimmed[tab_count..];
// Device lines have one tab
if (trimmed[0] != '\t' or trimmed.len < 2) continue;
const device_line = mem.trim(u8, trimmed[1..], " \t");
const space_idx = mem.indexOf(u8, device_line, " ") orelse continue; const space_idx = mem.indexOf(u8, device_line, " ") orelse continue;
const device_str = device_line[0..space_idx]; const device_str = device_line[0..space_idx];
const found_device = std.fmt.parseInt(u32, device_str, 16) catch continue; const found_device = std.fmt.parseInt(u32, device_str, 16) catch continue;