diff options
Diffstat (limited to 'salis.py')
| -rwxr-xr-x | salis.py | 97 |
1 files changed, 52 insertions, 45 deletions
@@ -1,7 +1,7 @@ #!/usr/bin/env -S PYTHONDONTWRITEBYTECODE=1 python import contextlib -import datetime +import ctypes import json import os import random @@ -9,7 +9,6 @@ import shutil import sqlite3 import subprocess import sys -import threading import urllib.parse import urllib.request @@ -117,28 +116,42 @@ for parser, option in parser_map: args = main_parser.parse_args() # ------------------------------------------------------------------------------ -# Logging +# Bootstrap logging system # ------------------------------------------------------------------------------ -log_lock = threading.Lock() +tempdir = TemporaryDirectory(prefix="salis_", delete=not args.keep_temp_dir) +logger_flags = set() +logger_includes = set() +logger_defines = set() -def now(): - return f"{datetime.datetime.now():%Y-%m-%d %H:%M:%S}" +logger_flags.update({*args.compiler_flags.split(), "-shared", "-fPIC"}) +logger_includes.update({"assert.h", "stdarg.h", "stdbool.h", "stdio.h", "stdlib.h", "time.h", "unistd.h"}) -def info(msg, val=""): - with log_lock: print(f"\r{now()} ++ \033[1;34mINFO\033[0m {msg}", val, flush=True) +if args.optimized: + logger_flags.add("-O3") + logger_defines.add("-DNDEBUG") +else: + logger_flags.add("-ggdb") -def warn(msg, val=""): - with log_lock: print(f"\r{now()} ++ \033[1;33mWARN\033[0m {msg}", val, flush=True) +logger_so = os.path.join(tempdir.name, "log.so") +logger_build_cmd = [args.compiler, "core/logger.c", "-o", logger_so] +logger_build_cmd.extend(logger_flags) +logger_build_cmd.extend(sum(map(lambda include: ["-include", include], logger_includes), [])) +logger_build_cmd.extend(logger_defines) +subprocess.run(logger_build_cmd, check=True) -def error(msg, val=""): - with log_lock: print(f"\r{now()} ++ \033[1;31mERROR\033[0m {msg}", val, flush=True) - sys.exit(1) +logger_dll = ctypes.CDLL(logger_so) +def info(msg): logger_dll.log_info(msg.encode()) +def warn(msg): logger_dll.log_warn(msg.encode()) +def erro(msg): logger_dll.log_erro(msg.encode()) and sys.exit(1) # ------------------------------------------------------------------------------ # Load configuration # ------------------------------------------------------------------------------ info(description) -info(f"Called '{prog} {args.command}' with the following options:", vars(args)) +info(f"Called '{prog} {args.command}' with the following options: {vars(args)}") +info(f"Using temporary directory: {tempdir.name}") +info(f"Using logging dl: {logger_so}") +info(f"Built with command: {logger_build_cmd}") if args.command in ["load", "new", "serve"]: sim_dir = os.path.join(os.environ["HOME"], ".salis", args.name) @@ -147,7 +160,7 @@ if args.command in ["load", "new", "serve"]: if args.command in ["load", "serve"]: if not os.path.isdir(sim_dir): - error("No simulation found named:", args.name) + erro(f"No simulation found named: {args.name}") sys.path.append(sim_dir) import opts @@ -157,25 +170,25 @@ if args.command in ["load", "serve"]: for key, val in opt_vars.items(): setattr(args, key, val) - info(f"Sourced configuration from: '{sim_opts}':", opt_vars) + info(f"Sourced configuration from: '{sim_opts}': {opt_vars}") if args.command in ["new"]: if args.data_push_pow and args.data_push_pow < args.sync_pow: - error("Data push power must be equal or greater than thread sync power") + erro("Data push power must be equal or greater than thread sync power") if os.path.isdir(sim_dir) and args.force: - warn("Force flag used! Wiping old simulation at:", sim_dir) + warn(f"Force flag used! Wiping old simulation at: {sim_dir}") shutil.rmtree(sim_dir) if os.path.isdir(sim_dir): - error("Simulation directory found at:", sim_dir) + erro(f"Simulation directory found at: {sim_dir}") if args.seed == -1: args.seed = random.getrandbits(64) - info("Using random seed:", args.seed) + info(f"Using random seed: {args.seed}") - info("Creating new simulation directory at:", sim_dir) - info("Creating configuration file at:", sim_opts) + info(f"Creating new simulation directory at: {sim_dir}") + info(f"Creating configuration file at: {sim_opts}") os.mkdir(sim_dir) @@ -193,7 +206,7 @@ if args.command in ["new"]: # Load architecture variables # ------------------------------------------------------------------------------ arch_path = os.path.join("arch", args.arch) -info("Loading architecture variables from:", os.path.join(arch_path, "arch_vars.py")) +info(f"Loading architecture variables from: {os.path.join(arch_path, "arch_vars.py")}") sys.path.append(arch_path) from arch_vars import ArchVars arch_vars = ArchVars(args) @@ -209,7 +222,7 @@ if args.command in ["serve"]: "vue@latest": "https://unpkg.com/vue@latest", } - info("Updating vendors:", vendors) + info(f"Updating vendors: {vendors}") for file, url in vendors.items(): with urllib.request.urlopen(url) as response: @@ -235,18 +248,15 @@ if args.command in ["serve"]: sqlx_links.add("-lz") - sqlx_tempdir = TemporaryDirectory(prefix="salis_sqlx_", delete=not args.keep_temp_dir) - info("Created a temporary salis SQLite extension directory at:", sqlx_tempdir.name) - - sqlx_so = os.path.join(sqlx_tempdir.name, "render.so") - info("Building salis SQLite extension at:", sqlx_so) + sqlx_so = os.path.join(tempdir.name, "render.so") + info(f"Building salis SQLite extension at: {sqlx_so}") sqlx_build_cmd = [args.compiler, "core/render.c", "-o", sqlx_so] sqlx_build_cmd.extend(sqlx_flags) sqlx_build_cmd.extend(sqlx_defines) sqlx_build_cmd.extend(sqlx_links) - info("Using build command:", sqlx_build_cmd) + info(f"Using build command: {sqlx_build_cmd}") subprocess.run(sqlx_build_cmd, check=True) # Generate configuration so front-end knows how to render the plots. @@ -309,8 +319,8 @@ if args.command in ["serve"]: for key in arch_vars.heatmaps: heatmaps[key] = (heatmaps[key] if key in heatmaps else {}) | arch_vars.heatmaps[key] - info("Generated plot configuration:", plots) - info("Generated heatmap configuration:", heatmaps) + info(f"Generated plot configuration: {plots}") + info(f"Generated heatmap configuration: {heatmaps}") # NOTE: this server implementation is very minimal and has no built-in security. # Please do not put this on the internet! Only run the data server within secure @@ -411,7 +421,7 @@ if args.command in ["bench", "new"] and args.anc is not None: anc_path = os.path.join("anc", args.arch, f"{args.anc}.asm") if not os.path.isfile(anc_path): - error("Could not find ancestor file:", anc_path) + erro(f"Could not find ancestor file: {anc_path}") with open(anc_path, "r") as file: lines = file.read().splitlines() @@ -433,10 +443,10 @@ if args.command in ["bench", "new"] and args.anc is not None: break if not found: - error("Unrecognized instruction in ancestor file:", line) + erro(f"Unrecognized instruction in ancestor file: {line}") anc_bytes_repr = ",".join(map(str, anc_bytes)) - info(f"Compiled ancestor file '{anc_path}' into byte array:", f"{{{anc_bytes_repr}}}") + info(f"Compiled ancestor file '{anc_path}' into byte array: {{{anc_bytes_repr}}}") # ------------------------------------------------------------------------------ # Populate compiler flags @@ -446,7 +456,7 @@ includes = set() defines = set() links = set() -flags.update({*args.compiler_flags.split(), f"-Iarch/{args.arch}"}) +flags.update({*args.compiler_flags.split(), f"-Iarch/{args.arch}", "-Icore"}) defines.add(f"-DARCH=\"{args.arch}\"") defines.add(f"-DCOMMAND_{args.command.upper()}") @@ -488,7 +498,7 @@ if args.command in ["bench", "new"]: if args.command in ["load", "new"]: ui_path = os.path.join("ui", args.ui) - info("Loading UI variables from:", os.path.join(ui_path, "ui_vars.py")) + info(f"Loading UI variables from: {os.path.join(ui_path, "ui_vars.py")}") sys.path.append(ui_path) from ui_vars import UIVars ui_vars = UIVars(args) @@ -509,7 +519,7 @@ if args.command in ["load", "new"]: defines.add(f"-DDATA_PUSH_INTERVAL={2 ** args.data_push_pow}ul") defines.add(f"-DDATA_PUSH_PATH=\"{data_push_path}\"") links.update({"-lsqlite3", "-lz"}) - info("Data will be aggregated at:", data_push_path) + info(f"Data will be aggregated at: {data_push_path}") else: warn("Data aggregation disabled") @@ -524,11 +534,8 @@ if args.command in ["load", "new"]: # ------------------------------------------------------------------------------ # Build executable # ------------------------------------------------------------------------------ -tempdir = TemporaryDirectory(prefix="salis_", delete=not args.keep_temp_dir) -info("Created a temporary salis directory at:", tempdir.name) - salis_bin = os.path.join(tempdir.name, "salis_bin") -info("Building salis binary at:", salis_bin) +info(f"Building salis binary at: {salis_bin}") build_cmd = [args.compiler, "core/salis.c", "-o", salis_bin] build_cmd.extend(flags) @@ -536,7 +543,7 @@ build_cmd.extend(sum(map(lambda include: ["-include", include], includes), [])) build_cmd.extend(defines) build_cmd.extend(links) -info("Using build command:", build_cmd) +info(f"Using build command: {build_cmd}") subprocess.run(build_cmd, check=True) # ------------------------------------------------------------------------------ @@ -547,7 +554,7 @@ info("Running salis binary...") run_cmd = [args.pre_cmd] if args.pre_cmd else [] run_cmd.append(salis_bin) -info("Using run command:", " ".join(run_cmd)) +info(f"Using run command: {" ".join(run_cmd)}") salis_sp = subprocess.Popen(run_cmd, stdout=sys.stdout, stderr=sys.stderr) # When using signals (e.g. SIGTERM), they must be sent to the entire process group @@ -561,4 +568,4 @@ except KeyboardInterrupt: code = salis_sp.returncode if code != 0: - error("Salis binary returned code:", code) + erro(f"Salis binary returned code: {code}") |
