From bb52acc8b7ad073068c9a2dc656d4fecf935d710 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Tue, 16 Jun 2026 18:16:18 +0200 Subject: Adds final tweaks to data client/server --- README.md | 41 +++++++++++++++++++++++++++----- arch/dummy/arch_plots.cpp | 5 ---- arch/dummy/plots.cpp | 5 ++++ arch/v1/arch_plots.cpp | 59 ---------------------------------------------- arch/v1/plots.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++++ core/client.cpp | 3 +-- data.png | Bin 0 -> 1173583 bytes salis.py | 8 ++++++- 8 files changed, 107 insertions(+), 73 deletions(-) delete mode 100644 arch/dummy/arch_plots.cpp create mode 100644 arch/dummy/plots.cpp delete mode 100644 arch/v1/arch_plots.cpp create mode 100644 arch/v1/plots.cpp create mode 100644 data.png diff --git a/README.md b/README.md index a012fdc..7175615 100644 --- a/README.md +++ b/README.md @@ -33,12 +33,12 @@ typically takes less than a second) based on the specified arguments and launches it immediately. Different VM architectures can be implemented as standalone C files, plus an -associated `arch_vars.py` script, within in the `arch/` directory. When creating -a new simulation, you can select a specific architecture using the `--arch` +associated `vars.py` script, within in the `arch/` directory. When creating a +new simulation, you can select a specific architecture using the `--arch` argument. Similarly, different user interfaces are implemented as C files, plus an -associated `ui_vars.py` script, within the `ui/` directory. For example, the +associated `vars.py` script, within the `ui/` directory. For example, the `curses` UI launches a terminal-based simulation visualizer, allowing easy exploration of *SALIS* memory cores and processes. In contrast, the `daemon` UI provides minimal output, making it ideal for running *SALIS* as a background @@ -62,10 +62,39 @@ removed, you can reload the saved simulation with the following command: user@host$ ./salis.py load -n world-1 -o ``` -## Requirements +## Data server and client + +![SALIS data client](data.png) +*SALIS data client showing live simulation data* + +This project includes a native data visualizer that plots live simulation data. +A generic set of plots is configured by default for all VM architectures. Each +architecture may expand on these by configuring its own set of plots within +`arch/{arch}/plots.cpp`. Once a simulation has been created (i.e., exists in +${HOME}/.salis), you may launch the data server with: +```console +user@host$ ./salis.py server -n world-1 -o +``` + +The server may run regardless of whether the simulator itself is running or not. +Once the server is running, you may attach a client from the local network by +running: +```console +user@host$ ./salis.py client -o -i ${SERVER_IP} +``` + +## Dependencies - C compiler - Python - -## Optional Dependencies - SQLite - Zlib + +## Dependencies for curses UI +- NCurses + +## Dependencies for data client +- GLFW +- GLU +- ImGui +- ImPlot +- OpenGL diff --git a/arch/dummy/arch_plots.cpp b/arch/dummy/arch_plots.cpp deleted file mode 100644 index 8cece2f..0000000 --- a/arch/dummy/arch_plots.cpp +++ /dev/null @@ -1,5 +0,0 @@ -std::array, 0> g_arch_traces = {}; -std::array, 0> g_arch_traces_heatmaps = {}; -std::array g_arch_plots = {}; -std::array g_arch_plots_stacked = {}; -std::array g_arch_plots_heatmaps = {}; diff --git a/arch/dummy/plots.cpp b/arch/dummy/plots.cpp new file mode 100644 index 0000000..8cece2f --- /dev/null +++ b/arch/dummy/plots.cpp @@ -0,0 +1,5 @@ +std::array, 0> g_arch_traces = {}; +std::array, 0> g_arch_traces_heatmaps = {}; +std::array g_arch_plots = {}; +std::array g_arch_plots_stacked = {}; +std::array g_arch_plots_heatmaps = {}; diff --git a/arch/v1/arch_plots.cpp b/arch/v1/arch_plots.cpp deleted file mode 100644 index d9147cb..0000000 --- a/arch/v1/arch_plots.cpp +++ /dev/null @@ -1,59 +0,0 @@ -std::array g_arch_traces = std::to_array>({ -#define INST(core, pref, index, label, mnemonic, symbol) \ - {#label "_" #pref "_" #core, #label}, -#define FOR_CORE(i) \ - {"wmb0_" #i, "wmb0_" #i}, \ - {"wmb1_" #i, "wmb1_" #i}, \ - {"wdea_" #i, "wdea_" #i}, \ - INST_SET(i, pop) \ - INST_SET(i, exe) \ - INST_SET(i, wrt) - FOR_CORES -#undef FOR_CORE -#undef INST -}); - -std::array g_arch_traces_heatmaps = std::to_array>({ -#define FOR_CORE(i) \ - {"wev_" #i, "wev_" #i}, \ - {"xev_" #i, "xev_" #i}, - FOR_CORES -#undef FOR_CORE -}); - -std::array g_arch_plots = std::to_array({ - {"wevs", "general", { -#define FOR_CORE(i) "wmb0_" #i, "wmb1_" #i, "wdea_" #i, - FOR_CORES -#undef FOR_CORE - }}, -}); - -std::array g_arch_plots_stacked = std::to_array({ -#define INST(core, pref, index, label, mnemonic, symbol) \ - #label "_" #pref "_" #core, -#define FOR_CORE(i) \ - {"ipop%_" #i, "population", { INST_SET(i, pop) }}, - FOR_CORES -#undef FOR_CORE -#define FOR_CORE(i) \ - {"iexe%_" #i, "population", { INST_SET(i, exe) }}, - FOR_CORES -#undef FOR_CORE -#define FOR_CORE(i) \ - {"iwrt%_" #i, "population", { INST_SET(i, wrt) }}, - FOR_CORES -#undef FOR_CORE -#undef INST -}); - -std::array g_arch_plots_heatmaps = std::to_array({ -#define FOR_CORE(i) \ - {"wev_" #i, "heatmaps", "wev_" #i}, - FOR_CORES -#undef FOR_CORE -#define FOR_CORE(i) \ - {"xev_" #i, "heatmaps", "xev_" #i}, - FOR_CORES -#undef FOR_CORE -}); diff --git a/arch/v1/plots.cpp b/arch/v1/plots.cpp new file mode 100644 index 0000000..d9147cb --- /dev/null +++ b/arch/v1/plots.cpp @@ -0,0 +1,59 @@ +std::array g_arch_traces = std::to_array>({ +#define INST(core, pref, index, label, mnemonic, symbol) \ + {#label "_" #pref "_" #core, #label}, +#define FOR_CORE(i) \ + {"wmb0_" #i, "wmb0_" #i}, \ + {"wmb1_" #i, "wmb1_" #i}, \ + {"wdea_" #i, "wdea_" #i}, \ + INST_SET(i, pop) \ + INST_SET(i, exe) \ + INST_SET(i, wrt) + FOR_CORES +#undef FOR_CORE +#undef INST +}); + +std::array g_arch_traces_heatmaps = std::to_array>({ +#define FOR_CORE(i) \ + {"wev_" #i, "wev_" #i}, \ + {"xev_" #i, "xev_" #i}, + FOR_CORES +#undef FOR_CORE +}); + +std::array g_arch_plots = std::to_array({ + {"wevs", "general", { +#define FOR_CORE(i) "wmb0_" #i, "wmb1_" #i, "wdea_" #i, + FOR_CORES +#undef FOR_CORE + }}, +}); + +std::array g_arch_plots_stacked = std::to_array({ +#define INST(core, pref, index, label, mnemonic, symbol) \ + #label "_" #pref "_" #core, +#define FOR_CORE(i) \ + {"ipop%_" #i, "population", { INST_SET(i, pop) }}, + FOR_CORES +#undef FOR_CORE +#define FOR_CORE(i) \ + {"iexe%_" #i, "population", { INST_SET(i, exe) }}, + FOR_CORES +#undef FOR_CORE +#define FOR_CORE(i) \ + {"iwrt%_" #i, "population", { INST_SET(i, wrt) }}, + FOR_CORES +#undef FOR_CORE +#undef INST +}); + +std::array g_arch_plots_heatmaps = std::to_array({ +#define FOR_CORE(i) \ + {"wev_" #i, "heatmaps", "wev_" #i}, + FOR_CORES +#undef FOR_CORE +#define FOR_CORE(i) \ + {"xev_" #i, "heatmaps", "xev_" #i}, + FOR_CORES +#undef FOR_CORE +}); diff --git a/core/client.cpp b/core/client.cpp index cf85b27..2ca419a 100644 --- a/core/client.cpp +++ b/core/client.cpp @@ -45,7 +45,6 @@ // ---------------------------------------------------------------------------- #define COLOR_BLACK ImVec4(0.f, 0.f, 0.f, 1.f) #define FONT_SIZE 12.f -#define FONT_SOURCE "/usr/share/fonts/droid/DroidSansMono.ttf" #define GLSL_VERSION "#version 130" #define PLOT_MIN_COLS 1 #define PLOT_MAX_COLS 8 @@ -204,7 +203,7 @@ private: // ---------------------------------------------------------------------------- // [SECTION] Plots // ---------------------------------------------------------------------------- -#include "arch_plots.cpp" +#include "plots.cpp" std::array g_core_traces = std::to_array>({ {"rowid", "rowid"}, diff --git a/data.png b/data.png new file mode 100644 index 0000000..17d30f4 Binary files /dev/null and b/data.png differ diff --git a/salis.py b/salis.py index 34795db..4e0044e 100755 --- a/salis.py +++ b/salis.py @@ -61,6 +61,7 @@ options = { (("C", "clones"), (new,), fmt_id): {"metavar": "N", "help": "number of ancestor clones on each core", "default": 1, "required": False, "type": nat}, (("c", "cores"), (new,), fmt_id): {"metavar": "N", "help": "number of simulator cores", "default": 2, "required": False, "type": nat}, (("d", "data-push-pow"), (new,), fmt_id): {"metavar": "POW", "help": "data aggregation interval exponent; interval = 2^{POW} >= {sync-pow}", "default": 28, "required": False, "type": nat}, + (("F", "font"), (client,), fmt_id): {"metavar": "FILE", "help": "font face to use", "default": "/usr/share/fonts/droid/DroidSansMono.ttf", "required": False}, (("f", "force"), (new,), fmt_id): {"action": "store_true", "help": "overwrite existing simulation of given name", "required": False}, (("F", "muta-flip"), (new,), fmt_id): {"action": "store_true", "help": "cosmic rays flip bits instead of randomizing whole bytes", "required": False}, (("g", "c-compiler"), (new, load, server, client), fmt_id): {"metavar": "CC", "help": "C compiler to use", "default": "gcc", "required": False, "type": str}, @@ -256,6 +257,10 @@ if args.command == "server": # Data client if args.command == "client": + # Check provided font file exists + if not os.path.isfile(args.font): + raise RuntimeError(f"Font file {args.font} does not exist; please provide a valid font") + # Pull basic information from the server # Required to build the client with correct flags args.name = request_from_server({"request": "name"})["name"] @@ -273,7 +278,7 @@ if args.command == "client": client_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("utf-8").strip() if server_hash != client_hash: - raise RuntimeError(f"Server hash '{server_hash}' and client hash '{client_hash}' don't match") + raise RuntimeError(f"Server hash '{server_hash}' and client hash '{client_hash}' do not match") log.info(f"Confirmed server and client are running against the same git hash: {server_hash}") @@ -417,6 +422,7 @@ if args.command == "client": if not args.no_vsync: ns.b.defines.add("-DVSYNC") + ns.b.defines.add(f"-DFONT_SOURCE=\"{args.font}\"") ns.b.defines.add(f"-DIP=\"{args.ip}\"") ns.b.links.add("-lGL") ns.b.links.add("-lglfw") -- cgit v1.2.1