From 5acf1f524ac3732136137bd2799fd60c6d0900fc Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Mon, 3 Jun 2024 15:18:22 -0700 Subject: [PATCH 01/25] threadpool: track and show task times --- src/gui/windows/debug.zig | 7 ++++++- src/utils.zig | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index cc13dfaf0..fb83e5868 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -38,6 +38,11 @@ pub fn render() void { y += 8; draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left); y += 8; + const perf = main.threadPool.getPerformance(); + draw.print("Queue task time: {} ms / {} tasks", .{@divFloor(perf.utime, 1000), perf.tasks}, 0, y, 8, .left); + y += 8; + draw.print(" {} µs / task", .{@divFloor(perf.utime, @max(perf.tasks, 1))}, 0, y, 8, .left); + y += 8; draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); y += 8; { @@ -57,4 +62,4 @@ pub fn render() void { draw.print("Opaque faces: {}, Transparent faces: {}", .{main.renderer.chunk_meshing.quadsDrawn, main.renderer.chunk_meshing.transparentQuadsDrawn}, 0, y, 8, .left); y += 8; } -} \ No newline at end of file +} diff --git a/src/utils.zig b/src/utils.zig index 0b2ec1502..4e04f677e 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1000,6 +1000,11 @@ pub const ThreadPool = struct { run: *const fn(*anyopaque) void, clean: *const fn(*anyopaque) void, }; + pub const Performance = struct { + mutex: std.Thread.Mutex = .{}, + tasks: u32 = 0, + utime: i64 = 0, + }; const refreshTime: u32 = 100; // The time after which all priorities get refreshed in milliseconds. threads: []std.Thread, @@ -1007,11 +1012,14 @@ pub const ThreadPool = struct { loadList: *BlockingMaxHeap(Task), allocator: NeverFailingAllocator, + performance: *Performance, + pub fn init(allocator: NeverFailingAllocator, threadCount: usize) ThreadPool { const self = ThreadPool { .threads = allocator.alloc(std.Thread, threadCount), .currentTasks = allocator.alloc(Atomic(?*const VTable), threadCount), .loadList = BlockingMaxHeap(Task).init(allocator), + .performance = allocator.create(Performance), .allocator = allocator, }; for(self.threads, 0..) |*thread, i| { @@ -1062,6 +1070,16 @@ pub const ThreadPool = struct { } } + pub fn getPerformance(self: ThreadPool) Performance { + self.performance.mutex.lock(); + defer { + self.performance.tasks = 0; + self.performance.utime = 0; + self.performance.mutex.unlock(); + } + return self.performance.*; + } + fn run(self: ThreadPool, id: usize) void { // In case any of the tasks wants to allocate memory: var sta = StackAllocator.init(main.globalAllocator, 1 << 23); @@ -1073,7 +1091,13 @@ pub const ThreadPool = struct { { const task = self.loadList.extractMax() catch break; self.currentTasks[id].store(task.vtable, .monotonic); + const start = std.time.microTimestamp(); task.vtable.run(task.self); + const end = std.time.microTimestamp(); + self.performance.mutex.lock(); + self.performance.tasks += 1; + self.performance.utime += end - start; + self.performance.mutex.unlock(); self.currentTasks[id].store(null, .monotonic); } From ad1aa463dceaada6f79b00bfc8e2e2c7a5353365 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Tue, 4 Jun 2024 16:35:30 -0700 Subject: [PATCH 02/25] debug window: subdivide task performance --- src/audio.zig | 2 +- src/gui/windows/debug.zig | 16 +++++++++++++--- src/network.zig | 2 +- src/renderer/chunk_meshing.zig | 4 ++-- src/renderer/mesh_storage.zig | 4 ++-- src/server/world.zig | 6 +++--- src/utils.zig | 33 ++++++++++++++++++++++++++------- 7 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/audio.zig b/src/audio.zig index 4a65178b2..51e0a51f7 100644 --- a/src/audio.zig +++ b/src/audio.zig @@ -100,7 +100,7 @@ const MusicLoadTask = struct { task.* = MusicLoadTask { .musicId = musicId, }; - main.threadPool.addTask(task, &vtable); + main.threadPool.addTask(task, &vtable, .misc); taskMutex.lock(); defer taskMutex.unlock(); activeTasks.append(main.globalAllocator, musicId); diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index fb83e5868..0820fe90b 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -5,6 +5,7 @@ const graphics = main.graphics; const draw = graphics.draw; const Texture = graphics.Texture; const Vec2f = main.vec.Vec2f; +const TaskType = main.utils.ThreadPool.TaskType; const gui = @import("../gui.zig"); const GuiWindow = gui.GuiWindow; @@ -39,10 +40,19 @@ pub fn render() void { draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left); y += 8; const perf = main.threadPool.getPerformance(); - draw.print("Queue task time: {} ms / {} tasks", .{@divFloor(perf.utime, 1000), perf.tasks}, 0, y, 8, .left); - y += 8; - draw.print(" {} µs / task", .{@divFloor(perf.utime, @max(perf.tasks, 1))}, 0, y, 8, .left); + const values = comptime std.enums.values(TaskType); + inline for(values) |t| { + const name = switch (t) { + .chunkgen => "chunkgen", + .lighting => "lighting", + .meshgen => "meshing", + .misc => "other", + else => continue, + }; + const i = @intFromEnum(t); + draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], perf.tasks[i])}, 0, y, 8, .left); y += 8; + } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); y += 8; { diff --git a/src/network.zig b/src/network.zig index b7f981ebb..7b77ec367 100644 --- a/src/network.zig +++ b/src/network.zig @@ -1748,7 +1748,7 @@ const ProtocolTask = struct { .protocol = protocol, .data = main.globalAllocator.dupe(u8, data), }; - main.threadPool.addTask(task, &vtable); + main.threadPool.addTask(task, &vtable, .misc); } pub fn getPriority(_: *ProtocolTask) f32 { diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index 10a832e6a..3efc1bfc3 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -640,7 +640,7 @@ pub const ChunkMesh = struct { task.* = .{ .mesh = mesh, }; - main.threadPool.addTask(task, &vtable); + main.threadPool.addTask(task, &vtable, .lighting); } pub fn getPriority(_: *LightRefreshTask) f32 { @@ -1237,4 +1237,4 @@ pub const ChunkMesh = struct { chunkList.append(self.chunkAllocation.start); transparentQuadsDrawn += self.culledSortingCount; } -}; \ No newline at end of file +}; diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index eaca6596f..f4c81aedd 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -1049,7 +1049,7 @@ pub const MeshGenerationTask = struct { task.* = MeshGenerationTask { .mesh = mesh, }; - main.threadPool.addTask(task, &vtable); + main.threadPool.addTask(task, &vtable, .meshgen); } pub fn getPriority(self: *MeshGenerationTask) f32 { @@ -1092,4 +1092,4 @@ pub fn updateLightMap(map: *LightMap.LightMapFragment) void { mutex.lock(); defer mutex.unlock(); mapUpdatableList.append(map); -} \ No newline at end of file +} diff --git a/src/server/world.zig b/src/server/world.zig index 9ceb9305d..39140f647 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -50,7 +50,7 @@ const ChunkManager = struct { .creationTime = std.time.milliTimestamp(), .source = source, }; - main.threadPool.addTask(task, &vtable); + main.threadPool.addTask(task, &vtable, .chunkgen); } pub fn getPriority(self: *ChunkLoadTask) f32 { @@ -114,7 +114,7 @@ const ChunkManager = struct { .creationTime = std.time.milliTimestamp(), .source = source, }; - main.threadPool.addTask(task, &vtable); + main.threadPool.addTask(task, &vtable, .lighting); } pub fn getPriority(self: *LightMapLoadTask) f32 { @@ -431,7 +431,7 @@ pub const ServerWorld = struct { task.* = .{ .pos = pos, }; - main.threadPool.addTask(task, &vtable); + main.threadPool.addTask(task, &vtable, .chunkgen); } pub fn getPriority(_: *RegenerateLODTask) f32 { diff --git a/src/utils.zig b/src/utils.zig index 4e04f677e..e1fafa939 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -985,10 +985,18 @@ pub fn BlockingMaxHeap(comptime T: type) type { } pub const ThreadPool = struct { + pub const TaskType = enum(usize) { + chunkgen, + lighting, + meshgen, + misc, + taskTypes, + }; const Task = struct { cachedPriority: f32, self: *anyopaque, vtable: *const VTable, + taskType: TaskType, fn biggerThan(self: Task, other: Task) bool { return self.cachedPriority > other.cachedPriority; @@ -1002,8 +1010,19 @@ pub const ThreadPool = struct { }; pub const Performance = struct { mutex: std.Thread.Mutex = .{}, - tasks: u32 = 0, - utime: i64 = 0, + tasks: [@intFromEnum(TaskType.taskTypes)]u32 = {}, + utime: [@intFromEnum(TaskType.taskTypes)]i64 = {}, + + fn clear(self: *Performance) void { + for(0..@intFromEnum(TaskType.taskTypes)) |i| { + self.tasks[i] = 0; + self.utime[i] = 0; + } + } + + fn init(self: Performance) void { + self.clear(); + } }; const refreshTime: u32 = 100; // The time after which all priorities get refreshed in milliseconds. @@ -1073,8 +1092,7 @@ pub const ThreadPool = struct { pub fn getPerformance(self: ThreadPool) Performance { self.performance.mutex.lock(); defer { - self.performance.tasks = 0; - self.performance.utime = 0; + self.performance.clear(); self.performance.mutex.unlock(); } return self.performance.*; @@ -1095,8 +1113,8 @@ pub const ThreadPool = struct { task.vtable.run(task.self); const end = std.time.microTimestamp(); self.performance.mutex.lock(); - self.performance.tasks += 1; - self.performance.utime += end - start; + self.performance.tasks[@intFromEnum(task.taskType)] += 1; + self.performance.utime[@intFromEnum(task.taskType)] += end - start; self.performance.mutex.unlock(); self.currentTasks[id].store(null, .monotonic); } @@ -1124,11 +1142,12 @@ pub const ThreadPool = struct { } } - pub fn addTask(self: ThreadPool, task: *anyopaque, vtable: *const VTable) void { + pub fn addTask(self: ThreadPool, task: *anyopaque, vtable: *const VTable, taskType: TaskType) void { self.loadList.add(Task { .cachedPriority = vtable.getPriority(task), .vtable = vtable, .self = task, + .taskType = taskType, }); } From af2962b0490d6f53c3ac57a4ac079a29984b27d1 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Tue, 4 Jun 2024 16:49:05 -0700 Subject: [PATCH 03/25] indent debug window code --- src/gui/windows/debug.zig | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index 0820fe90b..c43bf7ef7 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -39,20 +39,20 @@ pub fn render() void { y += 8; draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left); y += 8; - const perf = main.threadPool.getPerformance(); - const values = comptime std.enums.values(TaskType); - inline for(values) |t| { - const name = switch (t) { - .chunkgen => "chunkgen", - .lighting => "lighting", - .meshgen => "meshing", - .misc => "other", - else => continue, - }; - const i = @intFromEnum(t); - draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], perf.tasks[i])}, 0, y, 8, .left); + const perf = main.threadPool.getPerformance(); + const values = comptime std.enums.values(TaskType); + inline for(values) |t| { + const name = switch (t) { + .chunkgen => "chunkgen", + .lighting => "lighting", + .meshgen => "meshing", + .misc => "other", + else => continue, + }; + const i = @intFromEnum(t); + draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], perf.tasks[i])}, 0, y, 8, .left); y += 8; - } + } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); y += 8; { From ae11566915e0b9faba8b1eb7ca36dbaeebf509e6 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Tue, 4 Jun 2024 19:44:10 -0700 Subject: [PATCH 04/25] task perfs: remove meshgen for lighting --- src/gui/windows/debug.zig | 1 - src/renderer/mesh_storage.zig | 2 +- src/utils.zig | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index c43bf7ef7..3aaccc4b3 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -45,7 +45,6 @@ pub fn render() void { const name = switch (t) { .chunkgen => "chunkgen", .lighting => "lighting", - .meshgen => "meshing", .misc => "other", else => continue, }; diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index f4c81aedd..2999dc72c 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -1049,7 +1049,7 @@ pub const MeshGenerationTask = struct { task.* = MeshGenerationTask { .mesh = mesh, }; - main.threadPool.addTask(task, &vtable, .meshgen); + main.threadPool.addTask(task, &vtable, .lighting); } pub fn getPriority(self: *MeshGenerationTask) f32 { diff --git a/src/utils.zig b/src/utils.zig index e1fafa939..51534319b 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -988,7 +988,6 @@ pub const ThreadPool = struct { pub const TaskType = enum(usize) { chunkgen, lighting, - meshgen, misc, taskTypes, }; From ce26e555fbb61b49a14e370c7a7ab2890b77c125 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Wed, 5 Jun 2024 12:57:28 -0700 Subject: [PATCH 05/25] task perfs: don't divide by zero --- src/gui/windows/debug.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index 3aaccc4b3..67421c11c 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -49,7 +49,7 @@ pub fn render() void { else => continue, }; const i = @intFromEnum(t); - draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], perf.tasks[i])}, 0, y, 8, .left); + draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); y += 8; } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); From 93a9d048aac29468ef6cb0a62316c84591ebc194 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Wed, 5 Jun 2024 13:25:22 -0700 Subject: [PATCH 06/25] task perf: move taskType to vtable --- src/audio.zig | 3 ++- src/network.zig | 3 ++- src/renderer/chunk_meshing.zig | 3 ++- src/renderer/mesh_storage.zig | 3 ++- src/server/world.zig | 9 ++++++--- src/utils.zig | 10 +++++----- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/audio.zig b/src/audio.zig index 51e0a51f7..b022e6798 100644 --- a/src/audio.zig +++ b/src/audio.zig @@ -93,6 +93,7 @@ const MusicLoadTask = struct { .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), + .taskType = .misc, }; pub fn schedule(musicId: []const u8) void { @@ -100,7 +101,7 @@ const MusicLoadTask = struct { task.* = MusicLoadTask { .musicId = musicId, }; - main.threadPool.addTask(task, &vtable, .misc); + main.threadPool.addTask(task, &vtable); taskMutex.lock(); defer taskMutex.unlock(); activeTasks.append(main.globalAllocator, musicId); diff --git a/src/network.zig b/src/network.zig index 7b77ec367..6de638633 100644 --- a/src/network.zig +++ b/src/network.zig @@ -1739,6 +1739,7 @@ const ProtocolTask = struct { .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), + .taskType = .misc, }; pub fn schedule(conn: *Connection, protocol: u8, data: []const u8) void { @@ -1748,7 +1749,7 @@ const ProtocolTask = struct { .protocol = protocol, .data = main.globalAllocator.dupe(u8, data), }; - main.threadPool.addTask(task, &vtable, .misc); + main.threadPool.addTask(task, &vtable); } pub fn getPriority(_: *ProtocolTask) f32 { diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index 3efc1bfc3..d75ff8f33 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -633,6 +633,7 @@ pub const ChunkMesh = struct { .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), + .taskType = .lighting, }; pub fn scheduleAndDecreaseRefCount(mesh: *ChunkMesh) void { @@ -640,7 +641,7 @@ pub const ChunkMesh = struct { task.* = .{ .mesh = mesh, }; - main.threadPool.addTask(task, &vtable, .lighting); + main.threadPool.addTask(task, &vtable); } pub fn getPriority(_: *LightRefreshTask) f32 { diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index 2999dc72c..23dfc187b 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -1042,6 +1042,7 @@ pub const MeshGenerationTask = struct { .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), + .taskType = .lighting, }; pub fn schedule(mesh: *chunk.Chunk) void { @@ -1049,7 +1050,7 @@ pub const MeshGenerationTask = struct { task.* = MeshGenerationTask { .mesh = mesh, }; - main.threadPool.addTask(task, &vtable, .lighting); + main.threadPool.addTask(task, &vtable); } pub fn getPriority(self: *MeshGenerationTask) f32 { diff --git a/src/server/world.zig b/src/server/world.zig index 39140f647..96d758446 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -41,6 +41,7 @@ const ChunkManager = struct { .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), + .taskType = .chunkgen, }; pub fn scheduleAndDecreaseRefCount(pos: ChunkPosition, source: ?*User) void { @@ -50,7 +51,7 @@ const ChunkManager = struct { .creationTime = std.time.milliTimestamp(), .source = source, }; - main.threadPool.addTask(task, &vtable, .chunkgen); + main.threadPool.addTask(task, &vtable); } pub fn getPriority(self: *ChunkLoadTask) f32 { @@ -105,6 +106,7 @@ const ChunkManager = struct { .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), + .taskType = .lighting, }; pub fn scheduleAndDecreaseRefCount(pos: terrain.SurfaceMap.MapFragmentPosition, source: ?*User) void { @@ -114,7 +116,7 @@ const ChunkManager = struct { .creationTime = std.time.milliTimestamp(), .source = source, }; - main.threadPool.addTask(task, &vtable, .lighting); + main.threadPool.addTask(task, &vtable); } pub fn getPriority(self: *LightMapLoadTask) f32 { @@ -424,6 +426,7 @@ pub const ServerWorld = struct { .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), + .taskType = .chunkgen, }; pub fn schedule(pos: ChunkPosition) void { @@ -431,7 +434,7 @@ pub const ServerWorld = struct { task.* = .{ .pos = pos, }; - main.threadPool.addTask(task, &vtable, .chunkgen); + main.threadPool.addTask(task, &vtable); } pub fn getPriority(_: *RegenerateLODTask) f32 { diff --git a/src/utils.zig b/src/utils.zig index 51534319b..61078b6c2 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -995,7 +995,6 @@ pub const ThreadPool = struct { cachedPriority: f32, self: *anyopaque, vtable: *const VTable, - taskType: TaskType, fn biggerThan(self: Task, other: Task) bool { return self.cachedPriority > other.cachedPriority; @@ -1006,6 +1005,7 @@ pub const ThreadPool = struct { isStillNeeded: *const fn(*anyopaque, milliTime: i64) bool, run: *const fn(*anyopaque) void, clean: *const fn(*anyopaque) void, + taskType: TaskType = .misc, }; pub const Performance = struct { mutex: std.Thread.Mutex = .{}, @@ -1111,9 +1111,10 @@ pub const ThreadPool = struct { const start = std.time.microTimestamp(); task.vtable.run(task.self); const end = std.time.microTimestamp(); + const taskType = @intFromEnum(task.vtable.taskType); self.performance.mutex.lock(); - self.performance.tasks[@intFromEnum(task.taskType)] += 1; - self.performance.utime[@intFromEnum(task.taskType)] += end - start; + self.performance.tasks[taskType] += 1; + self.performance.utime[taskType] += end - start; self.performance.mutex.unlock(); self.currentTasks[id].store(null, .monotonic); } @@ -1141,12 +1142,11 @@ pub const ThreadPool = struct { } } - pub fn addTask(self: ThreadPool, task: *anyopaque, vtable: *const VTable, taskType: TaskType) void { + pub fn addTask(self: ThreadPool, task: *anyopaque, vtable: *const VTable) void { self.loadList.add(Task { .cachedPriority = vtable.getPriority(task), .vtable = vtable, .self = task, - .taskType = taskType, }); } From 993157a4356896cdadb16faa9f02b56a738bc189 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 6 Oct 2024 12:54:07 -0700 Subject: [PATCH 07/25] use directEnumArrayLen instead of C-style length --- src/gui/windows/debug.zig | 1 - src/utils.zig | 12 +++++++++--- src/utils/list.zig | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index 2763ac852..dbd99df73 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -69,7 +69,6 @@ pub fn render() void { .chunkgen => "chunkgen", .lighting => "lighting", .misc => "other", - else => continue, }; const i = @intFromEnum(t); draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); diff --git a/src/utils.zig b/src/utils.zig index d2cbe7ae4..5aa198db2 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1010,6 +1010,12 @@ pub fn BlockingMaxHeap(comptime T: type) type { // MARK: BlockingMaxHeap } pub const ThreadPool = struct { // MARK: ThreadPool + pub const TaskType = enum(usize) { + chunkgen, + lighting, + misc, + }; + pub const taskTypes = std.enums.directEnumArrayLen(TaskType, 0); const Task = struct { cachedPriority: f32, self: *anyopaque, @@ -1028,11 +1034,11 @@ pub const ThreadPool = struct { // MARK: ThreadPool }; pub const Performance = struct { mutex: std.Thread.Mutex = .{}, - tasks: [@intFromEnum(TaskType.taskTypes)]u32 = {}, - utime: [@intFromEnum(TaskType.taskTypes)]i64 = {}, + tasks: [taskTypes]u32 = {}, + utime: [taskTypes]i64 = {}, fn clear(self: *Performance) void { - for(0..@intFromEnum(TaskType.taskTypes)) |i| { + for(0..taskTypes) |i| { self.tasks[i] = 0; self.utime[i] = 0; } diff --git a/src/utils/list.zig b/src/utils/list.zig index 341c4db66..637d568df 100644 --- a/src/utils/list.zig +++ b/src/utils/list.zig @@ -433,7 +433,7 @@ pub fn ListUnmanaged(comptime T: type) type { }; } -const pageSize = 4 << 10; +const pageSize = 16 << 10; fn reserveMemory(len: usize) [*]align(pageSize) u8 { if(builtin.os.tag == .windows) { From af927fa020fd433e4b76d175f2219b158e4e9149 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 6 Oct 2024 12:57:13 -0700 Subject: [PATCH 08/25] use @tagName for task type classes --- src/gui/windows/debug.zig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index dbd99df73..a68d13d22 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -65,11 +65,7 @@ pub fn render() void { const perf = main.threadPool.getPerformance(); const values = comptime std.enums.values(TaskType); inline for(values) |t| { - const name = switch (t) { - .chunkgen => "chunkgen", - .lighting => "lighting", - .misc => "other", - }; + const name = @tagName(t) const i = @intFromEnum(t); draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); y += 8; From 0f705abdb153fcd6f6845097bda53e89623ab10f Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 6 Oct 2024 14:02:01 -0700 Subject: [PATCH 09/25] switch to atomics --- src/gui/windows/debug.zig | 4 ++-- src/utils.zig | 43 +++++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index a68d13d22..c8975d740 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -62,10 +62,10 @@ pub fn render() void { y += 8; draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left); y += 8; - const perf = main.threadPool.getPerformance(); + const perf = main.threadPool.performance.readAndReset(); const values = comptime std.enums.values(TaskType); inline for(values) |t| { - const name = @tagName(t) + const name = @tagName(t); const i = @intFromEnum(t); draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); y += 8; diff --git a/src/utils.zig b/src/utils.zig index 5aa198db2..7dc27b43b 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1033,20 +1033,36 @@ pub const ThreadPool = struct { // MARK: ThreadPool taskType: TaskType = .misc, }; pub const Performance = struct { - mutex: std.Thread.Mutex = .{}, - tasks: [taskTypes]u32 = {}, - utime: [taskTypes]i64 = {}, + tasks: [taskTypes]u32, + utime: [taskTypes]i64, + + fn add(self: *Performance, task: TaskType, time: i64) void { + const i = @intFromEnum(task); + _ = @atomicRmw(u32, &self.tasks[i], .Add, 1, .monotonic); + _ = @atomicRmw(i64, &self.utime[i], .Add, time, .monotonic); + } fn clear(self: *Performance) void { - for(0..taskTypes) |i| { - self.tasks[i] = 0; - self.utime[i] = 0; + for(0..taskTypes) |task| { + @atomicStore(u32, &self.tasks[task], 0, .monotonic); + @atomicStore(i64, &self.utime[task], 0, .monotonic); } } fn init(self: Performance) void { self.clear(); } + + pub fn readAndReset(self: *Performance) Performance { + var copy = Performance{.tasks = undefined, .utime = undefined}; + // atomics of dubious quality + for(0..taskTypes) |task| { + copy.tasks[task] = @atomicLoad(u32, &self.tasks[task], .monotonic); + copy.utime[task] = @atomicLoad(i64, &self.utime[task], .monotonic); + } + self.clear(); + return copy; + } }; const refreshTime: u32 = 100; // The time after which all priorities get refreshed in milliseconds. @@ -1113,15 +1129,6 @@ pub const ThreadPool = struct { // MARK: ThreadPool } } - pub fn getPerformance(self: ThreadPool) Performance { - self.performance.mutex.lock(); - defer { - self.performance.clear(); - self.performance.mutex.unlock(); - } - return self.performance.*; - } - fn run(self: ThreadPool, id: usize) void { // In case any of the tasks wants to allocate memory: var sta = StackAllocator.init(main.globalAllocator, 1 << 23); @@ -1136,11 +1143,7 @@ pub const ThreadPool = struct { // MARK: ThreadPool const start = std.time.microTimestamp(); task.vtable.run(task.self); const end = std.time.microTimestamp(); - const taskType = @intFromEnum(task.vtable.taskType); - self.performance.mutex.lock(); - self.performance.tasks[taskType] += 1; - self.performance.utime[taskType] += end - start; - self.performance.mutex.unlock(); + self.performance.add(task.vtable.taskType, end - start); self.currentTasks[id].store(null, .monotonic); } From abd928157c5da3a3bf6887178d20adf1f687e5be Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 6 Oct 2024 14:05:19 -0700 Subject: [PATCH 10/25] recategorize LightRefreshTaks, LightMapLoadTask under misc --- src/renderer/chunk_meshing.zig | 2 +- src/server/world.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index 60d9f3eab..df1266477 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -744,7 +744,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), - .taskType = .lighting, + .taskType = .misc, }; pub fn scheduleAndDecreaseRefCount(mesh: *ChunkMesh) void { diff --git a/src/server/world.zig b/src/server/world.zig index 592df99c4..9625c9286 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -202,7 +202,7 @@ const ChunkManager = struct { // MARK: ChunkManager .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), - .taskType = .lighting, + .taskType = .misc, }; pub fn scheduleAndDecreaseRefCount(pos: terrain.SurfaceMap.MapFragmentPosition, source: ?*User) void { From 61b94bbbec3160b31d1a8a9b5f7dfe662f4eccc8 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 6 Oct 2024 14:18:50 -0700 Subject: [PATCH 11/25] add frameCount --- src/main.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.zig b/src/main.zig index dc84ed1a0..aeba85147 100644 --- a/src/main.zig +++ b/src/main.zig @@ -388,6 +388,8 @@ pub var lastFrameTime = std.atomic.Value(f64).init(0); /// Measures time between different frames' beginnings. pub var lastDeltaTime = std.atomic.Value(f64).init(0); +pub var frameCount = 0; + var shouldExitToMenu = std.atomic.Value(bool).init(false); pub fn exitToMenu(_: usize) void { shouldExitToMenu.store(true, .monotonic); @@ -598,6 +600,7 @@ pub fn main() void { // MARK: main() c.glClearColor(0.5, 1, 1, 1); c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT); gui.windowlist.gpu_performance_measuring.stopQuery(); + frameCount += 1; } else { std.time.sleep(16_000_000); } @@ -648,6 +651,7 @@ pub fn main() void { // MARK: main() gui.openWindow("main"); audio.setMusic("cubyz:cubyz"); } + } if(game.world) |world| { From ad814685fa1a8b2c297f3a59f1e68d0c199d9e5f Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 6 Oct 2024 14:19:20 -0700 Subject: [PATCH 12/25] update perfs every perfUpdateFrequency frames --- src/gui/windows/debug.zig | 6 ++++-- src/main.zig | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index c8975d740..5b4395a5b 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -62,12 +62,14 @@ pub fn render() void { y += 8; draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left); y += 8; - const perf = main.threadPool.performance.readAndReset(); + if (main.frameCount % main.perfUpdateFrequency == 0) + main.lastPerformance = main.threadPool.performance.readAndReset(); + const perf = main.lastPerformance; const values = comptime std.enums.values(TaskType); inline for(values) |t| { const name = @tagName(t); const i = @intFromEnum(t); - draw.print(" " ++ name ++ " time: {} ms ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); + draw.print(" " ++ name ++ " time: {} ms/frame ({} µs/task)", .{@divFloor(perf.utime[i], 1000*main.perfUpdateFrequency), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); y += 8; } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); diff --git a/src/main.zig b/src/main.zig index aeba85147..d2bd83032 100644 --- a/src/main.zig +++ b/src/main.zig @@ -388,7 +388,12 @@ pub var lastFrameTime = std.atomic.Value(f64).init(0); /// Measures time between different frames' beginnings. pub var lastDeltaTime = std.atomic.Value(f64).init(0); -pub var frameCount = 0; +/// Records threadpool task count and times. +pub var lastPerformance = utils.ThreadPool.Performance{.tasks = [1]u32 {0} ** utils.ThreadPool.taskTypes, .utime = [1]i64 {0} ** utils.ThreadPool.taskTypes}; +/// Frames between updating threadpool performance figures. +pub const perfUpdateFrequency = 10; + +pub var frameCount: u64 = 0; var shouldExitToMenu = std.atomic.Value(bool).init(false); pub fn exitToMenu(_: usize) void { From 10d7bc3529c91bea39b69fe86c3ea1eba4ed20fd Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 6 Oct 2024 14:28:10 -0700 Subject: [PATCH 13/25] restore 4k pageSize --- src/utils/list.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/list.zig b/src/utils/list.zig index 637d568df..341c4db66 100644 --- a/src/utils/list.zig +++ b/src/utils/list.zig @@ -433,7 +433,7 @@ pub fn ListUnmanaged(comptime T: type) type { }; } -const pageSize = 16 << 10; +const pageSize = 4 << 10; fn reserveMemory(len: usize) [*]align(pageSize) u8 { if(builtin.os.tag == .windows) { From 4b609e78a057e42eadefdf8af00d3b1a441f0d3a Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Tue, 8 Oct 2024 12:23:06 -0700 Subject: [PATCH 14/25] lighting -> meshgenAndLighting --- src/renderer/mesh_storage.zig | 2 +- src/utils.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index 94b4a4443..d1c8d67e4 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -885,7 +885,7 @@ pub const MeshGenerationTask = struct { // MARK: MeshGenerationTask .isStillNeeded = @ptrCast(&isStillNeeded), .run = @ptrCast(&run), .clean = @ptrCast(&clean), - .taskType = .lighting, + .taskType = .meshgenAndLighting, }; pub fn schedule(mesh: *chunk.Chunk) void { diff --git a/src/utils.zig b/src/utils.zig index 7dc27b43b..05e47deac 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1012,7 +1012,7 @@ pub fn BlockingMaxHeap(comptime T: type) type { // MARK: BlockingMaxHeap pub const ThreadPool = struct { // MARK: ThreadPool pub const TaskType = enum(usize) { chunkgen, - lighting, + meshgenAndLighting, misc, }; pub const taskTypes = std.enums.directEnumArrayLen(TaskType, 0); From 5e8d1667459a6895ac37434d41016dc85b1bc58e Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Thu, 10 Oct 2024 08:33:13 -0700 Subject: [PATCH 15/25] reset counts on open rather than by time --- src/gui/windows/debug.zig | 10 ++++++---- src/main.zig | 5 ----- src/utils.zig | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index 5b4395a5b..7da5b219b 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -11,6 +11,10 @@ const gui = @import("../gui.zig"); const GuiWindow = gui.GuiWindow; const GuiComponent = gui.GuiComponent; +pub fn onOpen() void { + main.threadPool.performance.clear(); +} + pub var window = GuiWindow { .relativePosition = .{ .{ .attachedToFrame = .{.selfAttachmentPoint = .lower, .otherAttachmentPoint = .lower} }, @@ -62,14 +66,12 @@ pub fn render() void { y += 8; draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left); y += 8; - if (main.frameCount % main.perfUpdateFrequency == 0) - main.lastPerformance = main.threadPool.performance.readAndReset(); - const perf = main.lastPerformance; + const perf = main.threadPool.performance.read(); const values = comptime std.enums.values(TaskType); inline for(values) |t| { const name = @tagName(t); const i = @intFromEnum(t); - draw.print(" " ++ name ++ " time: {} ms/frame ({} µs/task)", .{@divFloor(perf.utime[i], 1000*main.perfUpdateFrequency), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); + draw.print(" " ++ name ++ " time: {} ms/frame ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); y += 8; } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); diff --git a/src/main.zig b/src/main.zig index d2bd83032..cb66d3966 100644 --- a/src/main.zig +++ b/src/main.zig @@ -390,10 +390,6 @@ pub var lastDeltaTime = std.atomic.Value(f64).init(0); /// Records threadpool task count and times. pub var lastPerformance = utils.ThreadPool.Performance{.tasks = [1]u32 {0} ** utils.ThreadPool.taskTypes, .utime = [1]i64 {0} ** utils.ThreadPool.taskTypes}; -/// Frames between updating threadpool performance figures. -pub const perfUpdateFrequency = 10; - -pub var frameCount: u64 = 0; var shouldExitToMenu = std.atomic.Value(bool).init(false); pub fn exitToMenu(_: usize) void { @@ -605,7 +601,6 @@ pub fn main() void { // MARK: main() c.glClearColor(0.5, 1, 1, 1); c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT); gui.windowlist.gpu_performance_measuring.stopQuery(); - frameCount += 1; } else { std.time.sleep(16_000_000); } diff --git a/src/utils.zig b/src/utils.zig index 05e47deac..8d8b0f7de 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1042,7 +1042,7 @@ pub const ThreadPool = struct { // MARK: ThreadPool _ = @atomicRmw(i64, &self.utime[i], .Add, time, .monotonic); } - fn clear(self: *Performance) void { + pub fn clear(self: *Performance) void { for(0..taskTypes) |task| { @atomicStore(u32, &self.tasks[task], 0, .monotonic); @atomicStore(i64, &self.utime[task], 0, .monotonic); @@ -1053,7 +1053,7 @@ pub const ThreadPool = struct { // MARK: ThreadPool self.clear(); } - pub fn readAndReset(self: *Performance) Performance { + pub fn read(self: *Performance) Performance { var copy = Performance{.tasks = undefined, .utime = undefined}; // atomics of dubious quality for(0..taskTypes) |task| { From ad7fa9d6fba06512297f3c8a2f31456afabe8c2c Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Thu, 10 Oct 2024 08:39:25 -0700 Subject: [PATCH 16/25] revert to mutex Performance --- src/utils.zig | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/utils.zig b/src/utils.zig index 8d8b0f7de..6b6156075 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1033,19 +1033,24 @@ pub const ThreadPool = struct { // MARK: ThreadPool taskType: TaskType = .misc, }; pub const Performance = struct { + mutex: std.Thread.Mutex = .{}, tasks: [taskTypes]u32, utime: [taskTypes]i64, fn add(self: *Performance, task: TaskType, time: i64) void { + self.mutex.lock(); + defer self.mutex.unlock(); const i = @intFromEnum(task); - _ = @atomicRmw(u32, &self.tasks[i], .Add, 1, .monotonic); - _ = @atomicRmw(i64, &self.utime[i], .Add, time, .monotonic); + self.tasks[i] += 1; + self.utime[i] += time; } pub fn clear(self: *Performance) void { - for(0..taskTypes) |task| { - @atomicStore(u32, &self.tasks[task], 0, .monotonic); - @atomicStore(i64, &self.utime[task], 0, .monotonic); + self.mutex.lock(); + defer self.mutex.unlock(); + for(0..taskTypes) |i| { + self.tasks[i] = 0; + self.utime[i] = 0; } } @@ -1055,12 +1060,12 @@ pub const ThreadPool = struct { // MARK: ThreadPool pub fn read(self: *Performance) Performance { var copy = Performance{.tasks = undefined, .utime = undefined}; - // atomics of dubious quality - for(0..taskTypes) |task| { - copy.tasks[task] = @atomicLoad(u32, &self.tasks[task], .monotonic); - copy.utime[task] = @atomicLoad(i64, &self.utime[task], .monotonic); + self.mutex.lock(); + defer self.mutex.unlock(); + for(0..taskTypes) |i| { + copy.tasks[i] = self.tasks[i]; + copy.utime[i] = self.utime[i]; } - self.clear(); return copy; } }; From 4ac3709cb4084f15dd274059d53c789d64f810c2 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Thu, 10 Oct 2024 08:40:05 -0700 Subject: [PATCH 17/25] restore 4096 pageSize --- src/utils/list.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/list.zig b/src/utils/list.zig index 341c4db66..2f9c481f0 100644 --- a/src/utils/list.zig +++ b/src/utils/list.zig @@ -433,7 +433,7 @@ pub fn ListUnmanaged(comptime T: type) type { }; } -const pageSize = 4 << 10; +const pageSize = 4096; fn reserveMemory(len: usize) [*]align(pageSize) u8 { if(builtin.os.tag == .windows) { From e0b27dc2b394d0f9e5f2ff06bbbaecec65b5b918 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Thu, 10 Oct 2024 08:52:03 -0700 Subject: [PATCH 18/25] cleanup --- src/gui/windows/debug.zig | 6 +++--- src/main.zig | 4 ---- src/utils/.vimrc | 1 - 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 src/utils/.vimrc diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index 7da5b219b..fdb4c0a55 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -68,11 +68,11 @@ pub fn render() void { y += 8; const perf = main.threadPool.performance.read(); const values = comptime std.enums.values(TaskType); - inline for(values) |t| { + for(values) |t| { const name = @tagName(t); const i = @intFromEnum(t); - draw.print(" " ++ name ++ " time: {} ms/frame ({} µs/task)", .{@divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); - y += 8; + draw.print(" {s} time: {} ms/frame ({} µs/task)", .{name, @divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); + y += 8; } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); y += 8; diff --git a/src/main.zig b/src/main.zig index cb66d3966..dc84ed1a0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -388,9 +388,6 @@ pub var lastFrameTime = std.atomic.Value(f64).init(0); /// Measures time between different frames' beginnings. pub var lastDeltaTime = std.atomic.Value(f64).init(0); -/// Records threadpool task count and times. -pub var lastPerformance = utils.ThreadPool.Performance{.tasks = [1]u32 {0} ** utils.ThreadPool.taskTypes, .utime = [1]i64 {0} ** utils.ThreadPool.taskTypes}; - var shouldExitToMenu = std.atomic.Value(bool).init(false); pub fn exitToMenu(_: usize) void { shouldExitToMenu.store(true, .monotonic); @@ -651,7 +648,6 @@ pub fn main() void { // MARK: main() gui.openWindow("main"); audio.setMusic("cubyz:cubyz"); } - } if(game.world) |world| { diff --git a/src/utils/.vimrc b/src/utils/.vimrc deleted file mode 100644 index 0147abe09..000000000 --- a/src/utils/.vimrc +++ /dev/null @@ -1 +0,0 @@ -set noexpandtab From 0ee00d0d6145187223465a7d2c59cf90d72b0848 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Thu, 10 Oct 2024 14:52:29 -0700 Subject: [PATCH 19/25] correctly use Performance init --- src/utils.zig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils.zig b/src/utils.zig index 6b6156075..3207551bb 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1054,8 +1054,10 @@ pub const ThreadPool = struct { // MARK: ThreadPool } } - fn init(self: Performance) void { + fn init(allocator: NeverFailingAllocator) *Performance { + const self = allocator.create(Performance); self.clear(); + return self; } pub fn read(self: *Performance) Performance { @@ -1083,7 +1085,7 @@ pub const ThreadPool = struct { // MARK: ThreadPool .threads = allocator.alloc(std.Thread, threadCount), .currentTasks = allocator.alloc(Atomic(?*const VTable), threadCount), .loadList = BlockingMaxHeap(Task).init(allocator), - .performance = allocator.create(Performance), + .performance = Performance.init(allocator), .allocator = allocator, }; for(self.threads, 0..) |*thread, i| { From b77a076a1d56d061506e69c92d5185782984a311 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Thu, 10 Oct 2024 14:53:24 -0700 Subject: [PATCH 20/25] track task time per frame properly --- src/gui/windows/debug.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index fdb4c0a55..e70466a09 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -11,8 +11,11 @@ const gui = @import("../gui.zig"); const GuiWindow = gui.GuiWindow; const GuiComponent = gui.GuiComponent; +var trackedFrames: u64 = 0; + pub fn onOpen() void { main.threadPool.performance.clear(); + trackedFrames = 0; } pub var window = GuiWindow { @@ -28,6 +31,7 @@ pub var window = GuiWindow { }; pub fn render() void { + trackedFrames += 1; draw.setColor(0xffffffff); var y: f32 = 0; const fpsCapText = if(main.settings.fpsCap) |fpsCap| std.fmt.allocPrint(main.stackAllocator.allocator, " (limit: {d:.0} Hz)", .{fpsCap}) catch unreachable else ""; @@ -71,7 +75,7 @@ pub fn render() void { for(values) |t| { const name = @tagName(t); const i = @intFromEnum(t); - draw.print(" {s} time: {} ms/frame ({} µs/task)", .{name, @divFloor(perf.utime[i], 1000), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); + draw.print(" {s} time: {} ms/frame ({} µs/task)", .{name, @divFloor(perf.utime[i], 1000*trackedFrames), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); y += 8; } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); From e5144ec7ba58520d4fc074de1bd9516c7d84cca1 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sat, 12 Oct 2024 22:36:45 -0700 Subject: [PATCH 21/25] just copy.* --- src/utils.zig | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/utils.zig b/src/utils.zig index 3207551bb..b34ef2f2b 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1061,14 +1061,9 @@ pub const ThreadPool = struct { // MARK: ThreadPool } pub fn read(self: *Performance) Performance { - var copy = Performance{.tasks = undefined, .utime = undefined}; self.mutex.lock(); defer self.mutex.unlock(); - for(0..taskTypes) |i| { - copy.tasks[i] = self.tasks[i]; - copy.utime[i] = self.utime[i]; - } - return copy; + return self.*; } }; const refreshTime: u32 = 100; // The time after which all priorities get refreshed in milliseconds. From 5fd1127e6adfbb5866f93e7e8ee2f5f1065a86b1 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sat, 12 Oct 2024 23:04:01 -0700 Subject: [PATCH 22/25] use % total instead of % frame time --- src/gui/windows/debug.zig | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index e70466a09..ef3ade671 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -11,11 +11,9 @@ const gui = @import("../gui.zig"); const GuiWindow = gui.GuiWindow; const GuiComponent = gui.GuiComponent; -var trackedFrames: u64 = 0; pub fn onOpen() void { main.threadPool.performance.clear(); - trackedFrames = 0; } pub var window = GuiWindow { @@ -31,7 +29,6 @@ pub var window = GuiWindow { }; pub fn render() void { - trackedFrames += 1; draw.setColor(0xffffffff); var y: f32 = 0; const fpsCapText = if(main.settings.fpsCap) |fpsCap| std.fmt.allocPrint(main.stackAllocator.allocator, " (limit: {d:.0} Hz)", .{fpsCap}) catch unreachable else ""; @@ -72,10 +69,17 @@ pub fn render() void { y += 8; const perf = main.threadPool.performance.read(); const values = comptime std.enums.values(TaskType); + var totalUtime: i64 = 0; + for(values) |task| + totalUtime += perf.utime[@intFromEnum(task)]; + draw.print("total task time: {} µs", .{totalUtime}, 0, y, 8, .left); + y += 8; for(values) |t| { const name = @tagName(t); const i = @intFromEnum(t); - draw.print(" {s} time: {} ms/frame ({} µs/task)", .{name, @divFloor(perf.utime[i], 1000*trackedFrames), @divFloor(perf.utime[i], @max(1, perf.tasks[i]))}, 0, y, 8, .left); + const taskTime = @divFloor(perf.utime[i], @max(1, perf.tasks[i])); + const relativeTime = 100.0 * @as(f32, @floatFromInt(perf.utime[i])) / @as(f32, @floatFromInt(totalUtime)); + draw.print(" {s}: {} µs/task ({d:.1}%)", .{name, taskTime, relativeTime}, 0, y, 8, .left); y += 8; } draw.print("Mesh Queue size: {}", .{main.renderer.mesh_storage.updatableList.items.len}, 0, y, 8, .left); From 01358f23e0a57d5f776606065919b24bf28673bf Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sat, 12 Oct 2024 23:06:12 -0700 Subject: [PATCH 23/25] capitalize Total task time --- src/gui/windows/debug.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index ef3ade671..3133abd96 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -72,7 +72,7 @@ pub fn render() void { var totalUtime: i64 = 0; for(values) |task| totalUtime += perf.utime[@intFromEnum(task)]; - draw.print("total task time: {} µs", .{totalUtime}, 0, y, 8, .left); + draw.print("Total task time: {} µs", .{totalUtime}, 0, y, 8, .left); y += 8; for(values) |t| { const name = @tagName(t); From 85422a85ea3a5255f80f917d9ba9587e5bae59cb Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 20 Oct 2024 18:14:27 -0700 Subject: [PATCH 24/25] remove total task time --- src/gui/windows/debug.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig index 3133abd96..c55108259 100644 --- a/src/gui/windows/debug.zig +++ b/src/gui/windows/debug.zig @@ -72,8 +72,6 @@ pub fn render() void { var totalUtime: i64 = 0; for(values) |task| totalUtime += perf.utime[@intFromEnum(task)]; - draw.print("Total task time: {} µs", .{totalUtime}, 0, y, 8, .left); - y += 8; for(values) |t| { const name = @tagName(t); const i = @intFromEnum(t); From d6989adb8710c4c5360f9fe89c2d86bfec073991 Mon Sep 17 00:00:00 2001 From: Archbirdplus Date: Sun, 20 Oct 2024 18:25:51 -0700 Subject: [PATCH 25/25] destroy performance on deinit --- src/utils.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils.zig b/src/utils.zig index b34ef2f2b..5a1f44991 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1108,6 +1108,7 @@ pub const ThreadPool = struct { // MARK: ThreadPool } self.allocator.free(self.currentTasks); self.allocator.free(self.threads); + self.allocator.destroy(self.performance); } pub fn closeAllTasksOfType(self: ThreadPool, vtable: *const VTable) void {