multi-threaded the test runner
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 3 Dec 2021 04:45:28 +0000 (22:45 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 3 Dec 2021 04:45:28 +0000 (22:45 -0600)
scripts/run_tests.onyx

index 4cda81e9f79e3d9affd7a078826a0afb1e4731b6..73c88d97912ff5d5e63f5bae4da570c8cbe3d7d7 100644 (file)
@@ -85,34 +85,98 @@ find_onyx_files :: (root: str, cases: ^[..] str) {
     return;
 }
 
+#if false {
+    divide_array :: (arr: [] $T, divisions: [] [] T) {
+        if divisions.count == 0 do return;
+
+        chunk_size := arr.count / divisions.count;
+
+        i := 0;
+        for ^ divisions {
+            low := i*chunk_size;
+            high := (i+1)*chunk_size;
+            if i == divisions.count - 1 do high = divisions.count;
+            *it = arr[low .. high];
+            i += 1;
+        }
+    }
+}
+
+distributor :: (arr: [] $T) -> Iterator(T) {
+    Context :: struct (T: type_expr) {
+        mutex: sync.Mutex;
+        arr: [] T;
+        curr_pos: i32;
+    }
+
+    next :: (use c: ^Context($T)) -> (T, bool) {
+        sync.scoped_mutex(^mutex);
+
+        use package core.intrinsics.onyx {__zero_value}
+        if curr_pos >= arr.count do return __zero_value(T), false;
+
+        defer curr_pos += 1;
+        return arr[curr_pos], true;
+    }
+
+    close :: (use c: ^Context($T)) {
+        // This will leak because it shouldn't be freed.
+    }
+
+    c := new(Context(T));
+    sync.mutex_init(^c.mutex);
+    c.arr = arr;
+    c.curr_pos = 0;
+
+    return .{ c, #solidify next {T=T}, #solidify close {T=T}};
+}
+
 main :: (args) => {
     test_folder := "./tests";
 
-    onyx_cmd: str;
+    #persist onyx_cmd: str;
     switch runtime.OS {
-        case runtime.OS_Linux do onyx_cmd = "./bin/onyx";
+        case runtime.OS_Linux  {
+            onyx_cmd = "./bin/onyx";
+            if args.count > 1 {
+                if string.from_cstr(args[1]) == "debug" do onyx_cmd = "./bin/onyx-debug";
+            }
+        }
         case runtime.OS_Windows do onyx_cmd = "onyx.exe";
     }
 
+    test_cases :: (cases) => {
+        for *cases {
+            printf("[{}]  Running test {}...\n", context.thread_id, it);
+
+            proc := io.process_spawn(onyx_cmd, .["run", it]);
+            defer io.process_destroy(^proc);
+
+            proc_reader := io.reader_make(^proc);
+            output := io.read_all(^proc_reader);
+            defer memory.free_slice(^output);
+
+            if exit := io.process_wait(^proc); exit != .Success {
+                // Error running the test case
+                println(exit);
+                println(output);
+            }
+        }
+    }
+
     cases := array.make(str);
     find_onyx_files(test_folder, ^cases);
-    for cases {
-        printf("Running test {}...\n", it);
 
-        proc := io.process_spawn(onyx_cmd, .["run", it]);
-        defer io.process_destroy(^proc);
+    Thread_Count :: 3
+    #persist threads: [Thread_Count] thread.Thread;
 
-        proc_reader := io.reader_make(^proc);
-        output := io.read_all(^proc_reader);
-        defer memory.free_slice(^output);
+    case_iterator := distributor(cases);
 
-        if exit := io.process_wait(^proc); exit != .Success {
-            // Error running the test case
-            println(exit);
-            println(output);
-        }
+    for Thread_Count {
+        thread.spawn(^threads[it], ^case_iterator, test_cases);
     }
 
-    // Ensure the corresponding correct output file present
-    // Run tests, checking their output
+    test_cases(^case_iterator);
+    for ^ threads do thread.join(it);
+    println("Done");
 }
\ No newline at end of file