refactor(cli): Remove progress UI and update native/server code

Delete cli/src/ui/progress.zig (removing progress bars/spinners)

Update native GPU detection modules

Update server experiment API
This commit is contained in:
Jeremie Fraeys 2026-02-23 14:12:48 -05:00
parent fd317c9791
commit 6faa13aabf
No known key found for this signature in database
4 changed files with 16 additions and 167 deletions

View file

@ -229,28 +229,28 @@ pub fn formatMacOSGPUInfo(allocator: std.mem.Allocator, gpus: []const MacOSGPUIn
const name = std.mem.sliceTo(&gpu.name, 0);
const model = std.mem.sliceTo(&gpu.chipset_model, 0);
try writer.print("🎮 GPU {d}: {s}\n", .{ gpu.index, name });
try writer.print("GPU {d}: {s}\n", .{ gpu.index, name });
if (!std.mem.eql(u8, model, name)) {
try writer.print(" Model: {s}\n", .{model});
try writer.print("\tModel: {s}\n", .{model});
}
if (gpu.is_integrated) {
try writer.writeAll(" Type: Integrated (Unified Memory)\n");
try writer.writeAll("\tType: Integrated (Unified Memory)\n");
} else {
try writer.print(" VRAM: {d} MB\n", .{gpu.vram_mb});
try writer.print("\tVRAM: {d} MB\n", .{gpu.vram_mb});
}
if (gpu.utilization_percent) |util| {
try writer.print(" Utilization: {d}%\n", .{util});
try writer.print("\tUtilization: {d}%\n", .{util});
}
if (gpu.temperature_celsius) |temp| {
try writer.print(" Temperature: {d}°C\n", .{temp});
try writer.print("\tTemperature: {d}°C\n", .{temp});
}
if (gpu.power_mw) |power| {
try writer.print(" Power: {d:.1f} W\n", .{@as(f64, @floatFromInt(power)) / 1000.0});
try writer.print("\tPower: {d:.1f} W\n", .{@as(f64, @floatFromInt(power)) / 1000.0});
}
try writer.writeAll("\n");
}
try writer.writeAll("💡 Note: Detailed GPU metrics require powermetrics (sudo)\n");
try writer.writeAll("Note: Detailed GPU metrics require powermetrics (sudo)\n");
return buf.toOwnedSlice();
}

View file

@ -352,18 +352,18 @@ pub fn formatGPUInfo(allocator: std.mem.Allocator, gpus: []const GPUInfo) ![]u8
for (gpus) |gpu| {
const name = std.mem.sliceTo(&gpu.name, 0);
try writer.print("🎮 GPU {d}: {s}\n", .{ gpu.index, name });
try writer.print(" Utilization: {d}%\n", .{gpu.utilization});
try writer.print(" Memory: {d}/{d} MB\n", .{
try writer.print("GPU {d}: {s}\n", .{ gpu.index, name });
try writer.print("\tUtilization: {d}%\n", .{gpu.utilization});
try writer.print("\tMemory: {d}/{d} MB\n", .{
gpu.memory_used / 1024 / 1024,
gpu.memory_total / 1024 / 1024,
});
try writer.print(" Temperature: {d}°C\n", .{gpu.temperature});
try writer.print("\tTemperature: {d}°C\n", .{gpu.temperature});
if (gpu.power_draw > 0) {
try writer.print(" Power: {d:.1} W\n", .{@as(f64, @floatFromInt(gpu.power_draw)) / 1000.0});
try writer.print("\tPower: {d:.1} W\n", .{@as(f64, @floatFromInt(gpu.power_draw)) / 1000.0});
}
if (gpu.clock_sm > 0) {
try writer.print(" SM Clock: {d} MHz\n", .{gpu.clock_sm});
try writer.print("\tSM Clock: {d} MHz\n", .{gpu.clock_sm});
}
try writer.writeAll("\n");
}

View file

@ -113,8 +113,8 @@ pub fn list(allocator: std.mem.Allocator, json: bool) !void {
while (idx < max_display) : (idx += 1) {
const entry = entries[entries.len - idx - 1];
std.debug.print("{d:2}) Alias: {s}\n", .{ idx + 1, entry.job_name });
std.debug.print(" Commit: {s}\n", .{entry.commit_id});
std.debug.print(" Queued: {d}\n\n", .{entry.queued_at});
std.debug.print("\t\tCommit: {s}\n", .{entry.commit_id});
std.debug.print("\t\tQueued: {d}\n\n", .{entry.queued_at});
}
if (entries.len > max_display) {

View file

@ -1,151 +0,0 @@
const std = @import("std");
const colors = @import("../utils/colors.zig");
/// ProgressBar provides visual feedback for long-running operations.
/// It displays progress as a percentage, item count, and throughput rate.
pub const ProgressBar = struct {
total: usize,
current: usize,
label: []const u8,
start_time: i64,
width: usize,
/// Initialize a new progress bar
pub fn init(total: usize, label: []const u8) ProgressBar {
return .{
.total = total,
.current = 0,
.label = label,
.start_time = std.time.milliTimestamp(),
.width = 40, // Default bar width
};
}
/// Update the progress bar with current progress
pub fn update(self: *ProgressBar, current: usize) void {
self.current = current;
self.render();
}
/// Increment progress by one step
pub fn increment(self: *ProgressBar) void {
self.current += 1;
self.render();
}
/// Render the progress bar to stderr
fn render(self: ProgressBar) void {
const percent = if (self.total > 0)
@divFloor(self.current * 100, self.total)
else
0;
const elapsed_ms = std.time.milliTimestamp() - self.start_time;
const rate = if (elapsed_ms > 0 and self.current > 0)
@as(f64, @floatFromInt(self.current)) / (@as(f64, @floatFromInt(elapsed_ms)) / 1000.0)
else
0.0;
// Build progress bar
const filled = if (self.total > 0)
@divFloor(self.current * self.width, self.total)
else
0;
const empty = self.width - filled;
var bar_buf: [64]u8 = undefined;
var bar_stream = std.io.fixedBufferStream(&bar_buf);
const bar_writer = bar_stream.writer();
// Write filled portion
var i: usize = 0;
while (i < filled) : (i += 1) {
_ = bar_writer.write("=") catch {};
}
// Write empty portion
i = 0;
while (i < empty) : (i += 1) {
_ = bar_writer.write("-") catch {};
}
const bar = bar_stream.getWritten();
// Clear line and print progress
const stderr = std.io.getStdErr().writer();
stderr.print("\r{s} [{s}] {d}/{d} {d}% ({d:.1} items/s)", .{
self.label,
bar,
self.current,
self.total,
percent,
rate,
}) catch {};
}
/// Finish the progress bar and print a newline
pub fn finish(self: ProgressBar) void {
self.render();
const stderr = std.io.getStdErr().writer();
stderr.print("\n", .{}) catch {};
}
/// Complete with a success message
pub fn success(self: ProgressBar, msg: []const u8) void {
self.current = self.total;
self.render();
colors.printSuccess("\n{s}\n", .{msg});
}
/// Get elapsed time in milliseconds
pub fn elapsedMs(self: ProgressBar) i64 {
return std.time.milliTimestamp() - self.start_time;
}
/// Get current throughput (items per second)
pub fn throughput(self: ProgressBar) f64 {
const elapsed_ms = self.elapsedMs();
if (elapsed_ms > 0 and self.current > 0) {
return @as(f64, @floatFromInt(self.current)) / (@as(f64, @floatFromInt(elapsed_ms)) / 1000.0);
}
return 0.0;
}
};
/// Spinner provides visual feedback for indeterminate operations
pub const Spinner = struct {
label: []const u8,
start_time: i64,
frames: []const u8,
frame_idx: usize,
const DEFAULT_FRAMES = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
pub fn init(label: []const u8) Spinner {
return .{
.label = label,
.start_time = std.time.milliTimestamp(),
.frames = DEFAULT_FRAMES,
.frame_idx = 0,
};
}
/// Render one frame of the spinner
pub fn tick(self: *Spinner) void {
const frame = self.frames[self.frame_idx % self.frames.len];
const stderr = std.io.getStdErr().writer();
stderr.print("\r{s} {c} ", .{ self.label, frame }) catch {};
self.frame_idx += 1;
}
/// Stop the spinner and print a newline
pub fn stop(self: Spinner) void {
_ = self; // Intentionally unused - for API consistency
const stderr = std.io.getStdErr().writer();
stderr.print("\n", .{}) catch {};
}
/// Get elapsed time in seconds
pub fn elapsedSec(self: Spinner) i64 {
return @divFloor(std.time.milliTimestamp() - self.start_time, 1000);
}
};