From 946c64d5ab29bd472fdd5b04f94d656b2e374d41 Mon Sep 17 00:00:00 2001 From: ferreo Date: Sat, 30 Nov 2024 19:22:08 +0000 Subject: [PATCH] Update GPU functions to support multiple GPUs and adjust system info structure accordingly --- .github/release-nest-v3 | 2 +- pikafetch/debian/changelog | 2 +- pikafetch/src/system/hardware/gpu.zig | 213 ++++++++++-------- pikafetch/src/system/hardware/motherboard.zig | 20 +- pikafetch/src/system/info.zig | 33 ++- 5 files changed, 156 insertions(+), 114 deletions(-) diff --git a/.github/release-nest-v3 b/.github/release-nest-v3 index 56a6051..d8263ee 100644 --- a/.github/release-nest-v3 +++ b/.github/release-nest-v3 @@ -1 +1 @@ -1 \ No newline at end of file +2 \ No newline at end of file diff --git a/pikafetch/debian/changelog b/pikafetch/debian/changelog index 768d9fa..2e28ae9 100644 --- a/pikafetch/debian/changelog +++ b/pikafetch/debian/changelog @@ -1,4 +1,4 @@ -pikafetch (0.1.0-101pika1) pika; urgency=medium +pikafetch (0.1.0-101pika2) pika; urgency=medium * Initial release. diff --git a/pikafetch/src/system/hardware/gpu.zig b/pikafetch/src/system/hardware/gpu.zig index fbc9fc3..c1cdc3c 100644 --- a/pikafetch/src/system/hardware/gpu.zig +++ b/pikafetch/src/system/hardware/gpu.zig @@ -1,118 +1,131 @@ const std = @import("std"); -pub fn getGPUInfo(allocator: std.mem.Allocator) ![]const u8 { - const vendor_file = std.fs.openFileAbsolute("/sys/class/drm/card0/device/vendor", .{}) catch |err| switch (err) { - error.FileNotFound => return allocator.dupe(u8, "Unknown GPU"), - else => return err, - }; - defer vendor_file.close(); - - const device_file = std.fs.openFileAbsolute("/sys/class/drm/card0/device/device", .{}) catch |err| switch (err) { - error.FileNotFound => return allocator.dupe(u8, "Unknown GPU"), - else => return err, - }; - defer device_file.close(); - - var vendor_buf: [32]u8 = undefined; - var device_buf: [32]u8 = undefined; - - const vendor_bytes = try vendor_file.readAll(&vendor_buf); - const device_bytes = try device_file.readAll(&device_buf); - - const vendor_str = std.mem.trim(u8, vendor_buf[0..vendor_bytes], "\n\r \t0x"); - const device_str = std.mem.trim(u8, device_buf[0..device_bytes], "\n\r \t0x"); - - const vendor_id = try std.fmt.parseInt(u32, vendor_str, 16); - const device_id = try std.fmt.parseInt(u32, device_str, 16); - - const modalias_file = std.fs.openFileAbsolute("/sys/class/drm/card0/device/modalias", .{}) catch |err| switch (err) { - error.FileNotFound => null, - else => return err, - }; - defer if (modalias_file) |f| f.close(); - - const name_file = std.fs.openFileAbsolute("/sys/class/drm/card0/device/product", .{}) catch |err| switch (err) { - error.FileNotFound => null, - else => return err, - }; - defer if (name_file) |f| f.close(); - - const model_file = std.fs.openFileAbsolute("/sys/class/drm/card0/device/model", .{}) catch |err| switch (err) { - error.FileNotFound => null, - else => return err, - }; - defer if (model_file) |f| f.close(); - - const subsystem_file = std.fs.openFileAbsolute("/sys/class/drm/card0/device/subsystem_device", .{}) catch |err| switch (err) { - error.FileNotFound => null, - else => return err, - }; - defer if (subsystem_file) |f| f.close(); - - var name_buf: [256]u8 = undefined; - var gpu_name: []const u8 = ""; - - if (name_file) |f| { - const name_bytes = try f.readAll(&name_buf); - const name = std.mem.trim(u8, name_buf[0..name_bytes], "\n\r \t"); - if (name.len > 0) { - gpu_name = name; +pub fn getGPUInfo(allocator: std.mem.Allocator) ![][]const u8 { + var gpus = std.ArrayList([]const u8).init(allocator); + errdefer { + for (gpus.items) |gpu| { + allocator.free(gpu); } + gpus.deinit(); } - if (gpu_name.len == 0) { - if (model_file) |f| { + var card_num: u32 = 0; + while (true) : (card_num += 1) { + const card_path = try std.fmt.allocPrint(allocator, "/sys/class/drm/card{d}/device", .{card_num}); + defer allocator.free(card_path); + + const vendor_file = std.fs.openFileAbsolute(try std.fmt.allocPrint(allocator, "{s}/vendor", .{card_path}), .{}) catch |err| switch (err) { + error.FileNotFound => break, // No more cards found + else => return err, + }; + defer vendor_file.close(); + + const device_file = std.fs.openFileAbsolute(try std.fmt.allocPrint(allocator, "{s}/device", .{card_path}), .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => return err, + }; + defer device_file.close(); + + var vendor_buf: [32]u8 = undefined; + var device_buf: [32]u8 = undefined; + + const vendor_bytes = try vendor_file.readAll(&vendor_buf); + const device_bytes = try device_file.readAll(&device_buf); + + const vendor_str = std.mem.trim(u8, vendor_buf[0..vendor_bytes], "\n\r \t0x"); + const device_str = std.mem.trim(u8, device_buf[0..device_bytes], "\n\r \t0x"); + + const vendor_id = try std.fmt.parseInt(u32, vendor_str, 16); + const device_id = try std.fmt.parseInt(u32, device_str, 16); + + const modalias_file = std.fs.openFileAbsolute(try std.fmt.allocPrint(allocator, "/sys/class/drm/card{d}/device/modalias", .{card_num}), .{}) catch |err| switch (err) { + error.FileNotFound => null, + else => return err, + }; + defer if (modalias_file) |f| f.close(); + + const name_file = std.fs.openFileAbsolute(try std.fmt.allocPrint(allocator, "/sys/class/drm/card{d}/device/product", .{card_num}), .{}) catch |err| switch (err) { + error.FileNotFound => null, + else => return err, + }; + defer if (name_file) |f| f.close(); + + const model_file = std.fs.openFileAbsolute(try std.fmt.allocPrint(allocator, "/sys/class/drm/card{d}/device/model", .{card_num}), .{}) catch |err| switch (err) { + error.FileNotFound => null, + else => return err, + }; + defer if (model_file) |f| f.close(); + + const subsystem_file = std.fs.openFileAbsolute(try std.fmt.allocPrint(allocator, "/sys/class/drm/card{d}/device/subsystem_device", .{card_num}), .{}) catch |err| switch (err) { + error.FileNotFound => null, + else => return err, + }; + defer if (subsystem_file) |f| f.close(); + + var name_buf: [256]u8 = undefined; + var gpu_name: []const u8 = ""; + + if (name_file) |f| { const name_bytes = try f.readAll(&name_buf); const name = std.mem.trim(u8, name_buf[0..name_bytes], "\n\r \t"); if (name.len > 0) { gpu_name = name; } } - } - if (findPCIName(vendor_id, device_id)) |model| { - return std.fmt.allocPrint(allocator, "{s} {s}", .{ switch (vendor_id) { - 0x1002 => "AMD", - 0x10de => "NVIDIA", - 0x8086 => "Intel", - else => "Unknown", - }, model }); - } - - const driver_dir = std.fs.openDirAbsolute("/sys/class/drm/card0/device", .{}) catch |err| switch (err) { - error.FileNotFound => null, - else => return err, - }; - if (driver_dir) |d| { - defer { - var dir = d; - dir.close(); + if (gpu_name.len == 0) { + if (model_file) |f| { + const name_bytes = try f.readAll(&name_buf); + const name = std.mem.trim(u8, name_buf[0..name_bytes], "\n\r \t"); + if (name.len > 0) { + gpu_name = name; + } + } } - var path_buf: [256]u8 = undefined; - const path = d.readLink("driver", &path_buf) catch |err| switch (err) { - error.FileNotFound => return std.fmt.allocPrint(allocator, "{s} GPU (0x{x:0>4})", .{ switch (vendor_id) { - 0x1002 => "AMD", - 0x10de => "NVIDIA", - 0x8086 => "Intel", - else => "Unknown", - }, device_id }), - else => return err, - }; - const driver = std.fs.path.basename(path); - return std.fmt.allocPrint(allocator, "{s} (0x{x:0>4}, {s})", .{ switch (vendor_id) { - 0x1002 => "AMD", - 0x10de => "NVIDIA", - 0x8086 => "Intel", - else => "Unknown", - }, device_id, driver }); + + // Declare and initialize the driver variable + var dir_handle = std.fs.openDirAbsolute(card_path, .{}) catch null; + const driver = if (dir_handle) |*dir| blk: { + defer dir.close(); + var path_buf: [256]u8 = undefined; + if (dir.readLink("driver", &path_buf)) |path| { + break :blk std.fs.path.basename(path); + } else |_| { + break :blk null; + } + } else null; + + const gpu_info = if (findPCIName(vendor_id, device_id)) |model| + try std.fmt.allocPrint(allocator, "{s} {s}", .{ + switch (vendor_id) { + 0x1002 => "AMD", + 0x10de => "NVIDIA", + 0x8086 => "Intel", + else => "Unknown", + }, + model, + }) + else + try std.fmt.allocPrint(allocator, "{s} GPU (0x{x:0>4}){s}", .{ + switch (vendor_id) { + 0x1002 => "AMD", + 0x10de => "NVIDIA", + 0x8086 => "Intel", + else => "Unknown", + }, + device_id, + if (driver) |d| try std.fmt.allocPrint(allocator, ", {s}", .{d}) else "", + }); + + try gpus.append(gpu_info); } - return std.fmt.allocPrint(allocator, "{s} GPU (0x{x:0>4})", .{ switch (vendor_id) { - 0x1002 => "AMD", - 0x10de => "NVIDIA", - 0x8086 => "Intel", - else => "Unknown", - }, device_id }); + if (gpus.items.len == 0) { + const unknown = try allocator.dupe(u8, "Unknown GPU"); + try gpus.append(unknown); + } + + return gpus.toOwnedSlice(); } const pci_ids = @embedFile("../../data/pci.ids"); diff --git a/pikafetch/src/system/hardware/motherboard.zig b/pikafetch/src/system/hardware/motherboard.zig index c5d3e76..fa53d26 100644 --- a/pikafetch/src/system/hardware/motherboard.zig +++ b/pikafetch/src/system/hardware/motherboard.zig @@ -1,10 +1,22 @@ const std = @import("std"); pub fn getMotherboard(allocator: std.mem.Allocator) ![]const u8 { - const product_name = try std.fs.openFileAbsolute("/sys/class/dmi/id/product_name", .{}); - defer product_name.close(); + // Try board_name first as it's usually more reliable + const board_name = try std.fs.openFileAbsolute("/sys/class/dmi/id/board_name", .{}); + defer board_name.close(); var buffer: [256]u8 = undefined; - const size = try product_name.readAll(&buffer); - return allocator.dupe(u8, std.mem.trim(u8, buffer[0..size], "\n\r ")); + const size = try board_name.readAll(&buffer); + const name = std.mem.trim(u8, buffer[0..size], "\n\r "); + + // If board_name is empty or generic, try product_name as fallback + if (name.len == 0) { + const product_name = try std.fs.openFileAbsolute("/sys/class/dmi/id/product_name", .{}); + defer product_name.close(); + + const product_size = try product_name.readAll(&buffer); + return allocator.dupe(u8, std.mem.trim(u8, buffer[0..product_size], "\n\r ")); + } + + return allocator.dupe(u8, name); } diff --git a/pikafetch/src/system/info.zig b/pikafetch/src/system/info.zig index c2ad602..311da0f 100644 --- a/pikafetch/src/system/info.zig +++ b/pikafetch/src/system/info.zig @@ -25,7 +25,7 @@ pub const SystemInfo = struct { packages: u32, wm: []const u8, terminal: []const u8, - gpu: []const u8, + gpus: [][]const u8, swap_total: u64, swap_used: u64, disk_total: u64, @@ -41,7 +41,7 @@ pub const SystemInfo = struct { var host: ?[]const u8 = null; var wm_name: ?[]const u8 = null; var terminal_name: ?[]const u8 = null; - var gpu_info: ?[]const u8 = null; + var gpu_list: ?[][]const u8 = null; var shell_info: ?[]const u8 = null; var cpu_info: ?[]const u8 = null; @@ -53,7 +53,10 @@ pub const SystemInfo = struct { if (host) |h| allocator.free(h); if (wm_name) |w| allocator.free(w); if (terminal_name) |t| allocator.free(t); - if (gpu_info) |g| allocator.free(g); + if (gpu_list) |list| { + for (list) |g| allocator.free(g); + allocator.free(list); + } if (shell_info) |s| allocator.free(s); if (cpu_info) |c| allocator.free(c); } @@ -67,7 +70,7 @@ pub const SystemInfo = struct { const pkg_count = try packages.getDpkgCount(); wm_name = try wm.getWM(allocator); terminal_name = try terminal.getTerminal(allocator); - gpu_info = try gpu.getGPUInfo(allocator); + gpu_list = try gpu.getGPUInfo(allocator); const shell_data = try shell.getShellInfo(allocator); shell_info = shell_data.name; cpu_info = try cpu.getCPUInfo(allocator); @@ -88,7 +91,7 @@ pub const SystemInfo = struct { .packages = pkg_count, .wm = wm_name.?, .terminal = terminal_name.?, - .gpu = gpu_info.?, + .gpus = gpu_list.?, .swap_total = swap_info.total, .swap_used = swap_info.used, .disk_total = disk_info.total, @@ -106,13 +109,16 @@ pub const SystemInfo = struct { self.allocator.free(self.host); self.allocator.free(self.wm); self.allocator.free(self.terminal); - self.allocator.free(self.gpu); + for (self.gpus) |gpu_info| { + self.allocator.free(gpu_info); + } + self.allocator.free(self.gpus); self.allocator.free(self.shell_name); self.allocator.free(self.cpu_info); } pub fn formatInfo(self: *const SystemInfo) ![]const []const u8 { - var info = try std.ArrayList([]const u8).initCapacity(self.allocator, 14); + var info = try std.ArrayList([]const u8).initCapacity(self.allocator, 13 + self.gpus.len); errdefer { for (info.items) |item| { @@ -160,7 +166,18 @@ pub const SystemInfo = struct { try std.fmt.allocPrint(self.allocator, "{s}WM:{s} {s}", .{ colors.Color.bold, colors.Color.reset, self.wm }), try std.fmt.allocPrint(self.allocator, "{s}Terminal:{s} {s}", .{ colors.Color.bold, colors.Color.reset, self.terminal }), try std.fmt.allocPrint(self.allocator, "{s}CPU:{s} {s}", .{ colors.Color.bold, colors.Color.reset, self.cpu_info }), - try std.fmt.allocPrint(self.allocator, "{s}GPU:{s} {s}", .{ colors.Color.bold, colors.Color.reset, self.gpu }), + }); + + for (self.gpus, 0..) |gpu_info, i| { + try info.append(try std.fmt.allocPrint(self.allocator, "{s}GPU{s}{s}: {s}", .{ + colors.Color.bold, + if (self.gpus.len > 1) try std.fmt.allocPrint(self.allocator, " {d}", .{i + 1}) else "", + colors.Color.reset, + gpu_info, + })); + } + + try info.appendSlice(&[_][]const u8{ try std.fmt.allocPrint(self.allocator, "{s}Memory:{s} {d:.2} {s} / {d:.2} {s} ({s}{d}%{s})", .{ colors.Color.bold, colors.Color.reset, calculations.mem_fmt.value, calculations.mem_fmt.unit,