phased-executor #4

Merged
zack merged 5 commits from phased-executor into master 2026-04-03 01:53:24 +00:00
Showing only changes of commit fd3cd1b6e6 - Show all commits

View File

@@ -243,63 +243,54 @@ exec_join :: proc(executor: ^Executor($T)) {
import "core:fmt" import "core:fmt"
import "core:testing" import "core:testing"
when ODIN_TEST { @(test)
@(private = "file") stress_test_executor :: proc(t: ^testing.T) {
STRESS_TOTAL_CMDS :: 200_000 STRESS_TOTAL_CMDS :: 200_000
@(private = "file")
STRESS_NUM_THREADS :: 8 STRESS_NUM_THREADS :: 8
@(private = "file")
STRESS_NUM_ROUNDS :: 100 STRESS_NUM_ROUNDS :: 100
@(private = "file")
STRESS_CMDS_PER_ROUND :: STRESS_TOTAL_CMDS / STRESS_NUM_ROUNDS STRESS_CMDS_PER_ROUND :: STRESS_TOTAL_CMDS / STRESS_NUM_ROUNDS
@(private = "file")
Stress_Cmd :: union { Stress_Cmd :: union {
Stress_Payload, Stress_Payload,
} }
@(private = "file")
Stress_Payload :: struct { Stress_Payload :: struct {
exec_counts: ^[STRESS_TOTAL_CMDS]uint, exec_counts: ^[STRESS_TOTAL_CMDS]uint,
id: int, id: int,
} }
@(private = "file")
stress_handler :: proc(command: Stress_Cmd) { stress_handler :: proc(command: Stress_Cmd) {
payload := command.(Stress_Payload) payload := command.(Stress_Payload)
intrinsics.atomic_add_explicit(&payload.exec_counts[payload.id], 1, .Release) intrinsics.atomic_add_explicit(&payload.exec_counts[payload.id], 1, .Release)
} }
@(test) exec_counts := new([STRESS_TOTAL_CMDS]uint)
stress_test_executor :: proc(t: ^testing.T) { defer free(exec_counts)
exec_counts := new([STRESS_TOTAL_CMDS]uint)
defer free(exec_counts)
executor: Executor(Stress_Cmd) executor: Executor(Stress_Cmd)
init_executor(&executor, STRESS_NUM_THREADS, stress_handler, spin_limit = 500) init_executor(&executor, STRESS_NUM_THREADS, stress_handler, spin_limit = 500)
for round in 0 ..< STRESS_NUM_ROUNDS { for round in 0 ..< STRESS_NUM_ROUNDS {
base := round * STRESS_CMDS_PER_ROUND base := round * STRESS_CMDS_PER_ROUND
for i in 0 ..< STRESS_CMDS_PER_ROUND { for i in 0 ..< STRESS_CMDS_PER_ROUND {
exec_command(&executor, Stress_Payload{exec_counts = exec_counts, id = base + i}) exec_command(&executor, Stress_Payload{exec_counts = exec_counts, id = base + i})
}
exec_join(&executor)
} }
exec_join(&executor)
missed, duped: int
for i in 0 ..< STRESS_TOTAL_CMDS {
count := exec_counts[i]
if count == 0 do missed += 1
else if count > 1 do duped += 1
}
testing.expect(t, missed == 0, fmt.tprintf("Missed %d / %d commands", missed, STRESS_TOTAL_CMDS))
testing.expect(t, duped == 0, fmt.tprintf("Duplicated %d / %d commands", duped, STRESS_TOTAL_CMDS))
// Explicitly destroy to verify clean shutdown.
// If destroy_executor returns, all threads received the nil sentinel and exited,
// and thread.pool_join completed without deadlock.
destroy_executor(&executor)
testing.expect(t, !executor.initialized, "Executor still marked initialized after destroy")
} }
missed, duped: int
for i in 0 ..< STRESS_TOTAL_CMDS {
count := exec_counts[i]
if count == 0 do missed += 1
else if count > 1 do duped += 1
}
testing.expect(t, missed == 0, fmt.tprintf("Missed %d / %d commands", missed, STRESS_TOTAL_CMDS))
testing.expect(t, duped == 0, fmt.tprintf("Duplicated %d / %d commands", duped, STRESS_TOTAL_CMDS))
// Explicitly destroy to verify clean shutdown.
// If destroy_executor returns, all threads received the nil sentinel and exited,
// and thread.pool_join completed without deadlock.
destroy_executor(&executor)
testing.expect(t, !executor.initialized, "Executor still marked initialized after destroy")
} }