Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zig contribution and Benchmarking on Github actions runner #30

Merged
merged 14 commits into from
Sep 28, 2023
38 changes: 38 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Benchmark

on:
pull_request:
branches:
- main
push:
branches:
- main

jobs:
run-benchmarks:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: '1.21.1'
- name: Install crystal
uses: crystal-lang/install-crystal@v1
- name: Install zig
uses: goto-bus-stop/setup-zig@v2
- name: Install Julia
uses: julia-actions/setup-julia@v1
- name: Install Vlang
uses: vlang/[email protected]
- name: Install jq
run: sudo apt-get install -y jq
- name: Install odin
run: wget -O odin.zip https://github.com/odin-lang/Odin/releases/download/dev-2023-08/odin-ubuntu-amd64-dev-2023-08.zip && mkdir odin_exe && unzip odin.zip -d odin_exe && echo -e 'export PATH=$(pwd)/odin_exe:"$PATH"\n' >> ~/.bashrc && chmod +x odin_exe/odin
- name: Install hyperfine for benchmarking
run: cargo install hyperfine
- name: Run Benchmark
run: ./run.sh all
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ ols.json
odin/related
.dart_tool/
v/related

# Zig
zig-cache
zig/main
zig/main.o
1 change: 0 additions & 1 deletion go.work
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
go 1.21.1

use (
./go
./go_con
Expand Down
2 changes: 0 additions & 2 deletions go/go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
module g.io/related

go 1.21.1

require github.com/goccy/go-json v0.10.2

require github.com/ugurcsen/gods-generic v0.10.4
2 changes: 0 additions & 2 deletions go_con/go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
module g.io/related_concurrent

go 1.21.1

require github.com/goccy/go-json v0.10.2
47 changes: 36 additions & 11 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ run_crystal() {

}

run_zig() {
echo "Running Zig" &&
cd ./zig &&
zig build-exe -lc -O ReleaseFast main.zig
if [ $HYPER == 1 ]; then
command hyperfine -r 10 -w 3 --show-output "./main"
else
command time -f '%es %Mk' ./main
fi

check_output "related_posts_zig.json"
}

run_julia_v1() {
echo "Running Julia v1" &&
cd ./julia &&
Expand Down Expand Up @@ -207,6 +220,10 @@ elif [ "$first_arg" = "cr" ]; then

run_crystal

elif [ "$first_arg" = "zig" ]; then

run_zig

elif [ "$first_arg" = "jul1" ]; then

run_julia_v1
Expand All @@ -229,16 +246,22 @@ elif [ "$first_arg" = "v" ]; then

elif [ "$first_arg" = "all" ]; then

echo "running all" &&
run_go &&
run_go_concurrent &&
run_rust &&
run_rust_rayon &&
run_python &&
run_python_np &&
run_crystal &&
run_julia_v1 &&
run_julia_v2
echo -e "Running all\n" &&
run_go || echo -e "\n" &&
run_go_concurrent || echo -e "\n" &&
run_rust || echo -e "\n" &&
run_rust_rayon || echo -e "\n" &&
run_python || echo -e "\n" &&
run_python_np || echo -e "\n" &&
run_crystal || echo -e "\n" &&
run_zig || echo -e "\n" &&
run_julia_v1 || echo -e "\n" &&
run_julia_v2 || echo -e "\n" &&
run_odin || echo -e "\n" &&
run_jq || echo -e "\n" &&
run_vlang || echo -e "\n" &&
echo -e "Finished running all\n"


elif [ "$first_arg" = "clean" ]; then

Expand All @@ -251,10 +274,12 @@ elif [ "$first_arg" = "clean" ]; then
cd .. &&
cd rust_rayon && cargo clean &&
cd .. &&
cd zig && rm -f main main.o &&
cd ..
rm -f related_*.json

else

echo "Valid args: go | go_con | rust | rust_ray | py | numpy | cr | odin | jq | jul1 | jul2 | v | all | clean. Unknown argument: $first_arg"
echo "Valid args: go | go_con | rust | rust_ray | py | numpy | cr | zig | odin | jq | jul1 | jul2 | v | all | clean. Unknown argument: $first_arg"

fi
62 changes: 62 additions & 0 deletions zig/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const std = @import("std");
var allocator = std.heap.c_allocator;
const post = struct { _id: []const u8, title: []const u8, tags: [][]const u8 };
const posts = []post;
const constop_posts = struct { _id: *const []const u8, tags: *const [][]const u8, related: []*post };
const stdout = std.io.getStdOut().writer();

fn lessthan(context: void, lhs: usize, rhs: usize) bool {
_ = context;
return lhs < rhs;
}

pub fn main() !void {
const file = try std.fs.cwd().openFile("../posts.json", .{});
defer file.close();
const arr_posts = std.ArrayList(usize);
var map = std.StringHashMap(arr_posts).init(allocator);
defer map.deinit();
var json_reader = std.json.reader(allocator, file.reader());
defer json_reader.deinit();
const parsed = try std.json.parseFromTokenSource(posts, allocator, &json_reader, .{});
defer parsed.deinit();

const start = try std.time.Instant.now();

for (parsed.value, 0..) |post_ele, i| {
for (post_ele.tags) |tag| {
var g_p = try map.getOrPut(tag);
if (g_p.found_existing) {
try g_p.value_ptr.*.append(i);
} else {
var temp = arr_posts.init(allocator);
try temp.append(i);
g_p.value_ptr.* = temp;
}
}
}
var op = std.ArrayList(constop_posts).init(allocator);
for (0..parsed.value.len) |post_index| {
var top_5 = std.ArrayList(*post).init(allocator);
var rel_posts_tags: [6000]usize = [_]usize{0} ** 6000;
for (parsed.value[post_index].tags) |tag| {
const tag_posts = map.getPtr(tag).?;
for (0..tag_posts.*.items.len) |i_t| {
if (tag_posts.*.items[i_t] != post_index) rel_posts_tags[tag_posts.*.items[i_t]] += 1;
}
}
var n: usize = 5;
while (n > 0) : (n -= 1) {
const index = std.sort.argMax(usize, &rel_posts_tags, {}, lessthan).?;
try top_5.append(&parsed.value[index]);
rel_posts_tags[index] = 0;
}

try op.append(.{ ._id = &parsed.value[post_index]._id, .tags = &parsed.value[post_index].tags, .related = try top_5.toOwnedSlice() });
}
const end = try std.time.Instant.now();
try stdout.print("Processing time (w/o IO): {d}ms\n", .{@divFloor(end.since(start), std.time.ns_per_ms)});
const op_file = try std.fs.cwd().createFile("../related_posts_zig.json", .{});
defer op_file.close();
try std.json.stringify(try op.toOwnedSlice(), .{}, op_file.writer());
}