Skip to content

Commit ccca80b

Browse files
committed
initial commit
1 parent bf1e493 commit ccca80b

9 files changed

Lines changed: 245 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.zig-cache/*
2+
zig-out/*

build.zig

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const std = @import("std");
2+
3+
pub fn build(b: *std.Build) void {
4+
const target = b.standardTargetOptions(.{});
5+
const optimize = b.standardOptimizeOption(.{});
6+
//
7+
const kernelmaster_zig = b.createModule(.{
8+
.root_source_file = b.path("./src/kernelmaster.zig"),
9+
});
10+
//
11+
const exe = b.addExecutable(.{
12+
.name = "kernelmaster",
13+
.root_source_file = b.path("src/main.zig"),
14+
.target = target,
15+
.optimize = optimize,
16+
});
17+
exe.linkLibC();
18+
exe.root_module.addImport("kernelmaster", kernelmaster_zig);
19+
b.installArtifact(exe);
20+
const run_cmd = b.addRunArtifact(exe);
21+
run_cmd.step.dependOn(b.getInstallStep());
22+
if (b.args) |args| {
23+
run_cmd.addArgs(args);
24+
}
25+
const run_step = b.step("run", "Run the app");
26+
run_step.dependOn(&run_cmd.step);
27+
//
28+
const exe_unit_tests = b.addTest(.{
29+
.root_source_file = b.path("src/main.zig"),
30+
.target = target,
31+
.optimize = optimize,
32+
});
33+
exe_unit_tests.linkLibC();
34+
exe_unit_tests.root_module.addImport("kernelmaster", kernelmaster_zig);
35+
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
36+
run_exe_unit_tests.has_side_effects = true;
37+
const test_step = b.step("test", "Run unit tests");
38+
test_step.dependOn(&run_exe_unit_tests.step);
39+
}

build.zig.zon

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.{
2+
.name = "kernelmaster",
3+
.version = "0.0.0",
4+
.minimum_zig_version = "0.13.0",
5+
.dependencies = .{},
6+
.paths = .{
7+
"build.zig",
8+
"build.zig.zon",
9+
"src",
10+
"LICENSE",
11+
"README.md",
12+
},
13+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub const kernelmaster_error = error {
2+
kernelmaster_internal_error,
3+
kernelmaster_thread_error,
4+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const std = @import("std");
2+
const return_value = @import("../return_value/return_value.zig").return_value;
3+
const thread_info = @import("../thread_info/thread_info.zig").thread_info;
4+
const error_sets = @import("../error_sets/error_sets.zig");
5+
6+
pub const operation = struct {
7+
thread: std.Thread,
8+
result: *return_value,
9+
allocator: std.mem.Allocator,
10+
11+
fn primary_thread(allocator: std.mem.Allocator, result: *return_value,nthreads: usize, nkernels: u128, comptime kernel: anytype, args: anytype) void {
12+
result.* = return_value.success;
13+
if (nthreads == 0) {
14+
result.* = return_value.internal_error;
15+
return;
16+
}
17+
const threads =
18+
allocator.alloc(std.Thread, nthreads)
19+
catch {
20+
result.* = return_value.internal_error;
21+
return;
22+
};
23+
defer allocator.free(threads);
24+
const thread_returns =
25+
allocator.alloc(return_value, nthreads)
26+
catch {
27+
result.* = return_value.internal_error;
28+
return;
29+
};
30+
defer allocator.free(thread_returns);
31+
32+
const thread_info_gen = thread_info.generator.init(nthreads, nkernels, thread_returns);
33+
for (0.., thread_returns, threads) |nthreads_launched, *this_thread_return, *this_thread| {
34+
this_thread_return.* = return_value.success;
35+
this_thread.* =
36+
std.Thread.spawn(.{}, kernel, .{thread_info_gen.gen(nthreads_launched)} ++ args)
37+
catch {
38+
for (threads[0..nthreads_launched]) |thread| {
39+
thread.join();
40+
}
41+
result.* = return_value.internal_error;
42+
return;
43+
};
44+
}
45+
46+
for (0.., thread_returns, threads) |i, thread_returned, thread| {
47+
thread.join();
48+
if (thread_returned != return_value.success) {
49+
result.* = return_value.thread_error;
50+
for (threads[i..]) |thread_quickjoin| {
51+
thread_quickjoin.join();
52+
}
53+
return;
54+
}
55+
}
56+
return;
57+
}
58+
pub fn launch(allocator: std.mem.Allocator, nthreads: usize, nkernels: u128, comptime kernel: anytype, args: anytype) error_sets.kernelmaster_error!operation {
59+
const result: *return_value = allocator.create(return_value) catch return error.kernelmaster_internal_error;
60+
errdefer allocator.destroy(result);
61+
return .{
62+
.thread = std.Thread.spawn(
63+
.{},
64+
primary_thread,
65+
.{
66+
allocator,
67+
result,
68+
nthreads,
69+
nkernels,
70+
kernel,
71+
args,
72+
}
73+
) catch return error.kernelmaster_internal_error,
74+
.result = result,
75+
.allocator = allocator,
76+
};
77+
}
78+
pub fn sync(op: operation) !void {
79+
std.Thread.join(op.thread);
80+
const r: return_value = op.result.*;
81+
op.allocator.destroy(op.result);
82+
switch (r) {
83+
return_value.success => return,
84+
return_value.thread_error => return error.kernelmaster_thread_error,
85+
else => return error.kernelmaster_internal_error,
86+
}
87+
}
88+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub const return_value = enum(u8) {
2+
success = 0,
3+
internal_error = 15,
4+
thread_error = 255,
5+
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const return_value = @import("../return_value/return_value.zig").return_value;
2+
3+
pub const thread_info = struct {
4+
thread_return: *return_value,
5+
thread_id: usize,
6+
nthreads: usize,
7+
kernel_begin: u128,
8+
kernel_end: u128,
9+
10+
pub const generator = struct {
11+
remainder: usize,
12+
remainder_end: u128,
13+
perthread: u128,
14+
nthreads: usize,
15+
nkernels: u128,
16+
thread_returns: []return_value,
17+
pub fn init(nthreads: usize, nkernels: u128, thread_returns: []return_value) thread_info.generator {
18+
var r: thread_info.generator = .{
19+
.remainder = @intCast(nkernels % nthreads),
20+
.remainder_end = undefined,
21+
.perthread = nkernels / nthreads,
22+
.nthreads = nthreads,
23+
.nkernels = nkernels,
24+
.thread_returns = thread_returns[0..nthreads],
25+
};
26+
r.remainder_end = r.remainder * (1 + r.perthread);
27+
return r;
28+
}
29+
pub fn gen(self: thread_info.generator, i: usize) thread_info {
30+
if (i < self.remainder) {
31+
const kernel_begin: u128 = (1 + self.perthread) * i;
32+
return .{
33+
.thread_return = @ptrCast(self.thread_returns.ptr+i),
34+
.thread_id = i,
35+
.nthreads = self.nthreads,
36+
.kernel_begin = kernel_begin,
37+
.kernel_end = kernel_begin + @as(usize, 1) + self.perthread,
38+
};
39+
} else {
40+
const kernel_begin: u128 = self.remainder_end + (self.perthread * (i - self.remainder));
41+
return .{
42+
.thread_return = @ptrCast(self.thread_returns.ptr+i),
43+
.thread_id = i,
44+
.nthreads = self.nthreads,
45+
.kernel_begin = kernel_begin,
46+
.kernel_end = kernel_begin + self.perthread,
47+
};
48+
}
49+
}
50+
};
51+
};

src/kernelmaster.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const std = @import("std");
2+
const testing = std.testing;
3+
4+
pub const thread_info = @import("./capsules/thread_info/thread_info.zig").thread_info;
5+
pub const operation = @import("./capsules/operation/operation.zig").operation;
6+
7+
pub const error_sets = @import("./capsules/error_sets/error_sets.zig");
8+
9+
pub const return_value = @import("./capsules/return_value/return_value.zig").return_value;
10+
// bellow consts are defined to make it simpler to set a thread's return variable
11+
pub const thread_success = return_value.success;
12+
pub const thread_error = return_value.thread_error;
13+
14+
pub const launch = operation.launch;

src/main.zig

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const std = @import("std");
2+
const kernelmaster = @import("kernelmaster");
3+
4+
fn example_kernel(thread_info: kernelmaster.thread_info, comptime debug: bool) void {
5+
std.time.sleep(1_000_000_00 * @as(u64, thread_info.thread_id));
6+
if (!debug)
7+
return;
8+
std.debug.print("_ {}_id :: {} --> {}\n", .{thread_info.thread_id, thread_info.kernel_begin, thread_info.kernel_end});
9+
var k: u128 = thread_info.kernel_begin;
10+
while (k < thread_info.kernel_end) : (k += 1) {
11+
std.debug.print("|-{}\n", .{k});
12+
}
13+
std.debug.print("^\n", .{});
14+
return;
15+
}
16+
17+
fn kernelmaster_example(comptime debug: bool) !void {
18+
const op = try kernelmaster.operation.launch(std.heap.c_allocator, 7, 12, example_kernel, .{debug});
19+
try op.sync();
20+
return;
21+
}
22+
test "basic kernelmaster functionality" {
23+
try kernelmaster_example(false);
24+
}
25+
26+
pub fn main() void {
27+
kernelmaster_example(true) catch return;
28+
return;
29+
}

0 commit comments

Comments
 (0)