From 5c8eb765ad9c88625be20530b64e037008c6b7e0 Mon Sep 17 00:00:00 2001 From: GigabiteStudios Date: Sat, 19 Apr 2025 23:34:44 +0000 Subject: [PATCH] Made Multithreading Better --- remake/remake.py | 90 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 10 deletions(-) diff --git a/remake/remake.py b/remake/remake.py index 2a60587..8ae70ce 100644 --- a/remake/remake.py +++ b/remake/remake.py @@ -184,6 +184,13 @@ def link_objects(obj_files, link_dirs, libs): print(e.stderr.decode()) log(f"[ERROR] {' '.join(cmd)}\n{e.stderr.decode()}") sys.exit(1) + + + +import itertools +import math +import shutil + def build(): build_start = time.time() @@ -194,7 +201,66 @@ def build(): link_dirs, libs, extra_includes = resolve_packages() all_includes = INCLUDE_DIRS + extra_includes - compile_tasks = [] + compile_tasks = {} + status = {} + status_lock = threading.Lock() + + + + + last_status_snapshot = {} + + def print_status(): + with print_lock: + # Avoid redrawing if nothing changed + snapshot = {k: v for k, v in status.items() if v == "compiling"} + if snapshot == last_status_snapshot: + return + last_status_snapshot.clear() + last_status_snapshot.update(snapshot) + + # Clear panel area only, not entire terminal + term_size = shutil.get_terminal_size((80, 20)) + max_name_len = 24 + grid_cols = max(1, term_size.columns // (max_name_len + 6)) + + active = list(snapshot.keys()) + rows = math.ceil(len(active) / grid_cols) + grid = [[""] * grid_cols for _ in range(rows)] + + for i, src in enumerate(active): + col = i % grid_cols + row = i // grid_cols + name = src.name[:max_name_len].ljust(max_name_len) + grid[row][col] = f"[🔧] {name}" + + # Draw status block + sys.stdout.write("\033[s") # Save cursor + sys.stdout.write(f"\033[1;1H") # Move to top-left + sys.stdout.write("\033[0J") # Clear below + print(color(f"🔨 Compiling ({len(active)} jobs)...", Colors.OKCYAN)) + for row in grid: + if any(cell.strip() for cell in row): + print(" ".join(row)) + print(f"\n{color('⏱ Elapsed:', Colors.GRAY)} {time.time() - build_start:.1f}s") + sys.stdout.write("\033[u") # Restore cursor + sys.stdout.flush() + + + + def compile_and_track(source, obj): + with status_lock: + status[source] = "compiling" + print_status() + + result = compile_source(source, obj, all_includes) + + with status_lock: + status.pop(source, None) + print_status() + + return result + with ThreadPoolExecutor() as executor: for source in cpp_files: obj = obj_path(source) @@ -213,23 +279,27 @@ def build(): break if needs_build: - compile_tasks.append(executor.submit(compile_source, source, obj, all_includes)) - else: - with print_lock: - print(f"\r{color('👌 Up-to-date:', Colors.GRAY)} {source}{' ' * 20}", end="", flush=True) - + future = executor.submit(compile_and_track, source, obj) + compile_tasks[future] = source obj_files.append(obj) - for task in as_completed(compile_tasks): - if not task.result(): + print_status() + + for future in as_completed(compile_tasks): + if not future.result(): sys.exit(1) - print() + banner("📦 Linking") link_objects(obj_files, link_dirs, libs) + banner("✅ Build Complete") print(color(f"⏱ Build time: {time.time() - build_start:.2f}s", Colors.OKCYAN)) + + + + def run(): build() if TARGET.exists(): @@ -280,7 +350,7 @@ if __name__ == "__main__": try: if "clean" in sys.argv: clean() - if "clear" in sys.argv: + elif "clear" in sys.argv: clean() elif "run" in sys.argv: run()