Skip to content

Instantly share code, notes, and snippets.

@notcancername
Created July 18, 2025 05:42
Show Gist options
  • Save notcancername/fc3b8d6cb6e308d8b39f2891cba88e23 to your computer and use it in GitHub Desktop.
Save notcancername/fc3b8d6cb6e308d8b39f2891cba88e23 to your computer and use it in GitHub Desktop.
pub const std = @import("std");
pub const dvui = @import("dvui");
const Backend = dvui.backend;
pub const tardy = @import("tardy");
const Tardy = tardy.Tardy(.io_uring);
const Runtime = tardy.Runtime;
const Socket = tardy.Socket;
const Timer = tardy.Timer;
const DataMap = std.StringArrayHashMapUnmanaged(struct { std.ArrayListUnmanaged(u64), u64 });
pub fn parseLine(line: []const u8, out: *DataMap, allocator: std.mem.Allocator) !void {
var tok = std.mem.tokenizeScalar(u8, line, ' ');
const name = tok.next() orelse return error.Shit;
if (std.mem.eql(u8, name, "2s") or std.mem.indexOfScalar(u8, line, '\x1b') != null) return;
const two_secs = try std.fmt.parseInt(u64, tok.next() orelse return error.Shit, 10);
const total = try std.fmt.parseInt(u64, tok.next() orelse return error.Shit, 10);
if (out.getPtr(name)) |val_p| {
try val_p.@"0".append(allocator, two_secs);
val_p.@"1" = total;
} else {
const a_name = try allocator.dupe(u8, name);
errdefer allocator.free(a_name);
const gop = try out.getOrPutValue(allocator, a_name, .{ .empty, total });
errdefer _ = out.orderedRemove(a_name);
try gop.value_ptr.@"0".append(allocator, two_secs);
}
}
const Entry = struct {
gpa: std.mem.Allocator,
out: DataMap = .empty,
mutex: std.Thread.Mutex = .{},
in: std.fs.File,
err: anyerror!void = {},
window: ?*dvui.Window = null,
};
pub fn main() !void {
const gpa = std.heap.smp_allocator;
var t = try Tardy.init(gpa, .{ .threading = .single });
var e = Entry{ .gpa = gpa, .in = std.io.getStdIn() };
try t.entry_in_new_thread(
&e,
struct {
fn entry(rt: *Runtime, p: *Entry) !void {
try rt.spawn(.{ rt, p }, ioFrame, 2 << 20);
try rt.spawn(.{ rt, p }, sortFrame, 2 << 20);
}
}.entry,
);
try t.entry(
&e,
struct {
fn entry(rt: *Runtime, p: *Entry) !void {
try rt.spawn(.{ rt, p }, guiFrame, 8 << 20);
}
}.entry,
);
}
fn sortFrame(rt: *Runtime, p: *Entry) !void {
try Timer.delay(rt, .{ .seconds = 2 });
const SortContext = struct {
slice: DataMap.DataList.Slice,
pub fn init(dm: *DataMap) @This() {
return .{ .slice = dm.entries.slice() };
}
pub fn lessThan(self: *@This(), a: usize, b: usize) bool {
const it = self.slice.items(.value);
return it[a].@"1" > it[b].@"1";
}
pub fn swap(self: *@This(), a: usize, b: usize) void {
const a_old = self.slice.get(a);
const b_old = self.slice.get(b);
self.slice.set(b, a_old);
self.slice.set(a, b_old);
}
};
{
p.mutex.lock();
defer p.mutex.unlock();
var sc = SortContext.init(&p.out);
std.sort.insertionContext(0, p.out.entries.len, &sc);
try p.out.reIndex(p.gpa);
}
dvui.refresh(p.window, @src(), null);
}
fn ioFrame(rt: *Runtime, p: *Entry) !void {
var b: std.fifo.LinearFifo(u8, .{ .Static = 4096 }) = .init();
while (true) {
b.realign();
const len = try tardy.File.from_std(p.in).read(rt, b.writableSlice(0), null);
if (len == 0) {
p.err = error.EndOfStream;
break;
}
b.update(len);
const end_of_line = std.mem.indexOfScalar(u8, b.readableSlice(0), '\n') orelse {
continue;
};
{
p.mutex.lock();
defer p.mutex.unlock();
parseLine(b.readableSlice(0)[0..end_of_line], &p.out, p.gpa) catch |e| {
p.err = e;
};
}
b.discard(end_of_line + 1);
dvui.refresh(p.window, @src(), null);
}
}
fn guiFrame(rt: *Runtime, p: *Entry) !void {
var backend = try Backend.initWindow(.{
.allocator = p.gpa,
.size = .{ .w = 800.0, .h = 600.0 },
.min_size = .{ .w = 250.0, .h = 350.0 },
.vsync = true,
.title = "bcachefs graph",
.icon = null,
});
defer backend.deinit();
var win = try dvui.Window.init(
@src(),
p.gpa,
backend.backend(),
.{},
);
defer win.deinit();
p.window = &win;
var exit = false;
var interrupted = false;
while (true) {
if (exit) rt.stop();
try win.begin(win.beginWait(interrupted));
const quit = try backend.addAllEvents(&win);
if (quit) break;
_ = Backend.c.SDL_SetRenderDrawColor(backend.renderer, 0, 0, 0, 255);
_ = Backend.c.SDL_RenderClear(backend.renderer);
{
{
var m = dvui.menu(@src(), .horizontal, .{ .background = true, .expand = .horizontal });
defer m.deinit();
if (dvui.menuItemLabel(@src(), "File", .{ .submenu = true }, .{ .expand = .none })) |r| {
var fw = dvui.floatingMenu(@src(), .{ .from = r }, .{});
defer fw.deinit();
if (dvui.menuItemLabel(@src(), "Quit", .{}, .{}) != null) {
exit = true;
}
}
}
var scaler = dvui.scale(
@src(),
.{ .scale = &dvui.currentWindow().content_scale, .pinch_zoom = .global },
.{ .rect = .cast(dvui.windowRect()) },
);
scaler.deinit();
var scroll = dvui.scrollArea(@src(), .{}, .{ .expand = .both, .color_fill = .fill_window });
defer scroll.deinit();
p.err catch |e| dvui.toast(@src(), .{ .message = @errorName(e) });
if (dvui.Theme.picker(@src(), .{})) {}
var vboxo = dvui.box(@src(), .vertical, .{
.expand = .horizontal,
});
defer vboxo.deinit();
p.mutex.lock();
defer p.mutex.unlock();
for (p.out.keys(), p.out.values()) |k, *v| {
// const static = struct {
// var xaxis: dvui.PlotWidget.Axis = .{
// .name = "Seconds",
// };
// var yaxis: dvui.PlotWidget.Axis = .{
// .name = "Events",
// };
// };
var vbox = dvui.box(@src(), .vertical, .{
.min_size_content = .{ .w = 300, .h = 100 },
.max_size_content = .height(100),
.expand = .both,
.id_extra = std.hash.Wyhash.hash(69, k),
});
defer vbox.deinit();
var plot = dvui.plot(@src(), .{
.title = k,
// .x_axis = &static.xaxis,
// .y_axis = &static.yaxis,
.border_thick = 1.0,
.mouse_hover = true,
}, .{
.expand = .both,
.id_extra = std.hash.Wyhash.hash(69, k),
});
var s1 = plot.line();
for (v.@"0".items, 0..) |count, idx| {
s1.point(@floatFromInt(idx), @floatFromInt(count));
}
s1.stroke(2, dvui.themeGet().color_accent);
s1.deinit();
plot.deinit();
}
}
const end_micros = try win.end(.{});
try backend.setCursor(win.cursorRequested());
try backend.textInputRect(win.textInputRequested());
try backend.renderPresent();
const end_wait = win.waitTime(end_micros, 60);
interrupted = try backend.waitEventTimeout(end_wait);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment