From 9f7e70904e6c0fa650323ac5e50ebf6003da333c Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Tue, 24 Feb 2026 01:33:45 +0100 Subject: Removes usage of Jinja templates Use CPP to pre-process C files instead --- README.md | 41 +- anc/dummy/0123.asm | 4 + anc/v1/55a.asm | 66 + ancs/dummy/0123.asm | 6 - ancs/salis-v1/55a.asm | 74 - arch/dummy/arch.c | 149 ++ arch/dummy/arch.j2.c | 156 -- arch/dummy/arch_vars.py | 34 +- arch/salis-v1/arch.j2.c | 1134 ------------- arch/salis-v1/arch_vars.py | 125 -- arch/v1/arch.c | 1127 +++++++++++++ arch/v1/arch_vars.py | 116 ++ bench.j2.c | 52 - core.c | 982 +++++++++++ core.j2.c | 935 ----------- data/salis-v1/trend.yaml | 3915 -------------------------------------------- salis.py | 371 ++--- ui/curses/ui.c | 1371 ++++++++++++++++ ui/curses/ui.j2.c | 1386 ---------------- ui/curses/ui_vars.py | 10 +- ui/daemon/ui.c | 79 + ui/daemon/ui.j2.c | 86 - ui/daemon/ui_vars.py | 10 +- 23 files changed, 4111 insertions(+), 8118 deletions(-) create mode 100644 anc/dummy/0123.asm create mode 100644 anc/v1/55a.asm delete mode 100644 ancs/dummy/0123.asm delete mode 100644 ancs/salis-v1/55a.asm create mode 100644 arch/dummy/arch.c delete mode 100644 arch/dummy/arch.j2.c delete mode 100644 arch/salis-v1/arch.j2.c delete mode 100644 arch/salis-v1/arch_vars.py create mode 100644 arch/v1/arch.c create mode 100644 arch/v1/arch_vars.py delete mode 100644 bench.j2.c create mode 100644 core.c delete mode 100644 core.j2.c delete mode 100644 data/salis-v1/trend.yaml create mode 100644 ui/curses/ui.c delete mode 100644 ui/curses/ui.j2.c create mode 100644 ui/daemon/ui.c delete mode 100644 ui/daemon/ui.j2.c diff --git a/README.md b/README.md index f50caf5..a012fdc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # SALIS: A-life Simulator ![SALIS simulation](sim.png) -*SALIS simulation running on the V1 architecture with the ncurses user interface* +*SALIS simulation running the V1 architecture with the curses user interface* ## Overview *SALIS* is a platform for conducting artificial life experiments. It enables @@ -32,26 +32,29 @@ The python script compiles a temporary executable on the fly (compilation typically takes less than a second) based on the specified arguments and launches it immediately. -Different architectures can be implemented as standalone C templates in the -`arch/` directory. When creating a new simulation, you can select a specific -architecture using the `--arch` argument. +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` +argument. -Similarly, different user interfaces are implemented as C templates 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 service. Unlike the `--arch` -argument, you can choose a different `--ui` argument each time you load a -saved simulation. +Similarly, different user interfaces are implemented as C files, plus an +associated `ui_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 +service. Unlike the `--arch` argument, you can choose a different `--ui` argument +each time you load a saved simulation. As an example, the following command will launch a new *SALIS* simulation with 4 -copies of the `55a` ancestor organisms pre-compiled in each memory core. It -will use the `salis-v1` architecture, run on 8 memory cores, with each core -having a size of 2^22 bytes. The PRNG seed is set to `123456789`: +copies of the `55a` ancestor organisms pre-compiled in each memory core. It will +use the `v1` architecture, run on 8 memory cores, with each core having a size +of 2^22 bytes. The PRNG seed is set to `123456789`: ```console -user@host$ ./salis.py new -A55a -asalis-v1 -c8 -C4 -m22 -nworld-1 -s123456789 -o +user@host$ ./salis.py new -A55a -av1 -c8 -C4 -m22 -nworld-1 -s123456789 -o ``` +Use `Ctrl-C` to exit the simulator. + Upon exit, the simulation state will be automatically saved to `${HOME}/.salis/world-1/`. As long as the contents of this directory are not removed, you can reload the saved simulation with the following command: @@ -60,7 +63,9 @@ user@host$ ./salis.py load -n world-1 -o ``` ## Requirements -- C compiler - ideally GCC -- Python3 -- Jinja2 - installed globally or in an active virtual environment +- C compiler +- Python +## Optional Dependencies +- SQLite +- Zlib diff --git a/anc/dummy/0123.asm b/anc/dummy/0123.asm new file mode 100644 index 0000000..d52a6a6 --- /dev/null +++ b/anc/dummy/0123.asm @@ -0,0 +1,4 @@ +dummy 00 +dummy 01 +dummy 02 +dummy 03 diff --git a/anc/v1/55a.asm b/anc/v1/55a.asm new file mode 100644 index 0000000..aa95f07 --- /dev/null +++ b/anc/v1/55a.asm @@ -0,0 +1,66 @@ +; begin marker +loka + +; measure yourself +adrb +keya +adrf +keya +nop1 +incn +nop1 +subn +nop1 +nop1 + +; allocate child +lokb +notn +nop3 +pshn +nop1 +pshn +nop3 +ifnz +nop3 +jmpf +keyc +allb +nop1 +nop2 +jmpf +keyd +lokc +allf +nop1 +nop2 + +; copy yourself +lokd +load +nop0 +nop3 +wrte +nop2 +nop3 +incn +incn +nop2 +decn +nop1 +ifnz +nop1 +jmpb +keyd + +; split child +splt +popn +nop3 +popn +nop1 +jmpb +keyb + +; end marker +loka diff --git a/ancs/dummy/0123.asm b/ancs/dummy/0123.asm deleted file mode 100644 index b32d8bf..0000000 --- a/ancs/dummy/0123.asm +++ /dev/null @@ -1,6 +0,0 @@ -; Dummy ancestor for testing - -dummy 00 -dummy 01 -dummy 02 -dummy 03 diff --git a/ancs/salis-v1/55a.asm b/ancs/salis-v1/55a.asm deleted file mode 100644 index 6e060ba..0000000 --- a/ancs/salis-v1/55a.asm +++ /dev/null @@ -1,74 +0,0 @@ -; Project: Salis -; Author: Paul Oliver -; Email: contact@pauloliver.dev - -; Based on the original 55.anc ancestor from salis-v1: -; https://git.pauloliver.dev/salis-v1/tree/bin/genomes/55.anc -; This organism replicates bidirectionally. - -; begin template -loka - -; measure gene -adrb -keya -adrf -keya -nop1 -incn -nop1 -subn -nop1 -nop1 - -; alloc gene -lokb -notn -nop3 -pshn -nop1 -pshn -nop3 -ifnz -nop3 -jmpf -keyc -allb -nop1 -nop2 -jmpf -keyd -lokc -allf -nop1 -nop2 - -; copy gene -lokd -load -nop0 -nop3 -wrte -nop2 -nop3 -incn -incn -nop2 -decn -nop1 -ifnz -nop1 -jmpb -keyd - -; split gene -splt -popn -nop3 -popn -nop1 -jmpb -keyb - -; end template -loka diff --git a/arch/dummy/arch.c b/arch/dummy/arch.c new file mode 100644 index 0000000..cf30ba1 --- /dev/null +++ b/arch/dummy/arch.c @@ -0,0 +1,149 @@ +#if (defined(COMMAND_BENCH) || defined(COMMAND_NEW)) && defined(ANC_BYTES) +void arch_core_init(struct Core *core) { + assert(core); + +#if defined(MVEC_LOOP) + uint64_t addr = UINT64_HALF; +#else + uint64_t addr = 0; +#endif + + for (uint64_t i = 0; i < CLONES; ++i) { + uint64_t addr_clone = addr + (MVEC_SIZE / CLONES) * i; + + struct Proc *panc = proc_fetch(core, i); + + panc->mb0a = addr_clone; + panc->mb0s = ANC_SIZE; + panc->ip = addr_clone; + panc->sp = addr_clone; + } +} +#endif + +void arch_core_free(struct Core *core) { + assert(core); + + (void)core; +} + +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) +void arch_core_save(FILE *f, const struct Core *core) { + assert(f); + assert(core); + + (void)f; + (void)core; +} +#endif + +#if defined(COMMAND_LOAD) +void arch_core_load(FILE *f, struct Core *core) { + assert(f); + assert(core); + + (void)f; + (void)core; +} +#endif + +uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb0a; +} + +uint64_t arch_proc_mb0_size(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb0s; +} + +uint64_t arch_proc_mb1_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb1a; +} + +uint64_t arch_proc_mb1_size(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb1s; +} + +uint64_t arch_proc_ip_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->ip; +} + +uint64_t arch_proc_sp_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->sp; +} + +uint64_t arch_proc_slice(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + (void)core; + (void)pix; + + return 1; +} + +void arch_on_proc_kill(struct Core *core) { + assert(core); + assert(core->pnum > 1); + + (void)core; +} + +void arch_proc_step(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + (void)core; + (void)pix; + + return; +} + +#if !defined(NDEBUG) +void arch_validate_proc(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + (void)core; + (void)pix; + + assert(true); +} +#endif + +wchar_t arch_symbol(uint8_t inst) { + switch (inst) { +#define INST(index, label, mnemonic, symbol) case index: return symbol; + INST_SET +#undef INST + } +} + +const char *arch_mnemonic(uint8_t inst) { + switch (inst) { +#define INST(index, label, mnemonic, symbol) case index: return mnemonic; + INST_SET +#undef INST + } +} + +#if defined(DATA_PUSH_PATH) +void arch_push_data_header() { + assert(g_sim_data); +} + +void arch_push_data_line() { + assert(g_sim_data); +} +#endif diff --git a/arch/dummy/arch.j2.c b/arch/dummy/arch.j2.c deleted file mode 100644 index f51494f..0000000 --- a/arch/dummy/arch.j2.c +++ /dev/null @@ -1,156 +0,0 @@ -// Author: Paul Oliver -// Project: salis-v3 - -// Defines a minimal viable architecture for the Salis VM. -// Useful for debugging and benchmarking. May be used as a template when -// implementing a new architecture. - -{% if args.command in ["bench", "new"] and anc_bytes is defined %} -void arch_core_init(struct Core *core) { - assert(core); - - {% if arch_vars.mvec_loop %} - uint64_t addr = {{ uint64_half }}; - {% else %} - uint64_t addr = 0; - {% endif %} - - for (uint64_t i = 0; i < {{ args.clones }}; ++i) { - uint64_t addr_clone = addr + (({{ mvec_size }} / {{ args.clones }})) * i; - - struct Proc *panc = proc_fetch(core, i); - - panc->mb0a = addr_clone; - panc->mb0s = {{ anc_bytes|length }}; - panc->ip = addr_clone; - panc->sp = addr_clone; - } -} -{% endif %} - -void arch_core_free(struct Core *core) { - assert(core); - - (void)core; -} - -{% if args.command in ["load", "new"] %} -void arch_core_save(FILE *f, const struct Core *core) { - assert(f); - assert(core); - - (void)f; - (void)core; -} -{% endif %} - -{% if args.command in ["load"] %} -void arch_core_load(FILE *f, struct Core *core) { - assert(f); - assert(core); - - (void)f; - (void)core; -} -{% endif %} - -uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb0a; -} - -uint64_t arch_proc_mb0_size(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb0s; -} - -uint64_t arch_proc_mb1_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb1a; -} - -uint64_t arch_proc_mb1_size(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb1s; -} - -uint64_t arch_proc_ip_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->ip; -} - -uint64_t arch_proc_sp_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->sp; -} - -uint64_t arch_proc_slice(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - (void)core; - (void)pix; - - return 1; -} - -void arch_on_proc_kill(struct Core *core) { - assert(core); - assert(core->pnum > 1); - - (void)core; -} - -void arch_proc_step(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - (void)core; - (void)pix; - - return; -} - -{% if not args.optimized %} -void arch_validate_proc(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - (void)core; - (void)pix; - - assert(true); -} -{% endif %} - -wchar_t arch_symbol(uint8_t inst) { - switch (inst) { - {% for i in arch_vars.inst_set %} - case {{ loop.index0 }}: return L'{{ i[1] }}'; - {% endfor %} - } -} - -const char *arch_mnemonic(uint8_t inst) { - switch (inst) { - {% for i in arch_vars.inst_set %} - case {{ loop.index0 }}: return "{{ i[0]|join(' ') }}"; - {% endfor %} - } -} - -{% if data_push_path is defined %} -void arch_push_data_header() { - assert(g_sim_data); -} - -void arch_push_data_line() { - assert(g_sim_data); -} -{% endif %} diff --git a/arch/dummy/arch_vars.py b/arch/dummy/arch_vars.py index bc97ea9..0266e53 100644 --- a/arch/dummy/arch_vars.py +++ b/arch/dummy/arch_vars.py @@ -1,18 +1,6 @@ -def gen_arch_vars(_): - return { - "core_fields": [], - "mvec_loop": True, - - "proc_fields": [ - ("uint64_t", "ip"), - ("uint64_t", "sp"), - ("uint64_t", "mb0a"), - ("uint64_t", "mb0s"), - ("uint64_t", "mb1a"), - ("uint64_t", "mb1s"), - ], - - "inst_set": [ +class ArchVars: + def __init__(self, _): + self.inst_set = [ (["dummy", f"{i:02x}"], symbol) for i, symbol in enumerate( "⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟" @@ -20,7 +8,17 @@ def gen_arch_vars(_): "⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟" "⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿" ) - ], + ] - "inst_count": 2 ** 7, - } + self.core_fields = [] + self.data_is_compressed = False + self.mvec_loop = True + + self.proc_fields = [ + ("uint64_t", "ip"), + ("uint64_t", "sp"), + ("uint64_t", "mb0a"), + ("uint64_t", "mb0s"), + ("uint64_t", "mb1a"), + ("uint64_t", "mb1s"), + ] diff --git a/arch/salis-v1/arch.j2.c b/arch/salis-v1/arch.j2.c deleted file mode 100644 index 06a701d..0000000 --- a/arch/salis-v1/arch.j2.c +++ /dev/null @@ -1,1134 +0,0 @@ -// Author: Paul Oliver -// Project: Salis - -// Based on the original salis-v1 VM architecture: -// https://git.pauloliver.dev/salis-v1/about/ - -enum { - {% for i in arch_vars.inst_set %} - {{ i[0]|join(' ') }}, - {% endfor %} -}; - -{% if args.command in ["bench", "new"] and anc_bytes is defined %} -void arch_core_init(struct Core *core) { - assert(core); - - {% if arch_vars.mvec_loop %} - uint64_t addr = {{ uint64_half }}; - {% else %} - uint64_t addr = 0; - {% endif %} - - for (uint64_t i = 0; i < {{ args.clones }}; ++i) { - uint64_t addr_clone = addr + (({{ mvec_size }} / {{ args.clones }})) * i; - - struct Proc *panc = proc_fetch(core, i); - - panc->mb0a = addr_clone; - panc->mb0s = {{ anc_bytes|length }}; - panc->ip = addr_clone; - panc->sp = addr_clone; - } -} -{% endif %} - -void arch_core_free(struct Core *core) { - assert(core); - (void)core; -} - -{% if args.command in ["load", "new"] %} -void arch_core_save(FILE *f, const struct Core *core) { - assert(f); - assert(core); - - fwrite( core->iexe, sizeof(uint64_t), {{ arch_vars.inst_count }}, f); - fwrite( core->iwrt, sizeof(uint64_t), {{ arch_vars.inst_count }}, f); - fwrite(&core->emb0, sizeof(uint64_t), 1, f); - fwrite(&core->emb1, sizeof(uint64_t), 1, f); - fwrite(&core->eliv, sizeof(uint64_t), 1, f); - fwrite(&core->edea, sizeof(uint64_t), 1, f); - fwrite(&core->wmb0, sizeof(uint64_t), 1, f); - fwrite(&core->wmb1, sizeof(uint64_t), 1, f); - fwrite(&core->wdea, sizeof(uint64_t), 1, f); - fwrite( core->aeva, sizeof(uint64_t), {{ mvec_size }}, f); -} -{% endif %} - -{% if args.command in ["load"] %} -void arch_core_load(FILE *f, struct Core *core) { - assert(f); - assert(core); - - fread( core->iexe, sizeof(uint64_t), {{ arch_vars.inst_count }}, f); - fread( core->iwrt, sizeof(uint64_t), {{ arch_vars.inst_count }}, f); - fread(&core->emb0, sizeof(uint64_t), 1, f); - fread(&core->emb1, sizeof(uint64_t), 1, f); - fread(&core->eliv, sizeof(uint64_t), 1, f); - fread(&core->edea, sizeof(uint64_t), 1, f); - fread(&core->wmb0, sizeof(uint64_t), 1, f); - fread(&core->wmb1, sizeof(uint64_t), 1, f); - fread(&core->wdea, sizeof(uint64_t), 1, f); - fread( core->aeva, sizeof(uint64_t), {{ mvec_size }}, f); -} -{% endif %} - -uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb0a; -} - -uint64_t arch_proc_mb0_size(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb0s; -} - -uint64_t arch_proc_mb1_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb1a; -} - -uint64_t arch_proc_mb1_size(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->mb1s; -} - -uint64_t arch_proc_ip_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->ip; -} - -uint64_t arch_proc_sp_addr(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return proc_get(core, pix)->sp; -} - -uint64_t arch_proc_slice(const struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - (void)core; - (void)pix; - - return 1; -} - -void _free_memory_block(struct Core *core, uint64_t addr, uint64_t size) { - assert(core); - assert(size); - - for (uint64_t i = 0; i < size; ++i) { - mvec_free(core, addr + i); - - // Record deallocation event - ++core->aeva[addr]; - } -} - -void arch_on_proc_kill(struct Core *core) { - assert(core); - assert(core->pnum > 1); - - struct Proc *pfst = proc_fetch(core, core->pfst); - - _free_memory_block(core, pfst->mb0a, pfst->mb0s); - - if (pfst->mb1s) { - _free_memory_block(core, pfst->mb1a, pfst->mb1s); - } - - memcpy(pfst, &g_dead_proc, sizeof(struct Proc)); -} - -uint8_t _get_inst(const struct Core *core, uint64_t addr) { - assert(core); - - return mvec_get_inst(core, addr) % {{ arch_vars.inst_count }}; -} - -void _increment_ip(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - - proc->ip++; - proc->sp = proc->ip; -} - -bool _is_between(uint8_t inst, uint8_t lo, uint8_t hi) { - assert(inst < {{ arch_vars.inst_count }}); - assert(lo < {{ arch_vars.inst_count }}); - assert(hi < {{ arch_vars.inst_count }}); - assert(lo < hi); - - return (inst >= lo) && (inst <= hi); -} - -bool _is_key(uint8_t inst) { - assert(inst < {{ arch_vars.inst_count }}); - - return _is_between(inst, keya, keyp); -} - -bool _is_lock(uint8_t inst) { - assert(inst < {{ arch_vars.inst_count }}); - - return _is_between(inst, loka, lokp); -} - -bool _is_rmod(uint8_t inst) { - assert(inst < {{ arch_vars.inst_count }}); - - return _is_between(inst, nop0, nop3); -} - -bool _key_lock_match(uint8_t key, uint8_t lock) { - assert(key < {{ arch_vars.inst_count }}); - assert(lock < {{ arch_vars.inst_count }}); - assert(_is_key(key)); - - return (key - keya) == (lock - loka); -} - -bool _seek(struct Core *core, uint64_t pix, bool fwrd) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint8_t next = _get_inst(core, proc->ip + 1); - - if (!_is_key(next)) { - _increment_ip(core, pix); - return false; - } - - uint8_t spin = _get_inst(core, proc->sp); - - if (_key_lock_match(next, spin)) { - return true; - } - - if (fwrd) { - proc->sp++; - } else { - proc->sp--; - } - - return false; -} - -void _jump(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - - {% if not args.optimized %} - uint8_t next = _get_inst(core, proc->ip + 1); - uint8_t spin = _get_inst(core, proc->sp); - assert(_is_key(next)); - assert(_is_lock(spin)); - assert(_key_lock_match(next, spin)); - {% endif %} - - proc->ip = proc->sp; -} - -void _get_reg_addr_list(struct Core *core, uint64_t pix, uint64_t **rlist, int rcount, bool offset) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - assert(rlist); - assert(rcount); - assert(rcount < 4); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t madr = proc->ip + (offset ? 2 : 1); - - for (int i = 0; i < rcount; ++i) { - rlist[i] = &proc->r0x; - } - - for (int i = 0; i < rcount; ++i) { - uint64_t mnxt = madr + i; - uint8_t mins = _get_inst(core, mnxt); - - if (!_is_rmod(mins)) { - break; - } - - switch (mins) { - case nop0: - rlist[i] = &proc->r0x; - break; - case nop1: - rlist[i] = &proc->r1x; - break; - case nop2: - rlist[i] = &proc->r2x; - break; - case nop3: - rlist[i] = &proc->r3x; - break; - } - } -} - -void _addr(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t *reg; - - {% if not args.optimized %} - uint8_t next = _get_inst(core, proc->ip + 1); - uint8_t spin = _get_inst(core, proc->sp); - assert(_is_key(next)); - assert(_is_lock(spin)); - assert(_key_lock_match(next, spin)); - {% endif %} - - _get_reg_addr_list(core, pix, ®, 1, true); - *reg = proc->sp; - - _increment_ip(core, pix); -} - -void _ifnz(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t *reg; - - _get_reg_addr_list(core, pix, ®, 1, false); - - uint64_t jmod = _is_rmod(_get_inst(core, proc->ip + 1)) ? 1 : 0; - uint64_t rmod = *reg ? 1 : 2; - - proc->ip += jmod + rmod; - proc->sp = proc->ip; -} - -void _free_child_memory_of(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - - assert(proc->mb1s); - - _free_memory_block(core, proc->mb1a, proc->mb1s); - - proc->mb1a = 0; - proc->mb1s = 0; -} - -// Organisms allocate new memory blocks by means of their seek pointer (sp), -// which sweeps memory 1 byte per simulation step, extending the block as it goes. -// In case allocated memory is found mid-way, current allocation is discarded. -void _alloc(struct Core *core, uint64_t pix, bool fwrd) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t *regs[2]; - - _get_reg_addr_list(core, pix, regs, 2, false); - - uint64_t bsize = *regs[0]; - - // Do nothing if block-size is zero - if (!bsize) { - _increment_ip(core, pix); - return; - } - - // Do nothing if seek pointer is not adjacent to allocated memory block - // This is an error condition - if (proc->mb1s) { - uint64_t exp_addr = proc->mb1a; - - if (fwrd) { - exp_addr += proc->mb1s; - } else { - exp_addr--; - } - - if (proc->sp != exp_addr) { - _increment_ip(core, pix); - return; - } - } - - // Allocation was successful - // Store block address on register - if (proc->mb1s == bsize) { - _increment_ip(core, pix); - *regs[1] = proc->mb1a; - return; - } - - // Seek pointer collided with another allocated block - // Discard and keep trying - if (mvec_is_alloc(core, proc->sp)) { - if (proc->mb1s) { - _free_child_memory_of(core, pix); - } - - if (fwrd) { - proc->sp++; - } else { - proc->sp--; - } - - return; - } - - // Free (non-allocated) byte found - // Enlarge child block 1 byte - mvec_alloc(core, proc->sp); - - // Record allocation event - ++core->aeva[proc->sp]; - - if (!proc->mb1s || !fwrd) { - proc->mb1a = proc->sp; - } - - proc->mb1s++; - - // Move seek pointer - if (fwrd) { - proc->sp++; - } else { - proc->sp--; - } -} - -void _bswap(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - - if (proc->mb1s) { - uint64_t tmpa = proc->mb0a; - uint64_t tmps = proc->mb0s; - - proc->mb0a = proc->mb1a; - proc->mb0s = proc->mb1s; - proc->mb1a = tmpa; - proc->mb1s = tmps; - } - - _increment_ip(core, pix); -} - -void _bclear(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - - if (proc->mb1s) { - _free_child_memory_of(core, pix); - } - - _increment_ip(core, pix); -} - -void _split(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - - if (proc->mb1s) { - struct Proc child = {0}; - - child.ip = proc->mb1a; - child.sp = proc->mb1a; - child.mb0a = proc->mb1a; - child.mb0s = proc->mb1s; - - proc->mb1a = 0; - proc->mb1s = 0; - - // A new organism is born :) - proc_new(core, &child); - } else { - assert(!proc->mb1a); - } - - _increment_ip(core, pix); -} - -void _3rop(struct Core *core, uint64_t pix, uint8_t inst) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - uint64_t *regs[3]; - - _get_reg_addr_list(core, pix, regs, 3, false); - - // Organisms can do arithmetic using any sequence of 3 registers - switch (inst) { - case addn: - *regs[0] = *regs[1] + *regs[2]; - break; - case subn: - *regs[0] = *regs[1] - *regs[2]; - break; - case muln: - *regs[0] = *regs[1] * *regs[2]; - break; - case divn: - // Division by zero - // Do nothing - if (*regs[2]) { - *regs[0] = *regs[1] / *regs[2]; - } - - break; - default: - assert(false); - } - - _increment_ip(core, pix); -} - -void _1rop(struct Core *core, uint64_t pix, uint8_t inst) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - uint64_t *reg; - - _get_reg_addr_list(core, pix, ®, 1, false); - - switch (inst) { - case incn: - (*reg)++; - break; - case decn: - (*reg)--; - break; - case notn: - *reg = !(*reg); - break; - case shfl: - *reg <<= 1; - break; - case shfr: - *reg >>= 1; - break; - case zero: - *reg = 0; - break; - case unit: - *reg = 1; - break; - default: - assert(false); - } - - _increment_ip(core, pix); -} - -void _push(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t *reg; - - _get_reg_addr_list(core, pix, ®, 1, false); - - proc->s7 = proc->s6; - proc->s6 = proc->s5; - proc->s5 = proc->s4; - proc->s4 = proc->s3; - proc->s3 = proc->s2; - proc->s2 = proc->s1; - proc->s1 = proc->s0; - proc->s0 = *reg; - - _increment_ip(core, pix); -} - -void _pop(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t *reg; - - _get_reg_addr_list(core, pix, ®, 1, false); - - *reg = proc->s0; - proc->s0 = proc->s1; - proc->s1 = proc->s2; - proc->s2 = proc->s3; - proc->s3 = proc->s4; - proc->s4 = proc->s5; - proc->s5 = proc->s6; - proc->s6 = proc->s7; - proc->s7 = 0; - - _increment_ip(core, pix); -} - -int _sp_dir(uint64_t src, uint64_t dst) { - if (src == dst) { - return 0; - } else if (src - dst <= dst - src) { - return -1; - } else { - return 1; - } -} - -void _load(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t *regs[2]; - - _get_reg_addr_list(core, pix, regs, 2, false); - - int sp_dir = _sp_dir(proc->sp, *regs[0]); - - if (sp_dir == 1) { - proc->sp++; - } else if (sp_dir == -1) { - proc->sp--; - } else { - *regs[1] = mvec_get_inst(core, *regs[0]); - _increment_ip(core, pix); - } -} - -bool _is_writeable_by(const struct Core *core, uint64_t addr, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - return !mvec_is_alloc(core, addr) || mvec_is_proc_owner(core, addr, pix); -} - -void _write(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint64_t *regs[2]; - - _get_reg_addr_list(core, pix, regs, 2, false); - - int sp_dir = _sp_dir(proc->sp, *regs[0]); - - if (sp_dir == 1) { - proc->sp++; - } else if (sp_dir == -1) { - proc->sp--; - } else { - if (_is_writeable_by(core, *regs[0], pix)) { - // Store write event - uint8_t inst = *regs[1] % {{ arch_vars.inst_count }}; - - ++core->iwrt[inst]; - - if (mvec_is_in_mb0_of_proc(core, *regs[0], pix)) { - ++core->wmb0; - } else if (mvec_is_in_mb1_of_proc(core, *regs[0], pix)) { - ++core->wmb1; - } else { - ++core->wdea; - } - - // Write instruction - mvec_set_inst(core, *regs[0], *regs[1] % {{ inst_cap }}); - } - - _increment_ip(core, pix); - } -} - -void _2rop(struct Core *core, uint64_t pix, uint8_t inst) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - uint64_t *regs[2]; - - _get_reg_addr_list(core, pix, regs, 2, false); - - switch (inst) { - case dupl: - *regs[1] = *regs[0]; - break; - case swap: - { - uint64_t tmp = *regs[0]; - *regs[0] = *regs[1]; - *regs[1] = tmp; - } - - break; - default: - assert(false); - } - - _increment_ip(core, pix); -} - -void arch_proc_step(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - struct Proc *proc = proc_fetch(core, pix); - uint8_t inst = _get_inst(core, proc->ip); - - // Store execute event - ++core->iexe[inst]; - - if (mvec_is_in_mb0_of_proc(core, proc->ip, pix)) { - ++core->emb0; - } else if (mvec_is_in_mb1_of_proc(core, proc->ip, pix)) { - ++core->emb1; - } else if (mvec_is_alloc(core, proc->ip)) { - ++core->eliv; - } else { - ++core->edea; - } - - // Execute instruction - switch (inst) { - case jmpb: - if (_seek(core, pix, false)) { - _jump(core, pix); - } - - break; - case jmpf: - if (_seek(core, pix, true)) { - _jump(core, pix); - } - - break; - case adrb: - if (_seek(core, pix, false)) { - _addr(core, pix); - } - - break; - case adrf: - if (_seek(core, pix, true)) { - _addr(core, pix); - } - - break; - case ifnz: - _ifnz(core, pix); - break; - case allb: - _alloc(core, pix, false); - break; - case allf: - _alloc(core, pix, true); - break; - case bswp: - _bswap(core, pix); - break; - case bclr: - _bclear(core, pix); - break; - case splt: - _split(core, pix); - break; - case addn: - case subn: - case muln: - case divn: - _3rop(core, pix, inst); - break; - case incn: - case decn: - case notn: - case shfl: - case shfr: - case zero: - case unit: - _1rop(core, pix, inst); - break; - case pshn: - _push(core, pix); - break; - case popn: - _pop(core, pix); - break; - case load: - _load(core, pix); - break; - case wrte: - _write(core, pix); - break; - case dupl: - case swap: - _2rop(core, pix, inst); - break; - default: - _increment_ip(core, pix); - break; - } - - return; -} - -{% if not args.optimized %} -void arch_validate_proc(const struct Core *core, uint64_t pix) { - assert(core); - - const struct Proc *proc = proc_get(core, pix); - - assert(proc->mb0s); - - if (proc->mb1a) { - assert(proc->mb1s); - } - - for (uint64_t i = 0; i < proc->mb0s; ++i) { - uint64_t addr = proc->mb0a + i; - assert(mvec_is_alloc(core, addr)); - assert(mvec_is_proc_owner(core, addr, pix)); - } - - for (uint64_t i = 0; i < proc->mb1s; ++i) { - uint64_t addr = proc->mb1a + i; - assert(mvec_is_alloc(core, addr)); - assert(mvec_is_proc_owner(core, addr, pix)); - } -} -{% endif %} - -wchar_t arch_symbol(uint8_t inst) { - switch (inst % {{ arch_vars.inst_count }}) { - {% for i in arch_vars.inst_set %} - case {{ i[0]|join(' ') }}: return L'{{ i[1] }}'; - {% endfor %} - } - - assert(false); - return L'\0'; -} - -const char *arch_mnemonic(uint8_t inst) { - switch (inst % {{ arch_vars.inst_count }}) { - {% for i in arch_vars.inst_set %} - case {{ i[0]|join(' ') }}: return "{{ i[0]|join(' ') }}"; - {% endfor %} - } - - assert(false); - return NULL; -} - -// ---------------------------------------------------------------------------- -// Data aggregation functions -// ---------------------------------------------------------------------------- -{% if data_push_path is defined %} -void arch_push_data_header() { - assert(g_sim_data); - - // Creates general trend table for all cores - g_info("Creating 'trend' table in SQLite database"); - salis_exec_sql( - 0, NULL, NULL, - "create table trend (" - "step int not null, " - {% for i in range(args.cores) %} - "cycl_{{ i }} int not null, " - "mall_{{ i }} int not null, " - "pnum_{{ i }} int not null, " - "pfst_{{ i }} int not null, " - "plst_{{ i }} int not null, " - "amb0_{{ i }} real not null, " - "amb1_{{ i }} real not null, " - "emb0_{{ i }} int not null, " - "emb1_{{ i }} int not null, " - "eliv_{{ i }} int not null, " - "edea_{{ i }} int not null, " - "wmb0_{{ i }} int not null, " - "wmb1_{{ i }} int not null, " - "wdea_{{ i }} int not null{% if not loop.last %},{% endif %} " - {% endfor %} - ");" - ); - - // Creates core-specific instruction data tables - char *iprefs[] = { "pop", "exe", "wrt" }; - int iprefs_cnt = sizeof(iprefs) / sizeof(iprefs[0]); - - for (int i = 0; i < {{ args.cores }}; ++i) { - for (int j = 0; j < iprefs_cnt; ++j) { - g_info("Creating '%s_%d' table in SQLite database", iprefs[j], i); - salis_exec_sql( - 0, NULL, NULL, - "create table %s_%d (" - "step int not null, " - // Cycle data for all cores allows - // normalizing against each core's cycle speed - {% for i in range(args.cores) %} - "cycl_{{ i }} int not null, " - {% endfor %} - {% for i in arch_vars.inst_set %} - "{{ i[0][0] }} int not null{% if not loop.last %},{% endif %} " - {% endfor %} - ");", - iprefs[j], i - ); - } - } - - // Creates core-specific memory event tables - char *eprefs[] = { "aev" }; - int eprefs_cnt = sizeof(eprefs) / sizeof(eprefs[0]); - - for (int i = 0; i < {{ args.cores }}; ++i) { - for (int j = 0; j < eprefs_cnt; ++j) { - g_info("Creating '%s_%d' table in SQLite database", eprefs[j], i); - salis_exec_sql( - 0, NULL, NULL, - "create table %s_%d (" - "step int not null, " - "evts blob not null" - ");", - eprefs[j], i - ); - } - } -} - -void arch_push_data_line() { - assert(g_sim_data); - - // Measure current instruction population and average memory block sizes - uint64_t ipop[{{ args.cores }}][{{ arch_vars.inst_count }}] = { 0 }; - - double amb0[{{ args.cores }}] = { 0 }; - double amb1[{{ args.cores }}] = { 0 }; - - for (int i = 0; i < {{ args.cores }}; ++i) { - struct Core *core = &g_cores[i]; - - for (uint64_t j = core->pfst; j <= core->plst; ++j) { - const struct Proc *proc = proc_get(core, j); - - amb0[i] += (double)proc->mb0s; - amb1[i] += (double)proc->mb1s; - } - - amb0[i] /= core->pnum; - amb1[i] /= core->pnum; - - for (uint64_t j = 0; j < {{ mvec_size }}; ++j) { - ++ipop[i][_get_inst(core, j)]; - } - - {% if not args.optimized %} - // Make sure the counting was done right - uint64_t pop_tot = 0; - - for (int j = 0; j < {{ arch_vars.inst_count }}; ++j) { - pop_tot += ipop[i][j]; - } - - assert(pop_tot == {{ mvec_size }}); - {% endif %} - } - - // Insert row into trend table - g_info("Pushing row to 'trend' table in SQLite database"); - salis_exec_sql( - 0, NULL, NULL, - "insert into trend (" - "step, " - {% for i in range(args.cores) %} - "cycl_{{ i }}, " - "mall_{{ i }}, " - "pnum_{{ i }}, " - "pfst_{{ i }}, " - "plst_{{ i }}, " - "amb0_{{ i }}, " - "amb1_{{ i }}, " - "emb0_{{ i }}, " - "emb1_{{ i }}, " - "eliv_{{ i }}, " - "edea_{{ i }}, " - "wmb0_{{ i }}, " - "wmb1_{{ i }}, " - "wdea_{{ i }}{% if not loop.last %},{% endif %} " - {% endfor %} - ") values (" - "%ld, " - {% for i in range(args.cores) %} - "%ld, %ld, %ld, %ld, %ld, %f, %f, %ld, %ld, %ld, %ld, %ld, %ld, %ld{% if not loop.last %},{% endif %} " - {% endfor %} - ");", - g_steps, - {% for i in range(args.cores) +%} - g_cores[{{ i }}].cycl, - g_cores[{{ i }}].mall, - g_cores[{{ i }}].pnum, - g_cores[{{ i }}].pfst, - g_cores[{{ i }}].plst, - amb0[{{ i }}], - amb1[{{ i }}], - g_cores[{{ i }}].emb0, - g_cores[{{ i }}].emb1, - g_cores[{{ i }}].eliv, - g_cores[{{ i }}].edea, - g_cores[{{ i }}].wmb0, - g_cores[{{ i }}].wmb1, - g_cores[{{ i }}].wdea{% if not loop.last %},{% endif %} - {% endfor +%} - ); - - // Insert row into instruction data tables - char *iprefs[] = { "pop", "exe", "wrt" }; - int iprefs_cnt = sizeof(iprefs) / sizeof(iprefs[0]); - - for (int i = 0; i < {{ args.cores }}; ++i) { - for (int j = 0; j < iprefs_cnt; ++j) { - uint64_t *ia; - - if (!strcmp("pop", iprefs[j])) { - // Population is generated above, prior to push - ia = ipop[i]; - } else if (!strcmp("exe", iprefs[j])) { - ia = g_cores[i].iexe; - } else if (!strcmp("wrt", iprefs[j])) { - ia = g_cores[i].iwrt; - } - - g_info("Pushing row to '%s_%d' table in SQLite database", iprefs[j], i); - salis_exec_sql( - 0, NULL, NULL, - "insert into %s_%d (" - "step, " - {% for i in range(args.cores) %} - "cycl_{{ i }}, " - {% endfor %} - {% for i in arch_vars.inst_set %} - "{{ i[0][0] }}{% if not loop.last %},{% endif %} " - {% endfor %} - ") values (" - "%ld, " - {% for _ in range(args.cores) %} - "%ld, " - {% endfor %} - {% for _ in range(arch_vars.inst_count) %} - "%ld{% if not loop.last %},{% endif %} " - {% endfor %} - ");", - iprefs[j], - i, - g_steps, - {% for j in range(args.cores) %} - g_cores[{{ j }}].cycl, - {% endfor %} - {% for j in range(arch_vars.inst_count) %} - ia[{{ j }}]{% if not loop.last %},{% endif +%} - {% endfor %} - ); - } - } - - // Insert row into memory event tables - char *eprefs[] = { "aev" }; - int eprefs_cnt = sizeof(eprefs) / sizeof(eprefs[0]); - - // Event run-length data array is defined as static - // This prevents heap errors - static uint64_t erl_data[{{ mvec_size }} * 2]; - - for (int i = 0; i < {{ args.cores }}; ++i) { - for (int j = 0; j < eprefs_cnt; ++j) { - uint64_t *eva; - - if (!strcmp("aev", eprefs[j])) { - eva = g_cores[i].aeva; - } - - // Assume event data to be sparse in most cases - // Run-length encoding should help keep database size manageable, - // while making it easy to decode events array, wherever the - // database is consumed. - uint64_t addr = 0; - uint64_t eix = 0; - - while (addr < {{ mvec_size }}) { - assert(eix < {{ mvec_size }} * 2); - - erl_data[eix] = eva[addr]; - erl_data[eix + 1] = 0; - - while (addr < {{ mvec_size }} && eva[addr] == erl_data[eix]) { - ++erl_data[eix + 1]; - ++addr; - } - - eix += 2; - } - - {% if not args.optimized %} - uint64_t el = 0; - - for (uint64_t k = 0; k < eix; k += 2) { - el += erl_data[k + 1]; - } - - assert(el == {{ mvec_size }}); - {% endif %} - - // Insert blob into database - const void *blob_ptr = erl_data; - int blob_size = eix * sizeof(uint64_t); - - g_info("Pushing row to '%s_%d' table in SQLite database", eprefs[j], i); - salis_exec_sql( - 1, &blob_ptr, &blob_size, - "insert into %s_%d (step, evts) values (%ld, ?);", - eprefs[j], i, g_steps - ); - } - } - - // Reset all data aggregation core fields to zero - for (int i = 0; i < {{ args.cores }}; ++i) { - struct Core *core = &g_cores[i]; - - memset(core->iexe, 0, sizeof(uint64_t) * {{ arch_vars.inst_count }}); - memset(core->iwrt, 0, sizeof(uint64_t) * {{ arch_vars.inst_count }}); - - core->emb0 = 0; - core->emb1 = 0; - core->eliv = 0; - core->edea = 0; - core->wmb0 = 0; - core->wmb1 = 0; - core->wdea = 0; - - // Event vectors - memset(core->aeva, 0, sizeof(uint64_t) * {{ mvec_size }}); - } -} -{% endif %} diff --git a/arch/salis-v1/arch_vars.py b/arch/salis-v1/arch_vars.py deleted file mode 100644 index 25687ce..0000000 --- a/arch/salis-v1/arch_vars.py +++ /dev/null @@ -1,125 +0,0 @@ -def gen_arch_vars(args): - return { - "mvec_loop": False, - - # Organisms consist of: - # - instruction pointer - # - seeker pointer - # - main memory block - # - child memory block - # - 4 registers - # - 8 value stack - "proc_fields": [ - ("uint64_t", "ip"), - ("uint64_t", "sp"), - ("uint64_t", "mb0a"), - ("uint64_t", "mb0s"), - ("uint64_t", "mb1a"), - ("uint64_t", "mb1s"), - ("uint64_t", "r0x"), - ("uint64_t", "r1x"), - ("uint64_t", "r2x"), - ("uint64_t", "r3x"), - ("uint64_t", "s0"), - ("uint64_t", "s1"), - ("uint64_t", "s2"), - ("uint64_t", "s3"), - ("uint64_t", "s4"), - ("uint64_t", "s5"), - ("uint64_t", "s6"), - ("uint64_t", "s7"), - ], - - # Salis-v1 instruction set - "inst_set": [ - (["noop"], " "), - (["nop0"], "0"), - (["nop1"], "1"), - (["nop2"], "2"), - (["nop3"], "3"), - # ------------- - (["jmpb"], "("), - (["jmpf"], ")"), - (["adrb"], "["), - (["adrf"], "]"), - (["ifnz"], "?"), - # ------------- - (["allb"], "{"), - (["allf"], "}"), - (["bswp"], "%"), - (["bclr"], "|"), - (["splt"], "$"), - # ------------- - (["addn"], "+"), - (["subn"], "-"), - (["muln"], "*"), - (["divn"], "/"), - (["incn"], "^"), - (["decn"], "v"), - (["notn"], "!"), - (["shfl"], "<"), - (["shfr"], ">"), - (["zero"], "z"), - (["unit"], "u"), - # ------------- - (["pshn"], "#"), - (["popn"], "~"), - # ------------- - (["load"], "."), - (["wrte"], ":"), - (["dupl"], "="), - (["swap"], "x"), - # ------------- - (["keya"], "a"), - (["keyb"], "b"), - (["keyc"], "c"), - (["keyd"], "d"), - (["keye"], "e"), - (["keyf"], "f"), - (["keyg"], "g"), - (["keyh"], "h"), - (["keyi"], "i"), - (["keyj"], "j"), - (["keyk"], "k"), - (["keyl"], "l"), - (["keym"], "m"), - (["keyn"], "n"), - (["keyo"], "o"), - (["keyp"], "p"), - # ------------- - (["loka"], "A"), - (["lokb"], "B"), - (["lokc"], "C"), - (["lokd"], "D"), - (["loke"], "E"), - (["lokf"], "F"), - (["lokg"], "G"), - (["lokh"], "H"), - (["loki"], "I"), - (["lokj"], "J"), - (["lokk"], "K"), - (["lokl"], "L"), - (["lokm"], "M"), - (["lokn"], "N"), - (["loko"], "O"), - (["lokp"], "P"), - ], - - "inst_count": 2 ** 6, - - # Extra fields used exclusively for data aggregation - "core_fields": [ - ("uint64_t", f"iexe[{2 ** 6}]", False), - ("uint64_t", f"iwrt[{2 ** 6}]", False), - ("uint64_t", "emb0", True), - ("uint64_t", "emb1", True), - ("uint64_t", "eliv", True), - ("uint64_t", "edea", True), - ("uint64_t", "wmb0", True), - ("uint64_t", "wmb1", True), - ("uint64_t", "wdea", True), - - # Event data aggregators - ("uint64_t", f"aeva[{2 ** args.mvec_pow}]", False), - ], - } diff --git a/arch/v1/arch.c b/arch/v1/arch.c new file mode 100644 index 0000000..39cfe15 --- /dev/null +++ b/arch/v1/arch.c @@ -0,0 +1,1127 @@ +// Based on the original salis-v1 VM architecture: +// https://git.pauloliver.dev/salis-v1/about/ + +enum { +#define INST(index, label, mnemonic, symbol) label, + INST_SET +#undef INST +}; + +#if (defined(COMMAND_BENCH) || defined(COMMAND_NEW)) && defined(ANC_BYTES) +void arch_core_init(struct Core *core) { + assert(core); + +#if defined(MVEC_LOOP) + uint64_t addr = UINT64_HALF; +#else + uint64_t addr = 0; +#endif + + for (uint64_t i = 0; i < CLONES; ++i) { + uint64_t addr_clone = addr + (MVEC_SIZE / CLONES) * i; + + struct Proc *panc = proc_fetch(core, i); + + panc->mb0a = addr_clone; + panc->mb0s = ANC_SIZE; + panc->ip = addr_clone; + panc->sp = addr_clone; + } +} +#endif + +void arch_core_free(struct Core *core) { + assert(core); + (void)core; +} + +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) +void arch_core_save(FILE *f, const struct Core *core) { + assert(f); + assert(core); + + fwrite(core->iexe, sizeof(uint64_t), INST_COUNT, f); + fwrite(core->iwrt, sizeof(uint64_t), INST_COUNT, f); + fwrite(&core->emb0, sizeof(uint64_t), 1, f); + fwrite(&core->emb1, sizeof(uint64_t), 1, f); + fwrite(&core->eliv, sizeof(uint64_t), 1, f); + fwrite(&core->edea, sizeof(uint64_t), 1, f); + fwrite(&core->wmb0, sizeof(uint64_t), 1, f); + fwrite(&core->wmb1, sizeof(uint64_t), 1, f); + fwrite(&core->wdea, sizeof(uint64_t), 1, f); + fwrite(core->aeva, sizeof(uint64_t), MVEC_SIZE, f); +} +#endif + +#if defined(COMMAND_LOAD) +void arch_core_load(FILE *f, struct Core *core) { + assert(f); + assert(core); + + fread(core->iexe, sizeof(uint64_t), INST_COUNT, f); + fread(core->iwrt, sizeof(uint64_t), INST_COUNT, f); + fread(&core->emb0, sizeof(uint64_t), 1, f); + fread(&core->emb1, sizeof(uint64_t), 1, f); + fread(&core->eliv, sizeof(uint64_t), 1, f); + fread(&core->edea, sizeof(uint64_t), 1, f); + fread(&core->wmb0, sizeof(uint64_t), 1, f); + fread(&core->wmb1, sizeof(uint64_t), 1, f); + fread(&core->wdea, sizeof(uint64_t), 1, f); + fread(core->aeva, sizeof(uint64_t), MVEC_SIZE, f); +} +#endif + +uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb0a; +} + +uint64_t arch_proc_mb0_size(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb0s; +} + +uint64_t arch_proc_mb1_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb1a; +} + +uint64_t arch_proc_mb1_size(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->mb1s; +} + +uint64_t arch_proc_ip_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->ip; +} + +uint64_t arch_proc_sp_addr(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return proc_get(core, pix)->sp; +} + +uint64_t arch_proc_slice(const struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + (void)core; + (void)pix; + + return 1; +} + +void _free_memory_block(struct Core *core, uint64_t addr, uint64_t size) { + assert(core); + assert(size); + + for (uint64_t i = 0; i < size; ++i) { + mvec_free(core, addr + i); + + // Record deallocation event + ++core->aeva[addr]; + } +} + +void arch_on_proc_kill(struct Core *core) { + assert(core); + assert(core->pnum > 1); + + struct Proc *pfst = proc_fetch(core, core->pfst); + + _free_memory_block(core, pfst->mb0a, pfst->mb0s); + + if (pfst->mb1s) { + _free_memory_block(core, pfst->mb1a, pfst->mb1s); + } + + memcpy(pfst, &g_dead_proc, sizeof(struct Proc)); +} + +uint8_t _get_inst(const struct Core *core, uint64_t addr) { + assert(core); + + return mvec_get_inst(core, addr) % INST_COUNT; +} + +void _increment_ip(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + + proc->ip++; + proc->sp = proc->ip; +} + +bool _is_between(uint8_t inst, uint8_t lo, uint8_t hi) { + assert(inst < INST_COUNT); + assert(lo < INST_COUNT); + assert(hi < INST_COUNT); + assert(lo < hi); + + return (inst >= lo) && (inst <= hi); +} + +bool _is_key(uint8_t inst) { + assert(inst < INST_COUNT); + + return _is_between(inst, keya, keyp); +} + +bool _is_lock(uint8_t inst) { + assert(inst < INST_COUNT); + + return _is_between(inst, loka, lokp); +} + +bool _is_rmod(uint8_t inst) { + assert(inst < INST_COUNT); + + return _is_between(inst, nop0, nop3); +} + +bool _key_lock_match(uint8_t key, uint8_t lock) { + assert(key < INST_COUNT); + assert(lock < INST_COUNT); + assert(_is_key(key)); + + return (key - keya) == (lock - loka); +} + +bool _seek(struct Core *core, uint64_t pix, bool fwrd) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint8_t next = _get_inst(core, proc->ip + 1); + + if (!_is_key(next)) { + _increment_ip(core, pix); + return false; + } + + uint8_t spin = _get_inst(core, proc->sp); + + if (_key_lock_match(next, spin)) { + return true; + } + + if (fwrd) { + proc->sp++; + } else { + proc->sp--; + } + + return false; +} + +void _jump(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + +#if !defined(NDEBUG) + uint8_t next = _get_inst(core, proc->ip + 1); + uint8_t spin = _get_inst(core, proc->sp); + assert(_is_key(next)); + assert(_is_lock(spin)); + assert(_key_lock_match(next, spin)); +#endif + + proc->ip = proc->sp; +} + +void _get_reg_addr_list(struct Core *core, uint64_t pix, uint64_t **rlist, int rcount, bool offset) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + assert(rlist); + assert(rcount); + assert(rcount < 4); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t madr = proc->ip + (offset ? 2 : 1); + + for (int i = 0; i < rcount; ++i) { + rlist[i] = &proc->r0x; + } + + for (int i = 0; i < rcount; ++i) { + uint64_t mnxt = madr + i; + uint8_t mins = _get_inst(core, mnxt); + + if (!_is_rmod(mins)) { + break; + } + + switch (mins) { + case nop0: + rlist[i] = &proc->r0x; + break; + case nop1: + rlist[i] = &proc->r1x; + break; + case nop2: + rlist[i] = &proc->r2x; + break; + case nop3: + rlist[i] = &proc->r3x; + break; + } + } +} + +void _addr(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t *reg; + +#if !defined(NDEBUG) + uint8_t next = _get_inst(core, proc->ip + 1); + uint8_t spin = _get_inst(core, proc->sp); + assert(_is_key(next)); + assert(_is_lock(spin)); + assert(_key_lock_match(next, spin)); +#endif + + _get_reg_addr_list(core, pix, ®, 1, true); + *reg = proc->sp; + + _increment_ip(core, pix); +} + +void _ifnz(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t *reg; + + _get_reg_addr_list(core, pix, ®, 1, false); + + uint64_t jmod = _is_rmod(_get_inst(core, proc->ip + 1)) ? 1 : 0; + uint64_t rmod = *reg ? 1 : 2; + + proc->ip += jmod + rmod; + proc->sp = proc->ip; +} + +void _free_child_memory_of(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + + assert(proc->mb1s); + + _free_memory_block(core, proc->mb1a, proc->mb1s); + + proc->mb1a = 0; + proc->mb1s = 0; +} + +void _alloc(struct Core *core, uint64_t pix, bool fwrd) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t *regs[2]; + + _get_reg_addr_list(core, pix, regs, 2, false); + + uint64_t bsize = *regs[0]; + + // Do nothing if block-size is zero + if (!bsize) { + _increment_ip(core, pix); + return; + } + + // Do nothing if seek pointer is not adjacent to allocated memory block + if (proc->mb1s) { + uint64_t exp_addr = proc->mb1a; + + if (fwrd) { + exp_addr += proc->mb1s; + } else { + exp_addr--; + } + + if (proc->sp != exp_addr) { + _increment_ip(core, pix); + return; + } + } + + // Allocation was successful, store block address on register + if (proc->mb1s == bsize) { + _increment_ip(core, pix); + *regs[1] = proc->mb1a; + return; + } + + // Seek pointer collided with another allocated block, discard and keep looking + if (mvec_is_alloc(core, proc->sp)) { + if (proc->mb1s) { + _free_child_memory_of(core, pix); + } + + if (fwrd) { + proc->sp++; + } else { + proc->sp--; + } + + return; + } + + // Free (non-allocated) byte found, enlarge child block 1 byte + mvec_alloc(core, proc->sp); + + // Record allocation event + ++core->aeva[proc->sp]; + + if (!proc->mb1s || !fwrd) { + proc->mb1a = proc->sp; + } + + proc->mb1s++; + + // Advance seek pointer + if (fwrd) { + proc->sp++; + } else { + proc->sp--; + } +} + +void _bswap(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + + if (proc->mb1s) { + uint64_t tmpa = proc->mb0a; + uint64_t tmps = proc->mb0s; + + proc->mb0a = proc->mb1a; + proc->mb0s = proc->mb1s; + proc->mb1a = tmpa; + proc->mb1s = tmps; + } + + _increment_ip(core, pix); +} + +void _bclear(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + + if (proc->mb1s) { + _free_child_memory_of(core, pix); + } + + _increment_ip(core, pix); +} + +void _split(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + + if (proc->mb1s) { + struct Proc child = {0}; + + child.ip = proc->mb1a; + child.sp = proc->mb1a; + child.mb0a = proc->mb1a; + child.mb0s = proc->mb1s; + + proc->mb1a = 0; + proc->mb1s = 0; + + // A new organism is born :) + proc_new(core, &child); + } else { + assert(!proc->mb1a); + } + + _increment_ip(core, pix); +} + +void _3rop(struct Core *core, uint64_t pix, uint8_t inst) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + uint64_t *regs[3]; + + _get_reg_addr_list(core, pix, regs, 3, false); + + // Organisms can do arithmetic using any sequence of 3 registers + switch (inst) { + case addn: + *regs[0] = *regs[1] + *regs[2]; + break; + case subn: + *regs[0] = *regs[1] - *regs[2]; + break; + case muln: + *regs[0] = *regs[1] * *regs[2]; + break; + case divn: + // Division by zero + // Do nothing + if (*regs[2]) { + *regs[0] = *regs[1] / *regs[2]; + } + + break; + default: + assert(false); + } + + _increment_ip(core, pix); +} + +void _1rop(struct Core *core, uint64_t pix, uint8_t inst) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + uint64_t *reg; + + _get_reg_addr_list(core, pix, ®, 1, false); + + switch (inst) { + case incn: + (*reg)++; + break; + case decn: + (*reg)--; + break; + case notn: + *reg = !(*reg); + break; + case shfl: + *reg <<= 1; + break; + case shfr: + *reg >>= 1; + break; + case zero: + *reg = 0; + break; + case unit: + *reg = 1; + break; + default: + assert(false); + } + + _increment_ip(core, pix); +} + +void _push(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t *reg; + + _get_reg_addr_list(core, pix, ®, 1, false); + + proc->s7 = proc->s6; + proc->s6 = proc->s5; + proc->s5 = proc->s4; + proc->s4 = proc->s3; + proc->s3 = proc->s2; + proc->s2 = proc->s1; + proc->s1 = proc->s0; + proc->s0 = *reg; + + _increment_ip(core, pix); +} + +void _pop(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t *reg; + + _get_reg_addr_list(core, pix, ®, 1, false); + + *reg = proc->s0; + proc->s0 = proc->s1; + proc->s1 = proc->s2; + proc->s2 = proc->s3; + proc->s3 = proc->s4; + proc->s4 = proc->s5; + proc->s5 = proc->s6; + proc->s6 = proc->s7; + proc->s7 = 0; + + _increment_ip(core, pix); +} + +int _sp_dir(uint64_t src, uint64_t dst) { + if (src == dst) { + return 0; + } else if (src - dst <= dst - src) { + return -1; + } else { + return 1; + } +} + +void _load(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t *regs[2]; + + _get_reg_addr_list(core, pix, regs, 2, false); + + int sp_dir = _sp_dir(proc->sp, *regs[0]); + + if (sp_dir == 1) { + proc->sp++; + } else if (sp_dir == -1) { + proc->sp--; + } else { + *regs[1] = mvec_get_inst(core, *regs[0]); + _increment_ip(core, pix); + } +} + +bool _is_writeable_by(const struct Core *core, uint64_t addr, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + return !mvec_is_alloc(core, addr) || mvec_is_proc_owner(core, addr, pix); +} + +void _write(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint64_t *regs[2]; + + _get_reg_addr_list(core, pix, regs, 2, false); + + int sp_dir = _sp_dir(proc->sp, *regs[0]); + + if (sp_dir == 1) { + proc->sp++; + } else if (sp_dir == -1) { + proc->sp--; + } else { + if (_is_writeable_by(core, *regs[0], pix)) { + // Store write event + uint8_t inst = *regs[1] % INST_COUNT; + + ++core->iwrt[inst]; + + if (mvec_is_in_mb0_of_proc(core, *regs[0], pix)) { + ++core->wmb0; + } else if (mvec_is_in_mb1_of_proc(core, *regs[0], pix)) { + ++core->wmb1; + } else { + ++core->wdea; + } + + // Write instruction + mvec_set_inst(core, *regs[0], *regs[1] % INST_CAP); + } + + _increment_ip(core, pix); + } +} + +void _2rop(struct Core *core, uint64_t pix, uint8_t inst) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + uint64_t *regs[2]; + + _get_reg_addr_list(core, pix, regs, 2, false); + + switch (inst) { + case dupl: + *regs[1] = *regs[0]; + break; + case swap: + { + uint64_t tmp = *regs[0]; + *regs[0] = *regs[1]; + *regs[1] = tmp; + } + + break; + default: + assert(false); + } + + _increment_ip(core, pix); +} + +void arch_proc_step(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + struct Proc *proc = proc_fetch(core, pix); + uint8_t inst = _get_inst(core, proc->ip); + + // Store execute event + ++core->iexe[inst]; + + if (mvec_is_in_mb0_of_proc(core, proc->ip, pix)) { + ++core->emb0; + } else if (mvec_is_in_mb1_of_proc(core, proc->ip, pix)) { + ++core->emb1; + } else if (mvec_is_alloc(core, proc->ip)) { + ++core->eliv; + } else { + ++core->edea; + } + + // Execute instruction + switch (inst) { + case jmpb: + if (_seek(core, pix, false)) { + _jump(core, pix); + } + + break; + case jmpf: + if (_seek(core, pix, true)) { + _jump(core, pix); + } + + break; + case adrb: + if (_seek(core, pix, false)) { + _addr(core, pix); + } + + break; + case adrf: + if (_seek(core, pix, true)) { + _addr(core, pix); + } + + break; + case ifnz: + _ifnz(core, pix); + break; + case allb: + _alloc(core, pix, false); + break; + case allf: + _alloc(core, pix, true); + break; + case bswp: + _bswap(core, pix); + break; + case bclr: + _bclear(core, pix); + break; + case splt: + _split(core, pix); + break; + case addn: + case subn: + case muln: + case divn: + _3rop(core, pix, inst); + break; + case incn: + case decn: + case notn: + case shfl: + case shfr: + case zero: + case unit: + _1rop(core, pix, inst); + break; + case pshn: + _push(core, pix); + break; + case popn: + _pop(core, pix); + break; + case load: + _load(core, pix); + break; + case wrte: + _write(core, pix); + break; + case dupl: + case swap: + _2rop(core, pix, inst); + break; + default: + _increment_ip(core, pix); + break; + } + + return; +} + +#if !defined(NDEBUG) +void arch_validate_proc(const struct Core *core, uint64_t pix) { + assert(core); + + const struct Proc *proc = proc_get(core, pix); + + assert(proc->mb0s); + + if (proc->mb1a) { + assert(proc->mb1s); + } + + for (uint64_t i = 0; i < proc->mb0s; ++i) { + uint64_t addr = proc->mb0a + i; + assert(mvec_is_alloc(core, addr)); + assert(mvec_is_proc_owner(core, addr, pix)); + } + + for (uint64_t i = 0; i < proc->mb1s; ++i) { + uint64_t addr = proc->mb1a + i; + assert(mvec_is_alloc(core, addr)); + assert(mvec_is_proc_owner(core, addr, pix)); + } +} +#endif + +wchar_t arch_symbol(uint8_t inst) { + switch (inst % INST_COUNT) { +#define INST(index, label, mnemonic, symbol) case index: return symbol; + INST_SET +#undef INST + } + + assert(false); + return L'\0'; +} + +const char *arch_mnemonic(uint8_t inst) { + switch (inst % INST_COUNT) { +#define INST(index, label, mnemonic, symbol) case index: return mnemonic; + INST_SET +#undef INST + } + + assert(false); + return NULL; +} + +// ---------------------------------------------------------------------------- +// Data aggregation functions +// ---------------------------------------------------------------------------- +#if defined(DATA_PUSH_PATH) +void arch_push_data_header() { + assert(g_sim_data); + + g_info("Creating 'trend' table in SQLite database"); + salis_exec_sql( + 0, NULL, NULL, + "create table trend (" +#define FOR_CORE(i) \ + "cycl_" #i " int not null, " \ + "mall_" #i " int not null, " \ + "pnum_" #i " int not null, " \ + "pfst_" #i " int not null, " \ + "plst_" #i " int not null, " \ + "amb0_" #i " real not null, " \ + "amb1_" #i " real not null, " \ + "emb0_" #i " int not null, " \ + "emb1_" #i " int not null, " \ + "eliv_" #i " int not null, " \ + "edea_" #i " int not null, " \ + "wmb0_" #i " int not null, " \ + "wmb1_" #i " int not null, " \ + "wdea_" #i " int not null, " + FOR_CORES +#undef FOR_CORE + "step int not null" + ");" + ); + + // Instruction events + char *iprefs[] = { "pop", "exe", "wrt" }; + int iprefs_cnt = sizeof(iprefs) / sizeof(iprefs[0]); + + for (int i = 0; i < CORES; ++i) { + for (int j = 0; j < iprefs_cnt; ++j) { + g_info("Creating '%s_%d' table in SQLite database", iprefs[j], i); + salis_exec_sql( + 0, NULL, NULL, + "create table %s_%d (" +#define FOR_CORE(i) "cycl_" #i " int not null, " + FOR_CORES +#undef FOR_CORE +#define INST(index, label, mnemonic, symbol) #label " int not null, " + INST_SET +#undef INST + "step int not null" + ");", + iprefs[j], i + ); + } + } + + // Memory events + char *eprefs[] = { "aev" }; + int eprefs_cnt = sizeof(eprefs) / sizeof(eprefs[0]); + + for (int i = 0; i < CORES; ++i) { + for (int j = 0; j < eprefs_cnt; ++j) { + g_info("Creating '%s_%d' table in SQLite database", eprefs[j], i); + salis_exec_sql( + 0, NULL, NULL, + "create table %s_%d (" +#define FOR_CORE(i) "cycl_" #i " int not null, " + FOR_CORES +#undef FOR_CORE + "size int not null, " + "evts blob not null ," + "step int not null" + ");", + eprefs[j], i + ); + } + } +} + +void arch_push_data_line() { + assert(g_sim_data); + + // Instruction population + uint64_t ipop[CORES][INST_COUNT] = { 0 }; + + // Average memory block sizes + double amb0[CORES] = { 0 }; + double amb1[CORES] = { 0 }; + + for (int i = 0; i < CORES; ++i) { + struct Core *core = &g_cores[i]; + + for (uint64_t j = core->pfst; j <= core->plst; ++j) { + const struct Proc *proc = proc_get(core, j); + + amb0[i] += (double)proc->mb0s; + amb1[i] += (double)proc->mb1s; + } + + amb0[i] /= core->pnum; + amb1[i] /= core->pnum; + + for (uint64_t j = 0; j < MVEC_SIZE; ++j) { + ++ipop[i][_get_inst(core, j)]; + } + +#if !defined(NDEBUG) + uint64_t pop_tot = 0; + + for (int j = 0; j < INST_COUNT; ++j) { + pop_tot += ipop[i][j]; + } + + assert(pop_tot == MVEC_SIZE); +#endif + } + + g_info("Pushing row to 'trend' table in SQLite database"); + salis_exec_sql( + 0, NULL, NULL, + "insert into trend (" +#define FOR_CORE(i) \ + "cycl_" #i ", " \ + "mall_" #i ", " \ + "pnum_" #i ", " \ + "pfst_" #i ", " \ + "plst_" #i ", " \ + "amb0_" #i ", " \ + "amb1_" #i ", " \ + "emb0_" #i ", " \ + "emb1_" #i ", " \ + "eliv_" #i ", " \ + "edea_" #i ", " \ + "wmb0_" #i ", " \ + "wmb1_" #i ", " \ + "wdea_" #i ", " + FOR_CORES +#undef FOR_CORE + "step" + ") values (" +#define FOR_CORE(i) "%ld, %ld, %ld, %ld, %ld, %f, %f, %ld, %ld, %ld, %ld, %ld, %ld, %ld, " + FOR_CORES +#undef FOR_CORE + "%ld" + ");", +#define FOR_CORE(i) \ + g_cores[i].cycl, \ + g_cores[i].mall, \ + g_cores[i].pnum, \ + g_cores[i].pfst, \ + g_cores[i].plst, \ + amb0[i], \ + amb1[i], \ + g_cores[i].emb0, \ + g_cores[i].emb1, \ + g_cores[i].eliv, \ + g_cores[i].edea, \ + g_cores[i].wmb0, \ + g_cores[i].wmb1, \ + g_cores[i].wdea, + FOR_CORES +#undef FOR_CORE + g_steps + ); + + char *iprefs[] = { "pop", "exe", "wrt" }; + int iprefs_cnt = sizeof(iprefs) / sizeof(iprefs[0]); + + for (int i = 0; i < CORES; ++i) { + for (int j = 0; j < iprefs_cnt; ++j) { + uint64_t *ia; + + if (!strcmp("pop", iprefs[j])) { + ia = ipop[i]; + } else if (!strcmp("exe", iprefs[j])) { + ia = g_cores[i].iexe; + } else if (!strcmp("wrt", iprefs[j])) { + ia = g_cores[i].iwrt; + } + + g_info("Pushing row to '%s_%d' table in SQLite database", iprefs[j], i); + salis_exec_sql( + 0, NULL, NULL, + "insert into %s_%d (" +#define FOR_CORE(i) "cycl_" #i ", " + FOR_CORES +#undef FOR_CORE +#define INST(index, label, mnemonic, symbol) #label ", " + INST_SET +#undef INST + "step" + ") values (" +#define FOR_CORE(i) "%ld, " + FOR_CORES +#undef FOR_CORE +#define INST(index, label, mnemonic, symbol) "%ld, " + INST_SET +#undef INST + "%ld" + ");", + iprefs[j], + i, +#define FOR_CORE(i) g_cores[i].cycl, + FOR_CORES +#undef FOR_CORE +#define INST(index, label, mnemonic, symbol) ia[index], + INST_SET +#undef INST + g_steps + ); + } + } + + char *eprefs[] = { "aev" }; + int eprefs_cnt = sizeof(eprefs) / sizeof(eprefs[0]); + + // TODO: insert memory events + for (int i = 0; i < CORES; ++i) { + for (int j = 0; j < eprefs_cnt; ++j) { + uint64_t *in; + + if (!strcmp("aev", eprefs[j])) { + in = g_cores[i].aeva; + } + + // Compress event data + size_t size = sizeof(uint64_t) * MVEC_SIZE; + char *out = malloc(size); + assert(out); + + z_stream strm = { 0 }; + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + + deflateInit(&strm, Z_DEFAULT_COMPRESSION); + + strm.avail_in = size; + strm.avail_out = size; + strm.next_in = (Bytef *)in; + strm.next_out = (Bytef *)out; + + deflate(&strm, Z_FINISH); + + // Insert blob + const void *blob = out; + int blob_size = strm.total_out; + + g_info("Pushing row to '%s_%d' table in SQLite database", eprefs[j], i); + salis_exec_sql( + 1, &blob, &blob_size, + "insert into %s_%d (" +#define FOR_CORE(i) "cycl_" #i ", " + FOR_CORES +#undef FOR_CORE + "size, evts, step" + ") values (" +#define FOR_CORE(i) "%ld, " + FOR_CORES +#undef FOR_CORE + "%ld, ?, %ld" + ");", + eprefs[j], i, +#define FOR_CORE(i) g_cores[i].cycl, + FOR_CORES +#undef FOR_CORE + blob_size, g_steps + ); + + deflateEnd(&strm); + free(out); + } + } + + // Reset data aggregation fields + for (int i = 0; i < CORES; ++i) { + struct Core *core = &g_cores[i]; + + memset(core->iexe, 0, sizeof(uint64_t) * INST_COUNT); + memset(core->iwrt, 0, sizeof(uint64_t) * INST_COUNT); + + core->emb0 = 0; + core->emb1 = 0; + core->eliv = 0; + core->edea = 0; + core->wmb0 = 0; + core->wmb1 = 0; + core->wdea = 0; + + memset(core->aeva, 0, sizeof(uint64_t) * MVEC_SIZE); + //memset(core->eeva, 0, sizeof(uint64_t) * MVEC_SIZE); + //memset(core->weva, 0, sizeof(uint64_t) * MVEC_SIZE); + } +} +#endif diff --git a/arch/v1/arch_vars.py b/arch/v1/arch_vars.py new file mode 100644 index 0000000..2373e6b --- /dev/null +++ b/arch/v1/arch_vars.py @@ -0,0 +1,116 @@ +class ArchVars: + def __init__(self, args): + self.inst_set = [ + (["noop"], " "), + (["nop0"], "0"), + (["nop1"], "1"), + (["nop2"], "2"), + (["nop3"], "3"), + + (["jmpb"], "("), + (["jmpf"], ")"), + (["adrb"], "["), + (["adrf"], "]"), + (["ifnz"], "?"), + + (["allb"], "{"), + (["allf"], "}"), + (["bswp"], "%"), + (["bclr"], "|"), + (["splt"], "$"), + + (["addn"], "+"), + (["subn"], "-"), + (["muln"], "*"), + (["divn"], "/"), + (["incn"], "^"), + (["decn"], "v"), + (["notn"], "!"), + (["shfl"], "<"), + (["shfr"], ">"), + (["zero"], "z"), + (["unit"], "u"), + + (["pshn"], "#"), + (["popn"], "~"), + + (["load"], "."), + (["wrte"], ":"), + (["dupl"], "="), + (["swap"], "x"), + + (["keya"], "a"), + (["keyb"], "b"), + (["keyc"], "c"), + (["keyd"], "d"), + (["keye"], "e"), + (["keyf"], "f"), + (["keyg"], "g"), + (["keyh"], "h"), + (["keyi"], "i"), + (["keyj"], "j"), + (["keyk"], "k"), + (["keyl"], "l"), + (["keym"], "m"), + (["keyn"], "n"), + (["keyo"], "o"), + (["keyp"], "p"), + + (["loka"], "A"), + (["lokb"], "B"), + (["lokc"], "C"), + (["lokd"], "D"), + (["loke"], "E"), + (["lokf"], "F"), + (["lokg"], "G"), + (["lokh"], "H"), + (["loki"], "I"), + (["lokj"], "J"), + (["lokk"], "K"), + (["lokl"], "L"), + (["lokm"], "M"), + (["lokn"], "N"), + (["loko"], "O"), + (["lokp"], "P"), + ] + + self.core_fields = [ + ("uint64_t", "iexe", f"[{len(self.inst_set)}]"), # instruction execution counter + ("uint64_t", "iwrt", f"[{len(self.inst_set)}]"), # instruction write counter + + ("uint64_t", "emb0", ""), # executions within mb0 counter + ("uint64_t", "emb1", ""), # executions within mb1 counter + ("uint64_t", "eliv", ""), # executions within not-owned live code counter + ("uint64_t", "edea", ""), # executions within dead code counter + ("uint64_t", "wmb0", ""), # writes within mb0 counter + ("uint64_t", "wmb1", ""), # writes within mb1 counter + ("uint64_t", "wdea", ""), # writes within dead code counter + + ("uint64_t", "aeva", f"[{2 ** args.mvec_pow}]"), # allocation events array + #("uint64_t", "eeva", f"[{2 ** args.mvec_pow}]"), # execution events array + #("uint64_t", "weva", f"[{2 ** args.mvec_pow}]"), # write events array + ] + + self.data_is_compressed = True + self.mvec_loop = False + + self.proc_fields = [ + ("uint64_t", "ip"), + ("uint64_t", "sp"), + ("uint64_t", "mb0a"), + ("uint64_t", "mb0s"), + ("uint64_t", "mb1a"), + ("uint64_t", "mb1s"), + ("uint64_t", "r0x"), + ("uint64_t", "r1x"), + ("uint64_t", "r2x"), + ("uint64_t", "r3x"), + ("uint64_t", "s0"), + ("uint64_t", "s1"), + ("uint64_t", "s2"), + ("uint64_t", "s3"), + ("uint64_t", "s4"), + ("uint64_t", "s5"), + ("uint64_t", "s6"), + ("uint64_t", "s7"), + ] diff --git a/bench.j2.c b/bench.j2.c deleted file mode 100644 index e78861f..0000000 --- a/bench.j2.c +++ /dev/null @@ -1,52 +0,0 @@ -// Author: Paul Oliver -// Project: Salis - -// Simple benchmark test helps measure simulation speed. -// Steps the simulation N times and prints part of the simulator's state. - -void log_impl(const char *format, ...) { - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); -} - -int main() { - g_info = log_impl; - g_warn = log_impl; - - g_info("Salis Benchmark Test\n\n"); - - salis_init(); - salis_step({{ args.steps }}); - - g_info("seed => %#lx\n", {{ args.seed }}); - g_info("g_steps => %#lx\n", g_steps); - g_info("g_syncs => %#lx\n", g_syncs); - - for (int i = 0; i < {{ args.cores }}; ++i) { - g_info("\n"); - g_info("core %d mall => %#lx\n", i, g_cores[i].mall); - g_info("core %d mut0 => %#lx\n", i, g_cores[i].muta[0]); - g_info("core %d mut1 => %#lx\n", i, g_cores[i].muta[1]); - g_info("core %d mut2 => %#lx\n", i, g_cores[i].muta[2]); - g_info("core %d mut3 => %#lx\n", i, g_cores[i].muta[3]); - g_info("core %d pnum => %#lx\n", i, g_cores[i].pnum); - g_info("core %d pcap => %#lx\n", i, g_cores[i].pcap); - g_info("core %d pfst => %#lx\n", i, g_cores[i].pfst); - g_info("core %d plst => %#lx\n", i, g_cores[i].plst); - g_info("core %d pcur => %#lx\n", i, g_cores[i].pcur); - g_info("core %d psli => %#lx\n", i, g_cores[i].psli); - g_info("core %d cycl => %#lx\n", i, g_cores[i].cycl); - g_info("core %d ivpt => %#lx\n", i, g_cores[i].ivpt); - g_info("\n"); - - for (int j = 0; j < 32; ++j) { - g_info("%02x ", g_cores[i].mvec[j]); - } - - g_info("\n"); - } - - salis_free(); -} diff --git a/core.c b/core.c new file mode 100644 index 0000000..a4b57d8 --- /dev/null +++ b/core.c @@ -0,0 +1,982 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DATA_PUSH_BUSY_TIMEOUT 600000 +#define INST_CAP 0x80 +#define INST_MASK 0x7f +#define IPC_FLAG 0x80 +#define MALL_FLAG 0x80 +#define UINT64_HALF 0x8000000000000000ul + +struct Proc { +#define PROC_FIELD(type, name) type name; + PROC_FIELDS +#undef PROC_FIELD +}; + +struct Core { + uint64_t cycl; + uint64_t mall; + uint64_t muta[4]; + + uint64_t pnum; + uint64_t pcap; + uint64_t pfst; + uint64_t plst; + uint64_t pcur; + uint64_t psli; + + thrd_t thrd; + uint64_t thrd_idx; + + uint64_t ivpt; + uint64_t *ivav; + uint8_t *iviv; + +#define CORE_FIELD(type, name, suff) type name suff; + CORE_FIELDS +#undef CORE_FIELD + + struct Proc *pvec; + uint8_t mvec[MVEC_SIZE]; + uint8_t tgap[THREAD_GAP]; +}; + +// Globals +struct Core g_cores[CORES]; +uint64_t g_steps; +uint64_t g_syncs; +const struct Proc g_dead_proc; + +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) +char g_asav_pbuf[AUTOSAVE_NAME_LEN]; +#endif + +#if defined(DATA_PUSH_PATH) +sqlite3 *g_sim_data; +#endif + +// Each UI must install these logger functions before salis_init() gets invoked +void (*g_info)(const char *fmt, ...); +void (*g_warn)(const char *fmt, ...); + +// Each architecture must define these functions +#if defined(COMMAND_BENCH) || defined(COMMAND_NEW) +void arch_core_init(struct Core *core); +#endif + +void arch_core_free(struct Core *core); + +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) +void arch_core_save(FILE *f, const struct Core *core); +#endif + +#if defined(COMMAND_LOAD) +void arch_core_load(FILE *f, struct Core *core); +#endif + +uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix); +uint64_t arch_proc_mb0_size(const struct Core *core, uint64_t pix); +uint64_t arch_proc_mb1_addr(const struct Core *core, uint64_t pix); +uint64_t arch_proc_mb1_size(const struct Core *core, uint64_t pix); +uint64_t arch_proc_ip_addr(const struct Core *core, uint64_t pix); +uint64_t arch_proc_sp_addr(const struct Core *core, uint64_t pix); +uint64_t arch_proc_slice(const struct Core *core, uint64_t pix); +void arch_on_proc_kill(struct Core *core); +void arch_proc_step(struct Core *core, uint64_t pix); + +#if !defined(NDEBUG) +void arch_validate_proc(const struct Core *core, uint64_t pix); +#endif + +wchar_t arch_symbol(uint8_t inst); +const char *arch_mnemonic(uint8_t inst); + +#if defined(DATA_PUSH_PATH) +void arch_push_data_header(); +void arch_push_data_line(); +#endif + +// ---------------------------------------------------------------------------- +// Memory vector functions +// ---------------------------------------------------------------------------- +#if defined(MVEC_LOOP) +uint64_t mvec_loop(uint64_t addr) { + return addr % MVEC_SIZE; +} +#endif + +bool mvec_is_alloc(const struct Core *core, uint64_t addr) { + assert(core); + +#if defined(MVEC_LOOP) + return core->mvec[mvec_loop(addr)] & MALL_FLAG ? true : false; +#else + if (addr < MVEC_SIZE) { + return core->mvec[addr] & MALL_FLAG ? true : false; + } else { + return true; + } +#endif +} + +void mvec_alloc(struct Core *core, uint64_t addr) { + assert(core); + assert(!mvec_is_alloc(core, addr)); + +#if defined(MVEC_LOOP) + core->mvec[mvec_loop(addr)] |= MALL_FLAG; +#else + assert(addr < MVEC_SIZE); + core->mvec[addr] |= MALL_FLAG; +#endif + core->mall++; +} + +void mvec_free(struct Core *core, uint64_t addr) { + assert(core); + assert(mvec_is_alloc(core, addr)); + +#if defined(MVEC_LOOP) + core->mvec[mvec_loop(addr)] ^= MALL_FLAG; +#else + assert(addr < MVEC_SIZE); + core->mvec[addr] ^= MALL_FLAG; +#endif + core->mall--; +} + +uint8_t mvec_get_byte(const struct Core *core, uint64_t addr) { + assert(core); + +#if defined(MVEC_LOOP) + return core->mvec[mvec_loop(addr)]; +#else + if (addr < MVEC_SIZE) { + return core->mvec[addr]; + } else { + return 0; + } +#endif +} + +uint8_t mvec_get_inst(const struct Core *core, uint64_t addr) { + assert(core); + +#if defined(MVEC_LOOP) + return core->mvec[mvec_loop(addr)] & INST_MASK; +#else + if (addr < MVEC_SIZE) { + return core->mvec[addr] & INST_MASK; + } else { + return 0; + } +#endif +} + +void mvec_set_inst(struct Core *core, uint64_t addr, uint8_t inst) { + assert(core); + assert(inst < INST_CAP); + +#if defined(MVEC_LOOP) + core->mvec[mvec_loop(addr)] &= MALL_FLAG; + core->mvec[mvec_loop(addr)] |= inst; +#else + assert(addr < MVEC_SIZE); + core->mvec[addr] &= MALL_FLAG; + core->mvec[addr] |= inst; +#endif +} + +#if defined(MUTA_FLIP) +void mvec_flip_bit(struct Core *core, uint64_t addr, int bit) { + assert(core); + assert(bit < 8); + core->mvec[addr] ^= (1 << bit) & INST_MASK; +} +#endif + +bool mvec_proc_is_live(const struct Core *core, uint64_t pix) { + assert(core); + + return pix >= core->pfst && pix <= core->plst; +} + +bool mvec_is_in_mb0_of_proc(const struct Core *core, uint64_t addr, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + uint64_t mb0a = arch_proc_mb0_addr(core, pix); + uint64_t mb0s = arch_proc_mb0_size(core, pix); + + return ((addr - mb0a) % MVEC_SIZE) < mb0s; +} + +bool mvec_is_in_mb1_of_proc(const struct Core *core, uint64_t addr, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + uint64_t mb1a = arch_proc_mb1_addr(core, pix); + uint64_t mb1s = arch_proc_mb1_size(core, pix); + + return ((addr - mb1a) % MVEC_SIZE) < mb1s; +} + +bool mvec_is_proc_owner(const struct Core *core, uint64_t addr, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return mvec_is_in_mb0_of_proc(core, addr, pix) || mvec_is_in_mb1_of_proc(core, addr, pix); +} + +uint64_t mvec_get_owner(const struct Core *core, uint64_t addr) { + assert(core); + assert(mvec_is_alloc(core, addr)); + + for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) { + if (mvec_is_proc_owner(core, addr, pix)) { + return pix; + } + } + + assert(false); + return -1; +} + +// ---------------------------------------------------------------------------- +// Mutator functions +// ---------------------------------------------------------------------------- +#if defined(COMMAND_BENCH) || defined(COMMAND_NEW) +uint64_t muta_smix(uint64_t *seed) { + assert(seed); + + uint64_t next = (*seed += 0x9e3779b97f4a7c15); + next = (next ^ (next >> 30)) * 0xbf58476d1ce4e5b9; + next = (next ^ (next >> 27)) * 0x94d049bb133111eb; + + return next ^ (next >> 31); +} +#endif + +uint64_t muta_ro64(uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +uint64_t muta_next(struct Core *core) { + assert(core); + + uint64_t r = muta_ro64(core->muta[1] * 5, 7) * 9; + uint64_t t = core->muta[1] << 17; + + core->muta[2] ^= core->muta[0]; + core->muta[3] ^= core->muta[1]; + core->muta[1] ^= core->muta[2]; + core->muta[0] ^= core->muta[3]; + + core->muta[2] ^= t; + core->muta[3] = muta_ro64(core->muta[3], 45); + + return r; +} + +void muta_cosmic_ray(struct Core *core) { + assert(core); + + uint64_t a = muta_next(core) % MUTA_RANGE; + uint64_t b = muta_next(core); + + if (a < MVEC_SIZE) { +#if defined(MUTA_FLIP) + mvec_flip_bit(core, a, (int)(b % 8)); +#else + mvec_set_inst(core, a, b & INST_MASK); +#endif + } +} + +// ---------------------------------------------------------------------------- +// Process functions +// ---------------------------------------------------------------------------- +void proc_new(struct Core *core, const struct Proc *proc) { + assert(core); + assert(proc); + + if (core->pnum == core->pcap) { + // Reallocate dynamic array + uint64_t new_pcap = core->pcap * 2; + struct Proc *new_pvec = calloc(new_pcap, sizeof(struct Proc)); + + for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) { + uint64_t iold = pix % core->pcap; + uint64_t inew = pix % new_pcap; + memcpy(&new_pvec[inew], &core->pvec[iold], sizeof(struct Proc)); + } + + free(core->pvec); + core->pcap = new_pcap; + core->pvec = new_pvec; + } + + core->pnum++; + core->plst++; + memcpy(&core->pvec[core->plst % core->pcap], proc, sizeof(struct Proc)); +} + +void proc_kill(struct Core *core) { + assert(core); + assert(core->pnum > 1); + + arch_on_proc_kill(core); + + core->pcur++; + core->pfst++; + core->pnum--; +} + +const struct Proc *proc_get(const struct Core *core, uint64_t pix) { + assert(core); + + if (mvec_proc_is_live(core, pix)) { + return &core->pvec[pix % core->pcap]; + } else { + return &g_dead_proc; + } +} + +struct Proc *proc_fetch(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + + return &core->pvec[pix % core->pcap]; +} + +// ---------------------------------------------------------------------------- +// Core functions +// ---------------------------------------------------------------------------- +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) +void core_save(FILE *f, const struct Core *core) { + assert(f); + assert(core); + + fwrite(&core->cycl, sizeof(uint64_t), 1, f); + fwrite(&core->mall, sizeof(uint64_t), 1, f); + fwrite(core->muta, sizeof(uint64_t), 4, f); + fwrite(&core->pnum, sizeof(uint64_t), 1, f); + fwrite(&core->pcap, sizeof(uint64_t), 1, f); + fwrite(&core->pfst, sizeof(uint64_t), 1, f); + fwrite(&core->plst, sizeof(uint64_t), 1, f); + fwrite(&core->pcur, sizeof(uint64_t), 1, f); + fwrite(&core->psli, sizeof(uint64_t), 1, f); + fwrite(&core->ivpt, sizeof(uint64_t), 1, f); + + fwrite(core->iviv, sizeof(uint8_t), SYNC_INTERVAL, f); + fwrite(core->ivav, sizeof(uint64_t), SYNC_INTERVAL, f); + fwrite(core->pvec, sizeof(struct Proc), core->pcap, f); + fwrite(core->mvec, sizeof(uint8_t), MVEC_SIZE, f); + + arch_core_save(f, core); +} +#endif + +#if defined(COMMAND_BENCH) || defined(COMMAND_NEW) +#if defined(ANC_BYTES) +void core_assemble_ancestor(struct Core *core) { + assert(core); + +#if defined(MVEC_LOOP) + uint64_t addr = UINT64_HALF; +#else + uint64_t addr = 0; +#endif + + uint8_t anc_bytes[] = ANC_BYTES; + + for (uint64_t i = 0; i < sizeof(anc_bytes); ++i, ++addr) { + for (uint64_t j = 0; j < CLONES; ++j) { + uint64_t addr_clone = addr + (MVEC_SIZE / CLONES) * j; + + mvec_alloc(core, addr_clone); + mvec_set_inst(core, addr_clone, anc_bytes[i]); + } + } +} +#endif + +void core_init(struct Core *core, uint64_t *seed) { + assert(core); + assert(seed); + + if (*seed) { + core->muta[0] = muta_smix(seed); + core->muta[1] = muta_smix(seed); + core->muta[2] = muta_smix(seed); + core->muta[3] = muta_smix(seed); + } + + core->pnum = CLONES; + core->pcap = CLONES; + core->plst = CLONES - 1; + core->iviv = calloc(SYNC_INTERVAL, sizeof(uint8_t)); + core->ivav = calloc(SYNC_INTERVAL, sizeof(uint64_t)); + core->pvec = calloc(core->pcap, sizeof(struct Proc)); + + assert(core->iviv); + assert(core->ivav); + assert(core->pvec); + +#if defined(ANC_BYTES) + core_assemble_ancestor(core); + arch_core_init(core); +#endif +} +#endif + +#if defined(COMMAND_LOAD) +void core_load(FILE *f, struct Core *core) { + assert(f); + assert(core); + + fread(&core->cycl, sizeof(uint64_t), 1, f); + fread(&core->mall, sizeof(uint64_t), 1, f); + fread(core->muta, sizeof(uint64_t), 4, f); + fread(&core->pnum, sizeof(uint64_t), 1, f); + fread(&core->pcap, sizeof(uint64_t), 1, f); + fread(&core->pfst, sizeof(uint64_t), 1, f); + fread(&core->plst, sizeof(uint64_t), 1, f); + fread(&core->pcur, sizeof(uint64_t), 1, f); + fread(&core->psli, sizeof(uint64_t), 1, f); + fread(&core->ivpt, sizeof(uint64_t), 1, f); + + core->iviv = calloc(SYNC_INTERVAL, sizeof(uint8_t)); + core->ivav = calloc(SYNC_INTERVAL, sizeof(uint64_t)); + core->pvec = calloc(core->pcap, sizeof(struct Proc)); + + assert(core->iviv); + assert(core->ivav); + assert(core->pvec); + + fread(core->iviv, sizeof(uint8_t), SYNC_INTERVAL, f); + fread(core->ivav, sizeof(uint64_t), SYNC_INTERVAL, f); + fread(core->pvec, sizeof(struct Proc), core->pcap, f); + fread(core->mvec, sizeof(uint8_t), MVEC_SIZE, f); + + arch_core_load(f, core); +} +#endif + +void core_pull_ipcm(struct Core *core) { + assert(core); + assert(core->ivpt < SYNC_INTERVAL); + + uint8_t *iinst = &core->iviv[core->ivpt]; + uint64_t *iaddr = &core->ivav[core->ivpt]; + + if ((*iinst & IPC_FLAG) != 0) { + mvec_set_inst(core, *iaddr, *iinst & INST_MASK); + + *iinst = 0; + *iaddr = 0; + } + + assert(*iinst == 0); + assert(*iaddr == 0); +} + +void core_push_ipcm(struct Core *core, uint8_t inst, uint64_t addr) { + assert(core); + assert(core->ivpt < SYNC_INTERVAL); + assert((inst & IPC_FLAG) == 0); + + uint8_t *iinst = &core->iviv[core->ivpt]; + uint64_t *iaddr = &core->ivav[core->ivpt]; + + assert(*iinst == 0); + assert(*iaddr == 0); + + *iinst = inst | IPC_FLAG; + *iaddr = addr; +} + +void core_step(struct Core *core) { + assert(core); + + if (core->psli != 0) { + core_pull_ipcm(core); + arch_proc_step(core, core->pcur); + + core->psli--; + core->ivpt++; + + return; + } + + if (core->pcur != core->plst) { + core->psli = arch_proc_slice(core, ++core->pcur); + core_step(core); + return; + } + + core->pcur = core->pfst; + core->psli = arch_proc_slice(core, core->pcur); + core->cycl++; + + // TODO: Implement a day-night cycle + while (core->mall > MVEC_SIZE / 2 && core->pnum > 1) { + proc_kill(core); + } + + muta_cosmic_ray(core); + core_step(core); +} + +// ---------------------------------------------------------------------------- +// Main salis functions +// ---------------------------------------------------------------------------- +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) +void salis_save(const char *path) { +#if defined(COMPRESS) + size_t size = 0; + char *in = NULL; + FILE *f = open_memstream(&in, &size); +#else + FILE *f = fopen(path, "wb"); +#endif + + assert(f); + + for (int i = 0; i < CORES; ++i) { + core_save(f, &g_cores[i]); + } + + fwrite(&g_steps, sizeof(uint64_t), 1, f); + fwrite(&g_syncs, sizeof(uint64_t), 1, f); + fclose(f); + +#if defined(COMPRESS) + assert(size); + + char *out = malloc(size); + assert(out); + + z_stream strm = { 0 }; + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + + deflateInit(&strm, Z_DEFAULT_COMPRESSION); + + strm.avail_in = size; + strm.avail_out = size; + strm.next_in = (Bytef *)in; + strm.next_out = (Bytef *)out; + + deflate(&strm, Z_FINISH); + + FILE *fx = fopen(path, "wb"); + assert(fx); + + fwrite(&size, sizeof(size_t), 1, fx); + fwrite(out, sizeof(char), strm.total_out, fx); + fclose(fx); + + deflateEnd(&strm); + + free(in); + free(out); +#endif +} + +void salis_auto_save() { +#if defined(NDEBUG) + snprintf( +#else + int rem = snprintf( +#endif + g_asav_pbuf, + AUTOSAVE_NAME_LEN, + "%s-%#018lx", + SIM_PATH, + g_steps + ); + + assert(rem >= 0); + assert(rem < AUTOSAVE_NAME_LEN); + + g_info("Saving simulation state on step '%#lx'", g_steps); + salis_save(g_asav_pbuf); +} +#endif + +#if defined(DATA_PUSH_PATH) +void salis_exec_sql(int blob_cnt, const void **blobs, const int *blob_sizes, const char *sql_format, ...) { + assert(sql_format); + + va_list args; + va_start(args, sql_format); + int sql_len = vsnprintf(NULL, 0, sql_format, args) + 1; + char *sql_str = malloc(sql_len); + assert(sql_str); + va_end(args); + + va_start(args, sql_format); + vsprintf(sql_str, sql_format, args); + va_end(args); + + int sql_res; + sqlite3_stmt *sql_stmt; + + sql_res = sqlite3_prepare_v2(g_sim_data, sql_str, -1, &sql_stmt, NULL); + assert(sql_res == SQLITE_OK); + free(sql_str); + + for (int i = 0; i < blob_cnt; ++i) { + assert(blobs[i]); + sql_res = sqlite3_bind_blob(sql_stmt, i + 1, blobs[i], blob_sizes[i], SQLITE_STATIC); + assert(sql_res == SQLITE_OK); + } + + // Only handle SQLITE_BUSY error, in which case we retry the query. + // Setting 'journal_mode=wal;' should help prevent busy database errors. + while (true) { + sql_res = sqlite3_step(sql_stmt); + + if (sql_res == SQLITE_DONE || sql_res == SQLITE_ROW) { + break; + } + + g_warn("SQLite database returned error '%d' with message:", sql_res); + g_warn(sqlite3_errmsg(g_sim_data)); + + if (sql_res == SQLITE_BUSY) { + g_info("Will retry query..."); + continue; + } + + assert(false); + } + + sqlite3_finalize(sql_stmt); +} +#endif + +#if defined(COMMAND_BENCH) || defined(COMMAND_NEW) +void salis_init() { + assert(g_info); + assert(g_warn); + + uint64_t seed = SEED; + + for (int i = 0; i < CORES; ++i) { + core_init(&g_cores[i], &seed); + } + +#if defined(COMMAND_NEW) + salis_auto_save(); +#endif + +#if defined(DATA_PUSH_PATH) + sqlite3_open(DATA_PUSH_PATH, &g_sim_data); + assert(g_sim_data); + + // Install busy handler to retry transactions if DB is locked + sqlite3_busy_timeout(g_sim_data, DATA_PUSH_BUSY_TIMEOUT); + + // Enable Write-Ahead Logging (WAL) + // This seems to help prevent DB locks when displaying live data. + // See: https://sqlite.org/wal.html + salis_exec_sql(0, NULL, NULL, "pragma journal_mode=wal;"); + + arch_push_data_header(); + arch_push_data_line(); +#endif +} +#endif + +#if defined(COMMAND_LOAD) +void salis_load() { +#if defined(COMPRESS) + FILE *fx = fopen(SIM_PATH, "rb"); + assert(fx); + + fseek(fx, 0, SEEK_END); + size_t x_size = ftell(fx) - sizeof(size_t); + char *in = malloc(x_size); + rewind(fx); + assert(x_size); + assert(in); + + size_t size = 0; + fread(&size, sizeof(size_t), 1, fx); + fread(in, 1, x_size, fx); + fclose(fx); + assert(size); + + char *out = malloc(size); + assert(out); + + z_stream strm = { 0 }; + strm.next_in = (Bytef *)in; + strm.avail_in = x_size; + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + + inflateInit(&strm); + + strm.avail_out = size; + strm.next_out = (Bytef *)out; + +#if defined(NDEBUG) + inflate(&strm, Z_FINISH); +#else + assert(inflate(&strm, Z_FINISH)); +#endif + + inflateEnd(&strm); + + FILE *f = fmemopen(out, size, "rb"); +#else + FILE *f = fopen(SIM_PATH, "rb"); +#endif + + assert(f); + + for (int i = 0; i < CORES; ++i) { + core_load(f, &g_cores[i]); + } + + fread(&g_steps, sizeof(uint64_t), 1, f); + fread(&g_syncs, sizeof(uint64_t), 1, f); + fclose(f); + +#if defined(COMPRESS) + free(in); + free(out); +#endif + +#if defined(DATA_PUSH_PATH) + sqlite3_open(DATA_PUSH_PATH, &g_sim_data); + assert(g_sim_data); + + // Install busy handler to retry transactions if DB is locked + sqlite3_busy_timeout(g_sim_data, DATA_PUSH_BUSY_TIMEOUT); +#endif +} +#endif + +int salis_thread(struct Core *core) { + assert(core); + + for (uint64_t i = 0; i < core->thrd_idx; ++i) { + core_step(core); + } + + return 0; +} + +void salis_run_thread(uint64_t ns) { + for (int i = 0; i < CORES; ++i) { + g_cores[i].thrd_idx = ns; + + thrd_create( + &g_cores[i].thrd, + (thrd_start_t)salis_thread, + &g_cores[i] + ); + } + + for (int i = 0; i < CORES; ++i) { + thrd_join(g_cores[i].thrd, NULL); + } + + g_steps += ns; +} + +void salis_sync() { + uint8_t *iviv0 = g_cores[0].iviv; + uint64_t *ivav0 = g_cores[0].ivav; + + for (int i = 1; i < CORES; ++i) { + g_cores[i - 1].iviv = g_cores[i].iviv; + g_cores[i - 1].ivav = g_cores[i].ivav; + } + + g_cores[CORES - 1].iviv = iviv0; + g_cores[CORES - 1].ivav = ivav0; + + for (int i = 0; i < CORES; ++i) { + g_cores[i].ivpt = 0; + } + + g_syncs++; +} + +void salis_loop(uint64_t ns, uint64_t dt) { + assert(dt); + + if (ns < dt) { + salis_run_thread(ns); + return; + } + + salis_run_thread(dt); + salis_sync(); + +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) + if (g_steps % AUTOSAVE_INTERVAL == 0) { + salis_auto_save(); + } +#endif + +#if defined(DATA_PUSH_PATH) + if (g_steps % DATA_PUSH_INTERVAL == 0) { + arch_push_data_line(); + } +#endif + + salis_loop(ns - dt, SYNC_INTERVAL); +} + +#if !defined(NDEBUG) +void salis_validate_core(const struct Core *core) { + assert(core->cycl <= g_steps); + assert(core->plst >= core->pfst); + assert(core->pnum == core->plst + 1 - core->pfst); + assert(core->pnum <= core->pcap); + assert(core->pcur >= core->pfst && core->pcur <= core->plst); + + uint64_t mall = 0; + + for (uint64_t i = 0; i < MVEC_SIZE; ++i) { + mall += mvec_is_alloc(core, i) ? 1 : 0; + } + + assert(core->mall == mall); + + for (uint64_t i = core->pfst; i <= core->plst; ++i) { + arch_validate_proc(core, i); + } + + for (uint64_t i = 0; i < SYNC_INTERVAL; ++i) { + uint8_t iinst = core->iviv[i]; + + if ((iinst & IPC_FLAG) == 0) { + uint64_t iaddr = core->ivav[i]; + + assert(iinst == 0); + assert(iaddr == 0); + } + } + + assert(core->ivpt == g_steps % SYNC_INTERVAL); +} + +void salis_validate() { + assert(g_steps / SYNC_INTERVAL == g_syncs); + + for (int i = 0; i < CORES; ++i) { + salis_validate_core(&g_cores[i]); + } +} +#endif + +void salis_step(uint64_t ns) { + assert(ns); + salis_loop(ns, SYNC_INTERVAL - (g_steps % SYNC_INTERVAL)); + +#if !defined(NDEBUG) + salis_validate(); +#endif +} + +void salis_free() { +#if defined(DATA_PUSH_PATH) + assert(g_sim_data); + sqlite3_close(g_sim_data); +#endif + + for (int i = 0; i < CORES; ++i) { + arch_core_free(&g_cores[i]); + + assert(g_cores[i].pvec); + assert(g_cores[i].iviv); + assert(g_cores[i].ivav); + + free(g_cores[i].pvec); + free(g_cores[i].iviv); + free(g_cores[i].ivav); + + g_cores[i].pvec = NULL; + g_cores[i].iviv = NULL; + g_cores[i].ivav = NULL; + } +} + +// ---------------------------------------------------------------------------- +// Architecture +// ---------------------------------------------------------------------------- +#include "arch.c" + +// ---------------------------------------------------------------------------- +// UI +// ---------------------------------------------------------------------------- +#if defined(COMMAND_LOAD) || defined(COMMAND_NEW) +#include "ui.c" +#endif + +// ---------------------------------------------------------------------------- +// Benchmark +// ---------------------------------------------------------------------------- +#if defined(COMMAND_BENCH) +void log_impl(const char *format, ...) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} + +int main() { + g_info = log_impl; + g_warn = log_impl; + + g_info("Salis Benchmark Test\n\n"); + + salis_init(); + salis_step(STEPS); + + g_info("seed => %#lx\n", SEED); + g_info("g_steps => %#lx\n", g_steps); + g_info("g_syncs => %#lx\n", g_syncs); + + for (int i = 0; i < CORES; ++i) { + g_info("\n"); + g_info("core %d mall => %#lx\n", i, g_cores[i].mall); + g_info("core %d mut0 => %#lx\n", i, g_cores[i].muta[0]); + g_info("core %d mut1 => %#lx\n", i, g_cores[i].muta[1]); + g_info("core %d mut2 => %#lx\n", i, g_cores[i].muta[2]); + g_info("core %d mut3 => %#lx\n", i, g_cores[i].muta[3]); + g_info("core %d pnum => %#lx\n", i, g_cores[i].pnum); + g_info("core %d pcap => %#lx\n", i, g_cores[i].pcap); + g_info("core %d pfst => %#lx\n", i, g_cores[i].pfst); + g_info("core %d plst => %#lx\n", i, g_cores[i].plst); + g_info("core %d pcur => %#lx\n", i, g_cores[i].pcur); + g_info("core %d psli => %#lx\n", i, g_cores[i].psli); + g_info("core %d cycl => %#lx\n", i, g_cores[i].cycl); + g_info("core %d ivpt => %#lx\n", i, g_cores[i].ivpt); + g_info("\n"); + + for (int j = 0; j < 32; ++j) { + g_info("%02x ", g_cores[i].mvec[j]); + } + + g_info("\n"); + } + + salis_free(); +} +#endif diff --git a/core.j2.c b/core.j2.c deleted file mode 100644 index a7bd9cc..0000000 --- a/core.j2.c +++ /dev/null @@ -1,935 +0,0 @@ -// Author: Paul Oliver -// Project: salis-v3 - -// Core template of the salis simulator. -// Different architectures and UIs can be attached in order to -// create a streamlined source file. - -{% for include in includes|sort %} -#include <{{ include }}> -{% endfor %} - -// Each architecture defines its own process type -struct Proc { - {% for type, val in arch_vars.proc_fields %} - {{ type }} {{ val }}; - {% endfor %} -}; - -// Simulation core -// Each core runs on a separate thread -// Core synchronization and IPC occurs at set intervals -struct Core { - uint64_t cycl; - uint64_t mall; - uint64_t muta[4]; - - uint64_t pnum; - uint64_t pcap; - uint64_t pfst; - uint64_t plst; - uint64_t pcur; - uint64_t psli; - - thrd_t thrd; - uint64_t thrd_idx; - - uint64_t ivpt; - uint64_t *ivav; - uint8_t *iviv; - - // Architecture specific custom fields - {% for type, val, _ in arch_vars.core_fields %} - {{ type }} {{ val }}; - {% endfor %} - - struct Proc *pvec; - uint8_t mvec[{{ mvec_size }}]; - uint8_t tgap[{{ thread_gap }}]; -}; - -// Globals -struct Core g_cores[{{ args.cores }}]; -uint64_t g_steps; -uint64_t g_syncs; -const struct Proc g_dead_proc; - -{% if args.command in ["load", "new"] %} -char g_asav_pbuf[{{ auto_save_name_len }}]; -{% endif %} - -{% if data_push_path is defined %} -sqlite3 *g_sim_data; -{% endif %} - -// Before invoking salis_init(), -// each UI must install its own logger functions -void (*g_info)(const char *fmt, ...); -void (*g_warn)(const char *fmt, ...); - -// Forward declarations -// Each architecture must define these -{% if args.command in ["bench", "new"] and anc_bytes is defined %} -void arch_core_init(struct Core *core); -{% endif %} - -void arch_core_free(struct Core *core); - -{% if args.command in ["load", "new"] %} -void arch_core_save(FILE *f, const struct Core *core); -{% endif %} - -{% if args.command in ["load"] %} -void arch_core_load(FILE *f, struct Core *core); -{% endif %} - -uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix); -uint64_t arch_proc_mb0_size(const struct Core *core, uint64_t pix); -uint64_t arch_proc_mb1_addr(const struct Core *core, uint64_t pix); -uint64_t arch_proc_mb1_size(const struct Core *core, uint64_t pix); -uint64_t arch_proc_ip_addr(const struct Core *core, uint64_t pix); -uint64_t arch_proc_sp_addr(const struct Core *core, uint64_t pix); -uint64_t arch_proc_slice(const struct Core *core, uint64_t pix); -void arch_on_proc_kill(struct Core *core); -void arch_proc_step(struct Core *core, uint64_t pix); - -{% if not args.optimized %} -void arch_validate_proc(const struct Core *core, uint64_t pix); -{% endif %} - -wchar_t arch_symbol(uint8_t inst); -const char *arch_mnemonic(uint8_t inst); - -{% if data_push_path is defined %} -void arch_push_data_header(); -void arch_push_data_line(); -{% endif %} - -// ---------------------------------------------------------------------------- -// Memory vector functions -// ---------------------------------------------------------------------------- -{% if arch_vars.mvec_loop %} -uint64_t mvec_loop(uint64_t addr) { - return addr % {{ mvec_size }}; -} -{% endif %} - -bool mvec_is_alloc(const struct Core *core, uint64_t addr) { - assert(core); - - {% if arch_vars.mvec_loop %} - return core->mvec[mvec_loop(addr)] & {{ mall_flag }} ? true : false; - {% else %} - if (addr < {{ mvec_size }}) { - return core->mvec[addr] & {{ mall_flag }} ? true : false; - } else { - return true; - } - {% endif %} -} - -void mvec_alloc(struct Core *core, uint64_t addr) { - assert(core); - assert(!mvec_is_alloc(core, addr)); - {% if arch_vars.mvec_loop %} - core->mvec[mvec_loop(addr)] |= {{ mall_flag }}; - {% else %} - assert(addr < {{ mvec_size }}); - core->mvec[addr] |= {{ mall_flag }}; - {% endif %} - core->mall++; -} - -void mvec_free(struct Core *core, uint64_t addr) { - assert(core); - assert(mvec_is_alloc(core, addr)); - {% if arch_vars.mvec_loop %} - core->mvec[mvec_loop(addr)] ^= {{ mall_flag }}; - {% else %} - assert(addr < {{ mvec_size }}); - core->mvec[addr] ^= {{ mall_flag }}; - {% endif %} - core->mall--; -} - -uint8_t mvec_get_byte(const struct Core *core, uint64_t addr) { - assert(core); - {% if arch_vars.mvec_loop %} - return core->mvec[mvec_loop(addr)]; - {% else %} - if (addr < {{ mvec_size }}) { - return core->mvec[addr]; - } else { - return 0; - } - {% endif %} -} - -uint8_t mvec_get_inst(const struct Core *core, uint64_t addr) { - assert(core); - {% if arch_vars.mvec_loop %} - return core->mvec[mvec_loop(addr)] & {{ inst_mask }}; - {% else %} - if (addr < {{ mvec_size }}) { - return core->mvec[addr] & {{ inst_mask }}; - } else { - return 0; - } - {% endif %} -} - -void mvec_set_inst(struct Core *core, uint64_t addr, uint8_t inst) { - assert(core); - assert(inst < {{ inst_cap}}); - {% if arch_vars.mvec_loop %} - core->mvec[mvec_loop(addr)] &= {{ mall_flag }}; - core->mvec[mvec_loop(addr)] |= inst; - {% else %} - assert(addr < {{ mvec_size }}); - core->mvec[addr] &= {{ mall_flag }}; - core->mvec[addr] |= inst; - {% endif %} -} - -{% if args.muta_flip %} -void mvec_flip_bit(struct Core *core, uint64_t addr, int bit) { - assert(core); - assert(bit < 8); - core->mvec[addr] ^= (1 << bit) & {{ inst_mask }}; -} -{% endif %} - -bool mvec_proc_is_live(const struct Core *core, uint64_t pix) { - assert(core); - - return pix >= core->pfst && pix <= core->plst; -} - -bool mvec_is_in_mb0_of_proc(const struct Core *core, uint64_t addr, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - uint64_t mb0a = arch_proc_mb0_addr(core, pix); - uint64_t mb0s = arch_proc_mb0_size(core, pix); - - return ((addr - mb0a) % {{ mvec_size }}) < mb0s; -} - -bool mvec_is_in_mb1_of_proc(const struct Core *core, uint64_t addr, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - uint64_t mb1a = arch_proc_mb1_addr(core, pix); - uint64_t mb1s = arch_proc_mb1_size(core, pix); - - return ((addr - mb1a) % {{ mvec_size }}) < mb1s; -} - -bool mvec_is_proc_owner(const struct Core *core, uint64_t addr, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - return mvec_is_in_mb0_of_proc(core, addr, pix) || mvec_is_in_mb1_of_proc(core, addr, pix); -} - -uint64_t mvec_get_owner(const struct Core *core, uint64_t addr) { - assert(core); - assert(mvec_is_alloc(core, addr)); - - for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) { - if (mvec_is_proc_owner(core, addr, pix)) { - return pix; - } - } - - assert(false); - return -1; -} - -// ---------------------------------------------------------------------------- -// Mutator functions -// ---------------------------------------------------------------------------- -{% if args.command in ["bench", "new"] %} -uint64_t muta_smix(uint64_t *seed) { - assert(seed); - - uint64_t next = (*seed += 0x9e3779b97f4a7c15); - next = (next ^ (next >> 30)) * 0xbf58476d1ce4e5b9; - next = (next ^ (next >> 27)) * 0x94d049bb133111eb; - - return next ^ (next >> 31); -} -{% endif %} - -uint64_t muta_ro64(uint64_t x, int k) { - return (x << k) | (x >> (64 - k)); -} - -uint64_t muta_next(struct Core *core) { - assert(core); - - uint64_t r = muta_ro64(core->muta[1] * 5, 7) * 9; - uint64_t t = core->muta[1] << 17; - - core->muta[2] ^= core->muta[0]; - core->muta[3] ^= core->muta[1]; - core->muta[1] ^= core->muta[2]; - core->muta[0] ^= core->muta[3]; - - core->muta[2] ^= t; - core->muta[3] = muta_ro64(core->muta[3], 45); - - return r; -} - -void muta_cosmic_ray(struct Core *core) { - assert(core); - - uint64_t a = muta_next(core) % {{ muta_range }}; - uint64_t b = muta_next(core); - - if (a < {{ mvec_size }}) { - {% if args.muta_flip %} - mvec_flip_bit(core, a, (int)(b % 8)); - {% else %} - mvec_set_inst(core, a, b & {{ inst_mask }}); - {% endif %} - } -} - -// ---------------------------------------------------------------------------- -// Process functions -// ---------------------------------------------------------------------------- -void proc_new(struct Core *core, const struct Proc *proc) { - assert(core); - assert(proc); - - if (core->pnum == core->pcap) { - // Reallocate dynamic array - uint64_t new_pcap = core->pcap * 2; - struct Proc *new_pvec = calloc(new_pcap, sizeof(struct Proc)); - - for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) { - uint64_t iold = pix % core->pcap; - uint64_t inew = pix % new_pcap; - memcpy(&new_pvec[inew], &core->pvec[iold], sizeof(struct Proc)); - } - - free(core->pvec); - core->pcap = new_pcap; - core->pvec = new_pvec; - } - - core->pnum++; - core->plst++; - memcpy(&core->pvec[core->plst % core->pcap], proc, sizeof(struct Proc)); -} - -void proc_kill(struct Core *core) { - assert(core); - assert(core->pnum > 1); - - arch_on_proc_kill(core); - - core->pcur++; - core->pfst++; - core->pnum--; -} - -const struct Proc *proc_get(const struct Core *core, uint64_t pix) { - assert(core); - - if (mvec_proc_is_live(core, pix)) { - return &core->pvec[pix % core->pcap]; - } else { - return &g_dead_proc; - } -} - -struct Proc *proc_fetch(struct Core *core, uint64_t pix) { - assert(core); - assert(mvec_proc_is_live(core, pix)); - - return &core->pvec[pix % core->pcap]; -} - -// ---------------------------------------------------------------------------- -// Core functions -// ---------------------------------------------------------------------------- -{% if args.command in ["load", "new"] %} -void core_save(FILE *f, const struct Core *core) { - assert(f); - assert(core); - - fwrite(&core->cycl, sizeof(uint64_t), 1, f); - fwrite(&core->mall, sizeof(uint64_t), 1, f); - fwrite( core->muta, sizeof(uint64_t), 4, f); - fwrite(&core->pnum, sizeof(uint64_t), 1, f); - fwrite(&core->pcap, sizeof(uint64_t), 1, f); - fwrite(&core->pfst, sizeof(uint64_t), 1, f); - fwrite(&core->plst, sizeof(uint64_t), 1, f); - fwrite(&core->pcur, sizeof(uint64_t), 1, f); - fwrite(&core->psli, sizeof(uint64_t), 1, f); - fwrite(&core->ivpt, sizeof(uint64_t), 1, f); - - fwrite(core->iviv, sizeof(uint8_t), {{ sync_interval }}, f); - fwrite(core->ivav, sizeof(uint64_t), {{ sync_interval }}, f); - fwrite(core->pvec, sizeof(struct Proc), core->pcap, f); - fwrite(core->mvec, sizeof(uint8_t), {{ mvec_size }}, f); - - arch_core_save(f, core); -} -{% endif %} - -{% if args.command in ["bench", "new"] %} -{% if anc_bytes is defined %} -void core_assemble_ancestor(struct Core *core) { - assert(core); - - {% if arch_vars.mvec_loop %} - uint64_t addr = {{ uint64_half }}; - {% else %} - uint64_t addr = 0; - {% endif %} - - uint8_t anc_bytes[] = { - {{ anc_bytes|join(",") }} - }; - - for (uint64_t i = 0; i < sizeof(anc_bytes); ++i, ++addr) { - for (uint64_t j = 0; j < {{ args.clones }}; ++j) { - uint64_t addr_clone = addr + (({{ mvec_size }} / {{ args.clones }})) * j; - - mvec_alloc(core, addr_clone); - mvec_set_inst(core, addr_clone, anc_bytes[i]); - } - } -} -{% endif %} - -void core_init(struct Core *core, uint64_t *seed) { - assert(core); - assert(seed); - - if (*seed) { - core->muta[0] = muta_smix(seed); - core->muta[1] = muta_smix(seed); - core->muta[2] = muta_smix(seed); - core->muta[3] = muta_smix(seed); - } - - core->pnum = {{ args.clones }}; - core->pcap = {{ args.clones }}; - core->plst = {{ args.clones }} - 1; - core->iviv = calloc({{ sync_interval }}, sizeof(uint8_t)); - core->ivav = calloc({{ sync_interval }}, sizeof(uint64_t)); - core->pvec = calloc(core->pcap, sizeof(struct Proc)); - - assert(core->iviv); - assert(core->ivav); - assert(core->pvec); - - {% if anc_bytes is defined %} - core_assemble_ancestor(core); - arch_core_init(core); - {% endif %} -} -{% endif %} - -{% if args.command in ["load"] %} -void core_load(FILE *f, struct Core *core) { - assert(f); - assert(core); - - fread(&core->cycl, sizeof(uint64_t), 1, f); - fread(&core->mall, sizeof(uint64_t), 1, f); - fread( core->muta, sizeof(uint64_t), 4, f); - fread(&core->pnum, sizeof(uint64_t), 1, f); - fread(&core->pcap, sizeof(uint64_t), 1, f); - fread(&core->pfst, sizeof(uint64_t), 1, f); - fread(&core->plst, sizeof(uint64_t), 1, f); - fread(&core->pcur, sizeof(uint64_t), 1, f); - fread(&core->psli, sizeof(uint64_t), 1, f); - fread(&core->ivpt, sizeof(uint64_t), 1, f); - - core->iviv = calloc({{ sync_interval }}, sizeof(uint8_t)); - core->ivav = calloc({{ sync_interval }}, sizeof(uint64_t)); - core->pvec = calloc(core->pcap, sizeof(struct Proc)); - - assert(core->iviv); - assert(core->ivav); - assert(core->pvec); - - fread(core->iviv, sizeof(uint8_t), {{ sync_interval }}, f); - fread(core->ivav, sizeof(uint64_t), {{ sync_interval }}, f); - fread(core->pvec, sizeof(struct Proc), core->pcap, f); - fread(core->mvec, sizeof(uint8_t), {{ mvec_size }}, f); - - arch_core_load(f, core); -} -{% endif %} - -void core_pull_ipcm(struct Core *core) { - assert(core); - assert(core->ivpt < {{ sync_interval }}); - - uint8_t *iinst = &core->iviv[core->ivpt]; - uint64_t *iaddr = &core->ivav[core->ivpt]; - - if ((*iinst & {{ ipc_flag }}) != 0) { - mvec_set_inst(core, *iaddr, *iinst & {{ inst_mask }}); - - *iinst = 0; - *iaddr = 0; - } - - assert(*iinst == 0); - assert(*iaddr == 0); -} - -void core_push_ipcm(struct Core *core, uint8_t inst, uint64_t addr) { - assert(core); - assert(core->ivpt < {{ sync_interval }}); - assert((inst & {{ ipc_flag }}) == 0); - - uint8_t *iinst = &core->iviv[core->ivpt]; - uint64_t *iaddr = &core->ivav[core->ivpt]; - - assert(*iinst == 0); - assert(*iaddr == 0); - - *iinst = inst | {{ ipc_flag }}; - *iaddr = addr; -} - -void core_step(struct Core *core) { - assert(core); - - if (core->psli != 0) { - core_pull_ipcm(core); - arch_proc_step(core, core->pcur); - - core->psli--; - core->ivpt++; - - return; - } - - if (core->pcur != core->plst) { - core->psli = arch_proc_slice(core, ++core->pcur); - core_step(core); - return; - } - - core->pcur = core->pfst; - core->psli = arch_proc_slice(core, core->pcur); - core->cycl++; - - // TODO: Implement day-night cycle - while (core->mall > {{ mvec_size }} / 2 && core->pnum > 1) { - proc_kill(core); - } - - muta_cosmic_ray(core); - core_step(core); -} - -// ---------------------------------------------------------------------------- -// Main salis functions -// ---------------------------------------------------------------------------- -{% if args.command in ["load", "new"] %} -void salis_save(const char *path) { - {% if args.compress %} - size_t size = 0; - char *in = NULL; - FILE *f = open_memstream(&in, &size); - {% else %} - FILE *f = fopen(path, "wb"); - {% endif %} - - assert(f); - - for (int i = 0; i < {{ args.cores }}; ++i) { - core_save(f, &g_cores[i]); - } - - fwrite(&g_steps, sizeof(uint64_t), 1, f); - fwrite(&g_syncs, sizeof(uint64_t), 1, f); - fclose(f); - - {% if args.compress %} - assert(size); - - char *out = malloc(size); - assert(out); - - z_stream strm = { 0 }; - strm.zalloc = NULL, - strm.zfree = NULL, - strm.opaque = NULL, - - deflateInit(&strm, Z_DEFAULT_COMPRESSION); - - strm.avail_in = size; - strm.avail_out = size; - strm.next_in = (Bytef *)in; - strm.next_out = (Bytef *)out; - - deflate(&strm, Z_FINISH); - - FILE *fx = fopen(path, "wb"); - assert(fx); - - fwrite(&size, sizeof(size_t), 1, fx); - fwrite(out, sizeof(char), strm.total_out, fx); - fclose(fx); - - deflateEnd(&strm); - - free(in); - free(out); - {% endif %} -} - -void salis_auto_save() { - {% if not args.optimized %} - int rem = snprintf( - {% else %} - snprintf( - {% endif %} - g_asav_pbuf, - {{ auto_save_name_len }}, - "%s-%#018lx", - "{{ sim_path }}", - g_steps - ); - - assert(rem >= 0); - assert(rem < {{ auto_save_name_len }}); - - g_info("Saving simulation state on step '%#lx'", g_steps); - salis_save(g_asav_pbuf); -} -{% endif %} - -{% if data_push_path is defined %} -void salis_exec_sql(int blob_cnt, const void **blobs, const int *blob_sizes, const char *sql_format, ...) { - assert(sql_format); - - va_list args; - va_start(args, sql_format); - int sql_len = vsnprintf(NULL, 0, sql_format, args) + 1; - char *sql_str = malloc(sql_len); - assert(sql_str); - va_end(args); - - va_start(args, sql_format); - vsprintf(sql_str, sql_format, args); - va_end(args); - - // Prepare statement - int sql_res; - sqlite3_stmt *sql_stmt; - - sql_res = sqlite3_prepare_v2(g_sim_data, sql_str, -1, &sql_stmt, NULL); - assert(sql_res == SQLITE_OK); - free(sql_str); - - // Caller may pass multiple binary blobs to the query - for (int i = 0; i < blob_cnt; ++i) { - assert(blobs[i]); - sql_res = sqlite3_bind_blob(sql_stmt, i + 1, blobs[i], blob_sizes[i], SQLITE_STATIC); - assert(sql_res == SQLITE_OK); - } - - // Execute the statement - // Only handle SQLITE_BUSY error, in which case we retry the query. - // In principle, setting 'journal_mode=wal;' should help prevent busy database errors. - while (true) { - sql_res = sqlite3_step(sql_stmt); - - if (sql_res == SQLITE_DONE || sql_res == SQLITE_ROW) { - break; - } - - g_warn("SQLite database returned error '%d' with message:", sql_res); - g_warn(sqlite3_errmsg(g_sim_data)); - - if (sql_res == SQLITE_BUSY) { - g_info("Will retry query..."); - continue; - } - - // Fail on unhandled error - assert(false); - } - - sqlite3_finalize(sql_stmt); -} -{% endif %} - -{% if args.command in ["bench", "new"] %} -void salis_init() { - assert(g_info); - assert(g_warn); - - uint64_t seed = {{ args.seed }}; - - for (int i = 0; i < {{ args.cores }}; ++i) { - core_init(&g_cores[i], &seed); - } - - {% if args.command in ["new"] %} - salis_auto_save(); - {% endif %} - - {% if data_push_path is defined %} - sqlite3_open("{{ data_push_path }}", &g_sim_data); - assert(g_sim_data); - - // Install busy handler to retry transactions if DB is locked - sqlite3_busy_timeout(g_sim_data, {{ data_push_busy_timeout }}); - - // Enable Write-Ahead Logging (WAL) - // This seems to help prevent DB locks when displaying live data - // See: https://sqlite.org/wal.html - salis_exec_sql(0, NULL, NULL, "pragma journal_mode=wal;"); - - arch_push_data_header(); - arch_push_data_line(); - {% endif %} -} -{% endif %} - -{% if args.command in ["load"] %} -void salis_load() { - {% if args.compress %} - FILE *fx = fopen("{{ sim_path }}", "rb"); - assert(fx); - - fseek(fx, 0, SEEK_END); - size_t x_size = ftell(fx) - sizeof(size_t); - char *in = malloc(x_size); - rewind(fx); - assert(x_size); - assert(in); - - size_t size = 0; - fread(&size, sizeof(size_t), 1, fx); - fread(in, 1, x_size, fx); - fclose(fx); - assert(size); - - char *out = malloc(size); - assert(out); - - z_stream strm = { 0 }; - strm.next_in = (Bytef *)in; - strm.avail_in = x_size; - strm.zalloc = NULL; - strm.zfree = NULL; - strm.opaque = NULL; - - inflateInit(&strm); - - strm.avail_out = size; - strm.next_out = (Bytef *)out; - - {% if not args.optimized %} - assert(inflate(&strm, Z_FINISH)); - {% else %} - inflate(&strm, Z_FINISH); - {% endif %} - - inflateEnd(&strm); - - FILE *f = fmemopen(out, size, "rb"); - {% else %} - FILE *f = fopen("{{ sim_path }}", "rb"); - {% endif %} - - assert(f); - - for (int i = 0; i < {{ args.cores }}; ++i) { - core_load(f, &g_cores[i]); - } - - fread(&g_steps, sizeof(uint64_t), 1, f); - fread(&g_syncs, sizeof(uint64_t), 1, f); - fclose(f); - - {% if args.compress %} - free(in); - free(out); - {% endif %} - - {% if data_push_path is defined %} - sqlite3_open("{{ data_push_path }}", &g_sim_data); - assert(g_sim_data); - - // Install busy handler to retry transactions if DB is locked - sqlite3_busy_timeout(g_sim_data, {{ data_push_busy_timeout }}); - {% endif %} -} -{% endif %} - -int salis_thread(struct Core *core) { - assert(core); - - for (uint64_t i = 0; i < core->thrd_idx; ++i) { - core_step(core); - } - - return 0; -} - -void salis_run_thread(uint64_t ns) { - for (int i = 0; i < {{ args.cores }}; ++i) { - g_cores[i].thrd_idx = ns; - - thrd_create( - &g_cores[i].thrd, - (thrd_start_t)salis_thread, - &g_cores[i] - ); - } - - for (int i = 0; i < {{ args.cores }}; ++i) { - thrd_join(g_cores[i].thrd, NULL); - } - - g_steps += ns; -} - -void salis_sync() { - uint8_t *iviv0 = g_cores[0].iviv; - uint64_t *ivav0 = g_cores[0].ivav; - - for (int i = 1; i < {{ args.cores }}; ++i) { - g_cores[i - 1].iviv = g_cores[i].iviv; - g_cores[i - 1].ivav = g_cores[i].ivav; - } - - g_cores[{{ args.cores }} - 1].iviv = iviv0; - g_cores[{{ args.cores }} - 1].ivav = ivav0; - - for (int i = 0; i < {{ args.cores }}; ++i) { - g_cores[i].ivpt = 0; - } - - g_syncs++; -} - -void salis_loop(uint64_t ns, uint64_t dt) { - assert(dt); - - if (ns < dt) { - salis_run_thread(ns); - return; - } - - salis_run_thread(dt); - salis_sync(); - - {% if args.command in ["load", "new"] %} - if (g_steps % {{ auto_save_interval }} == 0) { - salis_auto_save(); - } - {% endif %} - - {% if data_push_path is defined %} - if (g_steps % {{ data_push_interval }} == 0) { - arch_push_data_line(); - } - {% endif %} - - salis_loop(ns - dt, {{ sync_interval }}); -} - -{% if not args.optimized %} -void salis_validate_core(const struct Core *core) { - assert(core->cycl <= g_steps); - assert(core->plst >= core->pfst); - assert(core->pnum == core->plst + 1 - core->pfst); - assert(core->pnum <= core->pcap); - assert(core->pcur >= core->pfst && core->pcur <= core->plst); - - uint64_t mall = 0; - - for (uint64_t i = 0; i < {{ mvec_size }}; ++i) { - mall += mvec_is_alloc(core, i) ? 1 : 0; - } - - assert(core->mall == mall); - - for (uint64_t i = core->pfst; i <= core->plst; ++i) { - arch_validate_proc(core, i); - } - - for (uint64_t i = 0; i < {{ sync_interval }}; ++i) { - uint8_t iinst = core->iviv[i]; - - if ((iinst & {{ ipc_flag }}) == 0) { - uint64_t iaddr = core->ivav[i]; - - assert(iinst == 0); - assert(iaddr == 0); - } - } - - assert(core->ivpt == g_steps % {{ sync_interval }}); -} - -void salis_validate() { - assert(g_steps / {{ sync_interval }} == g_syncs); - - for (int i = 0; i < {{ args.cores }}; ++i) { - salis_validate_core(&g_cores[i]); - } -} -{% endif %} - -void salis_step(uint64_t ns) { - assert(ns); - salis_loop(ns, {{ sync_interval }} - (g_steps % {{ sync_interval }})); - - {% if not args.optimized %} - salis_validate(); - {% endif %} -} - -void salis_free() { - {% if data_push_path is defined %} - assert(g_sim_data); - sqlite3_close(g_sim_data); - {% endif %} - - for (int i = 0; i < {{ args.cores }}; ++i) { - arch_core_free(&g_cores[i]); - - assert(g_cores[i].pvec); - assert(g_cores[i].iviv); - assert(g_cores[i].ivav); - - free(g_cores[i].pvec); - free(g_cores[i].iviv); - free(g_cores[i].ivav); - - g_cores[i].pvec = NULL; - g_cores[i].iviv = NULL; - g_cores[i].ivav = NULL; - } -} - -// ---------------------------------------------------------------------------- -// Architecture -// ---------------------------------------------------------------------------- -{% include "arch/" ~ args.arch ~ "/arch.j2.c" %} - -// ---------------------------------------------------------------------------- -// UI -// ---------------------------------------------------------------------------- -{% if args.command in ["load", "new"] %} - {% include "ui/" ~ args.ui ~ "/ui.j2.c" %} -{% else %} - {% include "bench.j2.c" %} -{% endif %} diff --git a/data/salis-v1/trend.yaml b/data/salis-v1/trend.yaml deleted file mode 100644 index f6f63fb..0000000 --- a/data/salis-v1/trend.yaml +++ /dev/null @@ -1,3915 +0,0 @@ -# Author: Paul Oliver -# Project: Salis - -# Grafana dashboard configuration for showing trend data in simulations -# using salis-v1 architecture. It assumes 4 simulation cores but can be -# easily extended to more cores. - -apiVersion: dashboard.grafana.app/v2beta1 -kind: Dashboard -metadata: - name: adv6npj - generation: 208 - creationTimestamp: '2025-11-19T16:11:53Z' - labels: {} - annotations: {} -spec: - annotations: - - kind: AnnotationQuery - spec: - builtIn: true - enable: true - hide: true - iconColor: rgba(0, 211, 255, 1) - name: Annotations & Alerts - query: - group: grafana - kind: DataQuery - spec: {} - version: v0 - cursorSync: 'Off' - editable: true - elements: - panel-1: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, pnum_0, pnum_1, pnum_2, pnum_3 from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, pnum_0, pnum_1, pnum_2, pnum_3 from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: [] - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 1 - links: [] - title: PNUM - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: left - barAlignment: 0 - barWidthFactor: 0.6 - drawStyle: line - fillOpacity: 0 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineStyle: - fill: solid - lineWidth: 1 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: none - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: [] - options: - legend: - calcs: [] - displayMode: list - placement: bottom - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-10: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_2 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_2 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 10 - links: [] - title: INST POP 2 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: normal - thresholdsStyle: - mode: 'off' - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - - id: custom.axisSoftMax - value: 4194304 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-11: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_3 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_3 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 11 - links: [] - title: INST POP 3 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: normal - thresholdsStyle: - mode: 'off' - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(step|rowid|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - - id: custom.axisSoftMax - value: 4194304 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-13: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select rowid, - emb0_0, - emb1_0, - eliv_0, - edea_0, - emb0_1, - emb1_1, - eliv_1, - edea_1, - emb0_2, - emb1_2, - eliv_2, - edea_2, - emb0_3, - emb1_3, - eliv_3, - edea_3 - from trend - where rowid % 1 = 0 - ) order by rowid desc limit 2000 - ) where rowid between 0 and power(2, 64) order by rowid - asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - emb0_0, - emb1_0, - eliv_0, - edea_0, - emb0_1, - emb1_1, - eliv_1, - edea_1, - emb0_2, - emb1_2, - eliv_2, - edea_2, - emb0_3, - emb1_3, - eliv_3, - edea_3 - from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 13 - links: [] - title: EXEC OWN - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.6 - drawStyle: line - fillOpacity: 0 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 1 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: none - thresholdsStyle: - mode: 'off' - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /e.*_0/ - properties: - - id: color - value: - fixedColor: green - mode: shades - - matcher: - id: byRegexp - options: /e.*_1/ - properties: - - id: color - value: - fixedColor: yellow - mode: shades - - matcher: - id: byRegexp - options: /e.*_2/ - properties: - - id: color - value: - fixedColor: blue - mode: shades - - matcher: - id: byRegexp - options: /e.*_3/ - properties: - - id: color - value: - fixedColor: red - mode: shades - options: - legend: - calcs: [] - displayMode: list - placement: bottom - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-14: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - wmb0_0, - wmb1_0, - wdea_0, - wmb0_1, - wmb1_1, - wdea_1, - wmb0_2, - wmb1_2, - wdea_2, - wmb0_3, - wmb1_3, - wdea_3 - from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - wmb0_0, - wmb1_0, - wdea_0, - wmb0_1, - wmb1_1, - wdea_1, - wmb0_2, - wmb1_2, - wdea_2, - wmb0_3, - wmb1_3, - wdea_3 - from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 14 - links: [] - title: WRITE OWN - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.6 - drawStyle: line - fillOpacity: 0 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 1 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: none - thresholdsStyle: - mode: 'off' - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /w.*_0/ - properties: - - id: color - value: - fixedColor: green - mode: shades - - matcher: - id: byRegexp - options: /w.*_1/ - properties: - - id: color - value: - fixedColor: yellow - mode: shades - - matcher: - id: byRegexp - options: /w.*_2/ - properties: - - id: color - value: - fixedColor: blue - mode: shades - - matcher: - id: byRegexp - options: /w.*_3/ - properties: - - id: color - value: - fixedColor: red - mode: shades - options: - legend: - calcs: [] - displayMode: list - placement: bottom - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-15: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_0 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_0 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 15 - links: [] - title: INST EXEC % 0 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-16: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_1 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_1 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 16 - links: [] - title: INST EXEC % 1 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-17: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_2 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_2 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 17 - links: [] - title: INST EXEC % 2 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-18: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_3 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from exe_3 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 18 - links: [] - title: INST EXEC % 3 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-19: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_0 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_0 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 19 - links: [] - title: INST WRITE % 0 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-2: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, mall_0, mall_1, mall_2, mall_3 from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, mall_0, mall_1, mall_2, mall_3 from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 2 - links: [] - title: MALL - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.6 - drawStyle: line - fillOpacity: 0 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 1 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: none - thresholdsStyle: - mode: 'off' - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: [] - options: - legend: - calcs: [] - displayMode: list - placement: bottom - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-20: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_1 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_1 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 20 - links: [] - title: INST WRITE % 1 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-21: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_2 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_2 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 21 - links: [] - title: INST WRITE % 2 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-22: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_3 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from wrt_3 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 22 - links: [] - title: INST WRITE % 3 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: percent - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-3: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select rowid, cycl_0, cycl_1, cycl_2, cycl_3 from trend - where rowid % 1 = 0 - ) order by rowid desc limit 2000 - ) where rowid between 0 and power(2, 64) order by rowid - asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, cycl_0, cycl_1, cycl_2, cycl_3 from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 3 - links: [] - title: CYCL - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.6 - drawStyle: line - fillOpacity: 0 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 1 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: none - thresholdsStyle: - mode: 'off' - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: [] - options: - legend: - calcs: [] - displayMode: list - placement: bottom - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-4: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select rowid, plst_0, pfst_0, plst_1, pfst_1, plst_2, pfst_2, plst_3, pfst_3 from trend - where rowid % 1 = 0 - ) order by rowid desc limit 2000 - ) where rowid between 0 and power(2, 64) order by rowid - asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, plst_0, pfst_0, plst_1, pfst_1, plst_2, pfst_2, plst_3, pfst_3 from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 4 - links: [] - title: PPOP - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.6 - drawStyle: line - fillOpacity: 0 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 1 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: none - thresholdsStyle: - mode: 'off' - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byName - options: plst_0 - properties: - - id: custom.fillBelowTo - value: pfst_0 - - matcher: - id: byName - options: plst_1 - properties: - - id: custom.fillBelowTo - value: pfst_1 - - matcher: - id: byName - options: plst_2 - properties: - - id: custom.fillBelowTo - value: pfst_2 - - matcher: - id: byName - options: plst_3 - properties: - - id: custom.fillBelowTo - value: pfst_3 - - matcher: - id: byRegexp - options: /p.st_0/ - properties: - - id: color - value: - fixedColor: green - mode: shades - seriesBy: last - - matcher: - id: byRegexp - options: /p.st_1/ - properties: - - id: color - value: - fixedColor: yellow - mode: shades - - matcher: - id: byRegexp - options: /p.st_2/ - properties: - - id: color - value: - fixedColor: blue - mode: shades - - matcher: - id: byRegexp - options: /p.st_3/ - properties: - - id: color - value: - fixedColor: red - mode: shades - options: - legend: - calcs: [] - displayMode: list - placement: bottom - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-5: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select rowid, - amb0_0, - amb1_0, - amb0_1, - amb1_1, - amb0_2, - amb1_2, - amb0_3, - amb1_3 - from trend - where rowid % 1 = 0 - ) order by rowid desc limit 2000 - ) where rowid between 0 and power(2, 64) order by rowid - asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - amb0_0, - amb1_0, - amb0_1, - amb1_1, - amb0_2, - amb1_2, - amb0_3, - amb1_3 - from trend - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 5 - links: [] - title: AVRG MBS - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.6 - drawStyle: line - fillOpacity: 0 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 1 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: none - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /amb._0/ - properties: - - id: color - value: - fixedColor: green - mode: shades - - matcher: - id: byRegexp - options: /amb._1/ - properties: - - id: color - value: - fixedColor: yellow - mode: shades - - matcher: - id: byRegexp - options: /amb._2/ - properties: - - id: color - value: - fixedColor: blue - mode: shades - - matcher: - id: byRegexp - options: /amb._3/ - properties: - - id: color - value: - fixedColor: red - mode: shades - options: - legend: - calcs: [] - displayMode: list - placement: bottom - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-8: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_0 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_0 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 8 - links: [] - title: INST POP 0 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: normal - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - - id: custom.axisSoftMax - value: 4194304 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - panel-9: - kind: Panel - spec: - data: - kind: QueryGroup - spec: - queries: - - kind: PanelQuery - spec: - hidden: false - query: - group: frser-sqlite-datasource - kind: DataQuery - spec: - queryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_1 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - queryType: table - rawQueryText: >- - select * from ( - select * from ( - select $X_AXIS, - noop, - nop0, - nop1, - nop2, - nop3, - jmpb, - jmpf, - adrb, - adrf, - ifnz, - allb, - allf, - bswp, - bclr, - splt, - addn, - subn, - muln, - divn, - incn, - decn, - notn, - shfl, - shfr, - zero, - unit, - pshn, - popn, - load, - wrte, - dupl, - swap, - keya, - keyb, - keyc, - keyd, - keye, - keyf, - keyg, - keyh, - keyi, - keyj, - keyk, - keyl, - keym, - keyn, - keyo, - keyp, - loka, - lokb, - lokc, - lokd, - loke, - lokf, - lokg, - lokh, - loki, - lokj, - lokk, - lokl, - lokm, - lokn, - loko, - lokp - from pop_1 - where rowid % $NTH = 0 - ) order by $X_AXIS desc limit $ENTRIES - ) where $X_AXIS between $X_LOW and $X_HIGH order by - $X_AXIS asc; - timeColumns: - - time - - ts - version: v0 - refId: A - queryOptions: {} - transformations: [] - description: '' - id: 9 - links: [] - title: INST POP 1 - transparent: true - vizConfig: - group: trend - kind: VizConfig - spec: - fieldConfig: - defaults: - color: - mode: palette-classic - custom: - axisBorderShow: false - axisCenteredZero: false - axisColorMode: text - axisLabel: '' - axisPlacement: auto - barAlignment: 0 - barWidthFactor: 0.9 - drawStyle: line - fillOpacity: 70 - gradientMode: none - hideFrom: - legend: false - tooltip: false - viz: false - insertNulls: false - lineInterpolation: linear - lineWidth: 0 - pointSize: 5 - scaleDistribution: - type: linear - showPoints: never - showValues: false - spanNulls: false - stacking: - group: A - mode: normal - thresholdsStyle: - mode: 'off' - fieldMinMax: false - thresholds: - mode: absolute - steps: - - color: green - value: 0 - - color: red - value: 80 - unit: short - overrides: - - matcher: - id: byRegexp - options: /^(?!.*(rowid|step|cycl_))/ - properties: - - id: custom.axisSoftMin - value: 0 - - id: custom.axisSoftMax - value: 4194304 - options: - legend: - calcs: [] - displayMode: table - placement: right - showLegend: true - tooltip: - hideZeros: false - mode: single - sort: none - version: 12.2.1 - layout: - kind: GridLayout - spec: - items: [] - links: [] - liveNow: false - preload: false - tags: [] - timeSettings: - autoRefresh: 5s - autoRefreshIntervals: - - 5s - - 10s - - 30s - - 1m - - 5m - - 15m - - 30m - - 1h - - 2h - - 1d - fiscalYearStartMonth: 0 - from: now-6h - hideTimepicker: false - timezone: browser - to: now - title: Salis def.sim - TREND - variables: - - kind: TextVariable - spec: - current: - text: '2000' - value: '2000' - hide: dontHide - label: ENTRIES (MAX) - name: ENTRIES - query: '2000' - skipUrlSync: false - - kind: CustomVariable - spec: - allowCustomValue: false - current: - text: rowid - value: rowid - hide: dontHide - includeAll: false - label: X-AXIS - multi: false - name: X_AXIS - options: - - selected: true - text: rowid - value: rowid - - selected: false - text: step - value: step - - selected: false - text: cycl_0 - value: cycl_0 - - selected: false - text: cycl_1 - value: cycl_1 - - selected: false - text: cycl_2 - value: cycl_2 - - selected: false - text: cycl_3 - value: cycl_3 - query: rowid, step, cycl_0, cycl_1, cycl_2, cycl_3 - skipUrlSync: false - - kind: TextVariable - spec: - current: - text: '0' - value: '0' - hide: dontHide - label: X-LOW - name: X_LOW - query: '0' - skipUrlSync: false - - kind: TextVariable - spec: - current: - text: power(2, 64) - value: power(2, 64) - hide: dontHide - label: X-HIGH - name: X_HIGH - query: power(2, 64) - skipUrlSync: false - - kind: TextVariable - spec: - current: - text: '1' - value: '1' - hide: dontHide - name: NTH - query: '1' - skipUrlSync: false -status: {} diff --git a/salis.py b/salis.py index 5f81f2c..a44b180 100755 --- a/salis.py +++ b/salis.py @@ -1,11 +1,4 @@ -#!/usr/bin/env -S PYTHONDONTWRITEBYTECODE=1 python3 - -# Author: Paul Oliver -# Project: salis-v3 - -# Salis simulator launcher script -# Emits a single C source file, builds it into a binary and launches it. -# JIT compilation allows quick switching between all available executable configurations. +#!/usr/bin/env -S PYTHONDONTWRITEBYTECODE=1 python import os import random @@ -14,34 +7,33 @@ import subprocess import sys from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, ArgumentTypeError, RawTextHelpFormatter -from jinja2 import Environment, FileSystemLoader, StrictUndefined from tempfile import TemporaryDirectory # ------------------------------------------------------------------------------ # Parse CLI arguments # ------------------------------------------------------------------------------ -headline = "Salis: Simple A-Life Simulator" -script = sys.argv[0] -epilog = f"Use '-h' to list arguments for each command.\nExample: '{script} bench -h'" +description = "Salis: Simple A-Life Simulator" +prog = sys.argv[0] +epilog = f"Use '-h' to list arguments for each command.\nExample: '{prog} bench -h'" main_parser = ArgumentParser( - description = headline, - epilog = epilog, - formatter_class = RawTextHelpFormatter, - prog = script, + description=description, + epilog=epilog, + formatter_class=RawTextHelpFormatter, + prog=prog, ) parsers = main_parser.add_subparsers(dest="command", required=True) -fclass = ArgumentDefaultsHelpFormatter +formatter_class = lambda prog: ArgumentDefaultsHelpFormatter(prog, max_help_position=32) -bench = parsers.add_parser("bench", formatter_class=fclass, help="run benchmark") -load = parsers.add_parser("load", formatter_class=fclass, help="load saved simulation") -new = parsers.add_parser("new", formatter_class=fclass, help="create new simulation") +bench = parsers.add_parser("bench", formatter_class=formatter_class, help="run benchmark") +load = parsers.add_parser("load", formatter_class=formatter_class, help="load saved simulation") +new = parsers.add_parser("new", formatter_class=formatter_class, help="create new simulation") -archs = os.listdir("./arch") -uis = os.listdir("./ui") +architectures = os.listdir("./arch") +uis = os.listdir("./ui") -def iseed(i): +def seed(i): ival = int(i, 0) if ival < -1: raise ArgumentTypeError("invalid seed value") return ival @@ -57,135 +49,118 @@ def inat(i): return ival option_keys = ["short", "long", "metavar", "description", "default", "required", "type", "parsers"] - -# fmt: off -option_conf = [ - ["A", "anc", "ANC", "ancestor file name without extension, to be compiled on " - "all cores (ANC points to 'ancs//.asm')", None, True, str, [bench, new]], - ["a", "arch", archs, "VM architecture", "dummy", False, str, [bench, new]], - ["b", "steps", "N", "number of steps to run in benchmark", 0x1000000, False, ipos, [bench]], - ["C", "clones", "N", "number of ancestor clones on each core", 1, False, inat, [bench, new]], - ["c", "cores", "N", "number of simulator cores", 2, False, inat, [bench, new]], - ["d", "data-push-pow", "POW", "data aggregation interval exponent (interval == 2^POW >= " - "thread sync interval); a value of 0 disables data " - "aggregation (requires 'sqlite')", 28, False, ipos, [new]], - ["f", "force", None, "overwrite existing simulation of given name", False, False, bool, [new]], - ["F", "muta-flip", None, "cosmic rays flip bits instead of randomizing whole bytes", False, False, bool, [bench, new]], - ["M", "muta-pow", "POW", "mutator range exponent (range == 2^POW)", 32, False, ipos, [bench, new]], - ["m", "mvec-pow", "POW", "memory vector size exponent (size == 2^POW)", 20, False, ipos, [bench, new]], - ["n", "name", "NAME", "name of new or loaded simulation", "def.sim", False, str, [load, new]], - ["o", "optimized", None, "builds salis binary with optimizations", False, False, bool, [bench, load, new]], - ["p", "pre-cmd", "CMD", "shell command to wrap call to executable (e.g. gdb, " - "valgrind, etc.)", None, False, str, [bench, load, new]], - ["s", "seed", "SEED", "seed value for new simulation; a value of 0 disables " - "cosmic rays; a value of -1 creates a random seed", 0, False, iseed, [bench, new]], - ["S", "print-source", None, "print generated C source to stdout and exit", False, False, bool, [bench, load, new]], - ["T", "delete-temp-dir", None, "delete temporary directory on exit", True, False, bool, [bench, load, new]], - ["t", "thread-gap", "N", "memory gap between cores in bytes (may help reduce cache " - "misses?)", 0x100, False, inat, [bench, load, new]], - ["u", "ui", uis, "user interface", "curses", False, str, [load, new]], - ["x", "compress", None, "compress save files (requires 'zlib')", True, False, bool, [new]], - ["y", "sync-pow", "POW", "core sync interval exponent (interval == 2^POW)", 20, False, ipos, [bench, new]], - ["z", "auto-save-pow", "POW", "auto-save interval exponent (interval == 2^POW)", 36, False, ipos, [new]], +option_list = [ + ["A", "anc", "ANC", "ancestor file name without extension, to be compiled on all cores (ANC points to 'anc/{arch}/{ANC}.asm')", None, True, str, [bench, new]], + ["a", "arch", architectures, "VM architecture", "dummy", False, str, [bench, new]], + ["b", "steps", "N", "number of steps to run in benchmark", 0x1000000, False, ipos, [bench]], + ["C", "clones", "N", "number of ancestor clones on each core", 1, False, inat, [bench, new]], + ["c", "cores", "N", "number of simulator cores", 2, False, inat, [bench, new]], + ["d", "data-push-pow", "POW", "data aggregation interval exponent (interval == 2^{POW} >= {sync-pow}); a value of 0 disables data aggregation (requires 'sqlite')", 28, False, ipos, [new]], + ["f", "force", None, "overwrite existing simulation of given name", False, False, bool, [new]], + ["F", "muta-flip", None, "cosmic rays flip bits instead of randomizing whole bytes", False, False, bool, [bench, new]], + ["g", "compiler", "CC", "C compiler to use", "gcc", False, str, [bench, load, new]], + ["M", "muta-pow", "POW", "mutator range exponent (range == 2^{POW})", 32, False, ipos, [bench, new]], + ["m", "mvec-pow", "POW", "memory vector size exponent (size == 2^{POW})", 20, False, ipos, [bench, new]], + ["n", "name", "NAME", "name of new or loaded simulation", "def.sim", False, str, [load, new]], + ["o", "optimized", None, "builds salis binary with optimizations", False, False, bool, [bench, load, new]], + ["p", "pre-cmd", "CMD", "shell command to wrap call to executable (e.g. gdb, time, valgrind, etc.)", None, False, str, [bench, load, new]], + ["s", "seed", "SEED", "seed value for new simulation; a value of 0 disables cosmic rays; a value of -1 creates a random seed", 0, False, seed, [bench, new]], + ["T", "keep-temp-dir", None, "delete temporary directory on exit", False, False, bool, [bench, load, new]], + ["t", "thread-gap", "N", "memory gap between cores in bytes (may help reduce cache misses)", 0x100, False, inat, [bench, load, new]], + ["u", "ui", uis, "user interface", "curses", False, str, [load, new]], + ["x", "no-compress", None, "do not compress save files (useful if 'zlib' is unavailable)", True, False, bool, [new]], + ["y", "sync-pow", "POW", "core sync interval exponent (interval == 2^{POW})", 20, False, ipos, [bench, new]], + ["z", "auto-save-pow", "POW", "auto-save interval exponent (interval == 2^{POW})", 36, False, ipos, [new]], ] -# fmt: on -# Map arguments to subparsers that use them -options = list(map(lambda option: dict(zip(option_keys, option)), option_conf)) +options = list(map(lambda option: dict(zip(option_keys, option)), option_list)) parser_map = ((parser, option) for option in options for parser in option["parsers"]) for parser, option in parser_map: arg_kwargs = {} - def push_same(key): - arg_kwargs[key] = option[key] - - def push_diff(tgt_key, src_key): - arg_kwargs[tgt_key] = option[src_key] - - def push_val(key, val): - arg_kwargs[key] = val + def push_same(key): arg_kwargs[key] = option[key] + def push_diff(tgt_key, src_key): arg_kwargs[tgt_key] = option[src_key] + def push_val(key, val): arg_kwargs[key] = val push_diff("help", "description") push_same("required") - # No metavar means this argument is a flag if option["metavar"] is None: - push_val("action", "store_false" if option["default"] else "store_true") + push_val("action", "store_true") else: push_same("default") push_same("type") - if type(option["metavar"]) is list: - push_diff("choices", "metavar") - - if type(option["metavar"]) is str: - push_same("metavar") + if type(option["metavar"]) is list: push_diff("choices", "metavar") + if type(option["metavar"]) is str: push_same("metavar") - parser.add_argument( - f"-{option["short"]}", - f"--{option["long"]}", - **arg_kwargs, - ) + parser.add_argument(f"-{option["short"]}", f"--{option["long"]}", **arg_kwargs) args = main_parser.parse_args() +# ------------------------------------------------------------------------------ +# Logging +# ------------------------------------------------------------------------------ def info(msg, val=""): - print(f"\033[1;34mINFO:\033[0m {msg}", val) + print(f"\033[1;34m[INFO]\033[0m {msg}", val) def warn(msg, val=""): - print(f"\033[1;31mWARN:\033[0m {msg}", val) + print(f"\033[1;33m[WARN]\033[0m {msg}", val) def error(msg, val=""): - print(f"\033[1;31mERROR:\033[0m {msg}", val) + print(f"\033[1;31m[ERROR]\033[0m {msg}", val) sys.exit(1) # ------------------------------------------------------------------------------ # Load configuration # ------------------------------------------------------------------------------ -info(headline) -info(f"Called '{script}' with the following options:") +info(description) +info(f"Called '{prog}' with the following options:") for key, val in vars(args).items(): print(f"{key} = {repr(val)}") if args.command in ["load", "new"]: - sim_dir = f"{os.environ["HOME"]}/.salis/{args.name}" - sim_opts = f"{sim_dir}/opts.py" - sim_path = f"{sim_dir}/{args.name}" + sim_dir = os.path.join(os.environ["HOME"], ".salis", args.name) + sim_opts = os.path.join(sim_dir, "opts.py") + sim_path = os.path.join(sim_dir, args.name) if args.command in ["load"]: if not os.path.isdir(sim_dir): error("No simulation found named:", args.name) - info(f"Sourcing configuration from '{sim_opts}':") + info(f"Sourcing configuration from: '{sim_opts}':") sys.path.append(sim_dir) - import opts as opts_module + import opts - # Copy all fields in configuration file into the 'args' object - opts = (opt for opt in dir(opts_module) if not opt.startswith("__")) + opt_vars = (opt for opt in dir(opts) if not opt.startswith("__")) - for opt in opts: - opt_attr = getattr(opts_module, opt) - print(f"{opt} = {repr(opt_attr)}") - setattr(args, opt, opt_attr) + for opt_var in opt_vars: + opt_attr = getattr(opts, opt_var) + print(f"{opt_var} = {repr(opt_attr)}") + setattr(args, opt_var, opt_attr) if args.command in ["new"]: - if args.data_push_pow != 0 and args.data_push_pow < args.sync_pow: + 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") if os.path.isdir(sim_dir) and args.force: - warn("Force flag used - wiping old simulation at:", sim_dir) + warn("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) - info("Creating new simulation directory at:", sim_dir) - os.mkdir(sim_dir) + if args.seed == -1: + args.seed = random.getrandbits(64) + info("Using random seed:", args.seed) + info("Creating new simulation directory at:", sim_dir) info("Creating configuration file at:", sim_opts) + os.mkdir(sim_dir) + opts = ( option["long"].replace("-", "_") for option in options @@ -199,82 +174,24 @@ if args.command in ["new"]: # ------------------------------------------------------------------------------ # Load architecture and UI variables # ------------------------------------------------------------------------------ -arch_path = f"arch/{args.arch}" -info("Loading architecture specific variables from:", f"{arch_path}/arch_vars.py") +arch_path = os.path.join("arch", args.arch) +info("Loading architecture variables from:", os.path.join(arch_path, "arch_vars.py")) sys.path.append(arch_path) -from arch_vars import gen_arch_vars -arch_vars = gen_arch_vars(args) +from arch_vars import ArchVars +arch_vars = ArchVars(args) if args.command in ["load", "new"]: - ui_path = f"ui/{args.ui}" - info("Loading UI specific variables from:", f"{ui_path}/ui_vars.py") + ui_path = os.path.join("ui", args.ui) + info("Loading UI variables from:", os.path.join(ui_path, "ui_vars.py")) sys.path.append(ui_path) - from ui_vars import gen_ui_vars - ui_vars = gen_ui_vars(args) + from ui_vars import UIVars + ui_vars = UIVars(args) # ------------------------------------------------------------------------------ -# Fill in template variables -# ------------------------------------------------------------------------------ -ul_val = lambda val: f"{hex(val)}ul" -ul_pow = lambda val: f"{hex(2 ** val)}ul" - -includes = [ - "assert.h", - "stdarg.h", - "stdbool.h", - "stddef.h", - "stdint.h", - "stdlib.h", - "string.h", - "threads.h", -] - -inst_cap = "0x80" -inst_mask = "0x7f" -ipc_flag = "0x80" -mall_flag = "0x80" -muta_range = ul_pow(args.muta_pow) -mvec_size = ul_pow(args.mvec_pow) -sync_interval = ul_pow(args.sync_pow) -thread_gap = ul_val(args.thread_gap) -uint64_half = ul_val(0x8000000000000000) - -if args.seed == -1: - args.seed = ul_val(random.getrandbits(64)) - info("Using random seed", args.seed) -else: - args.seed = ul_val(args.seed) - -if args.command in ["bench"]: - includes.append("stdio.h") - args.steps = ul_val(args.steps) - -if args.command in ["load", "new"]: - auto_save_interval = ul_pow(args.auto_save_pow) - auto_save_name_len = f"{len(sim_path) + 20}" - - if args.data_push_pow != 0: - data_push_path = f"{sim_dir}/{args.name}.sqlite3" - data_push_interval = ul_pow(args.data_push_pow) - data_push_busy_timeout = 600000 - includes.append("sqlite3.h") - info("Data will be aggregated at:", data_push_path) - else: - warn("Data aggregation disabled") - - if args.compress: - includes.append("zlib.h") - info("Save file compression enabled") - else: - warn("Save file compression disabled") - - includes.extend(ui_vars["includes"]) - -# ------------------------------------------------------------------------------ -# Assemble ancestor organism into byte array +# Compile ancestor organism # ------------------------------------------------------------------------------ if args.command in ["bench", "new"] and args.anc is not None: - anc_path = f"ancs/{args.arch}/{args.anc}.asm" + 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) @@ -287,71 +204,120 @@ if args.command in ["bench", "new"] and args.anc is not None: lines = filter(lambda line: line, lines) lines = map(lambda line: line.split(), lines) - # A very simple assembler that compares lines in input ASM file against - # all entries in the instruction set table provided by each architecture. - # The resulting bytes equate to each instruction's index on the table. anc_bytes = [] for line in lines: found = False - for byte, tup in enumerate(arch_vars["inst_set"]): + for byte, tup in enumerate(arch_vars.inst_set): if line == tup[0]: anc_bytes.append(byte) found = True - continue + break if not found: error("Unrecognized instruction in ancestor file:", line) - anc_repr = f"[{','.join(map(str, anc_bytes))}]" - info(f"Compiled ancestor file '{anc_path}' into byte array:", anc_repr) + anc_bytes_repr = ",".join(map(str, anc_bytes)) + info(f"Compiled ancestor file '{anc_path}' into byte array:", f"{{{anc_bytes_repr}}}") # ------------------------------------------------------------------------------ -# Emit C source +# Populate compiler flags # ------------------------------------------------------------------------------ -tempdir = TemporaryDirectory(prefix="salis_", delete=args.delete_temp_dir) -info("Created a temporary salis directory at:", tempdir.name) +flags = set() +includes = set() +defines = set() +links = set() + +flags.update({"-Wall", "-Wextra", "-Werror", f"-Iarch/{args.arch}"}) + +defines.add(f"-DARCH=\"{args.arch}\"") +defines.add(f"-DCOMMAND_{args.command.upper()}") +defines.add(f"-DCORES={args.cores}") +defines.add(f"-DMUTA_RANGE={2 ** args.muta_pow}ul") +defines.add(f"-DMVEC_SIZE={2 ** args.mvec_pow}ul") +defines.add(f"-DSEED={args.seed}ul") +defines.add(f"-DSYNC_INTERVAL={2 ** args.sync_pow}ul") +defines.add(f"-DTHREAD_GAP={args.thread_gap}") + +defines.add(f"-DCORE_FIELDS={" ".join(f"CORE_FIELD({", ".join(field)})" for field in arch_vars.core_fields)}") +defines.add(f"-DPROC_FIELDS={" ".join(f"PROC_FIELD({", ".join(field)})" for field in arch_vars.proc_fields)}") +defines.add(f"-DINST_SET={" ".join(f"INST({index}, {"_".join(inst[0])}, \"{" ".join(inst[0])}\", L'{inst[1]}')" for index, inst in enumerate(arch_vars.inst_set))}") +defines.add(f"-DCORE_FIELD_COUNT={len(arch_vars.core_fields)}") +defines.add(f"-DPROC_FIELD_COUNT={len(arch_vars.proc_fields)}") +defines.add(f"-DINST_COUNT={len(arch_vars.inst_set)}") +defines.add(f"-DFOR_CORES={" ".join(f"FOR_CORE({i})" for i in range(args.cores))}") + +if args.muta_flip: defines.add("-DMUTA_FLIP") +if arch_vars.mvec_loop: defines.add("-DMVEC_LOOP") + +if args.optimized: + flags.add("-O3") + defines.add("-DNDEBUG") +else: + flags.add("-ggdb") -salis_src = f"{tempdir.name}/salis.c" -info("Emitting C source at:", salis_src) +if args.command in ["bench"]: + includes.add("stdio.h") + defines.add(f"-DSTEPS={args.steps}ul") -jinja_env = Environment( - loader = FileSystemLoader("."), - lstrip_blocks = True, - trim_blocks = True, - undefined = StrictUndefined, -) +if args.command in ["bench", "new"]: + defines.add(f"-DCLONES={args.clones}") + + if args.anc is not None: + defines.add(f"-DANC_BYTES={{{anc_bytes_repr}}}") + defines.add(f"-DANC_SIZE={len(anc_bytes)}") -source_str = jinja_env.get_template("core.j2.c").render(**locals()) +if args.command in ["load", "new"]: + flags.add(f"-Iui/{args.ui}") + includes.update(ui_vars.includes) + defines.update(ui_vars.defines) + defines.add(f"-DAUTOSAVE_INTERVAL={2 ** args.auto_save_pow}ul") + defines.add(f"-DAUTOSAVE_NAME_LEN={len(sim_path) + 20}") + defines.add(f"-DNAME=\"{args.name}\"") + defines.add(f"-DSIM_PATH=\"{sim_path}\"") + links.update(ui_vars.links) + + if args.data_push_pow: + includes.add("sqlite3.h") + data_push_path = os.path.join(sim_dir, f"{args.name}.sqlite3") + defines.add(f"-DDATA_PUSH_INTERVAL={2 ** args.data_push_pow}ul") + defines.add(f"-DDATA_PUSH_PATH=\"{data_push_path}\"") + links.add("-lsqlite3") + info("Data will be aggregated at:", data_push_path) -if args.print_source: - info("Printing C source and exiting...") - print(source_str) - exit(0) + if arch_vars.data_is_compressed: + includes.add("zlib.h") + links.add("-lz") + info("Data aggregation requires compression") + else: + warn("Data aggregation disabled") -with open(salis_src, "w") as file: - file.write(source_str) + if not args.no_compress: + includes.add("zlib.h") + defines.add("-D_POSIX_C_SOURCE=200809L") + defines.add("-DCOMPRESS") + links.add("-lz") + info("Save file compression enabled") + else: + warn("Save file compression disabled") # ------------------------------------------------------------------------------ # Build executable # ------------------------------------------------------------------------------ -salis_bin = f"{tempdir.name}/salis_bin" -info("Building salis binary at:", salis_bin) - -build_cmd = ["gcc", salis_src, "-o", salis_bin, "-Wall", "-Wextra", "-Werror", "-Wno-overlength-strings", "-pedantic", "-std=c11"] -build_cmd.extend(["-O3", "-DNDEBUG"] if args.optimized else ["-ggdb"]) +tempdir = TemporaryDirectory(prefix="salis_", delete=not args.keep_temp_dir) +info("Created a temporary salis directory at:", tempdir.name) -if args.command in ["load", "new"]: - build_cmd.extend(ui_vars["flags"]) +salis_bin = os.path.join(tempdir.name, "salis_bin") +info("Building salis binary at:", salis_bin) - # Enable POSIX extensions (open_memstream) if compression is enabled - # This makes it easy to generate compressed data arrays for lzip using - # C's native FILE interface. - build_cmd.extend(["-lz", "-D_POSIX_C_SOURCE=200809L"] if args.compress else []) - build_cmd.extend(["-lsqlite3"] if args.data_push_pow != 0 else []) +build_cmd = [args.compiler, "core.c", "-o", salis_bin] +build_cmd.extend(flags) +build_cmd.extend(sum(map(lambda include: [f"-include", include], includes), [])) +build_cmd.extend(defines) +build_cmd.extend(links) -info("Using build command:", " ".join(build_cmd)) +info("Using build command:", build_cmd) subprocess.run(build_cmd, check=True) # ------------------------------------------------------------------------------ @@ -365,7 +331,6 @@ run_cmd.append(salis_bin) info("Using run command:", " ".join(run_cmd)) salis_sp = subprocess.Popen(run_cmd, stdout=sys.stdout, stderr=sys.stderr) -# Ctrl-C terminates the simulator gracefully. # When using signals (e.g. SIGTERM), they must be sent to the entire process group # to make sure both the simulator and the interpreter get shut down. try: diff --git a/ui/curses/ui.c b/ui/curses/ui.c new file mode 100644 index 0000000..faf1b6e --- /dev/null +++ b/ui/curses/ui.c @@ -0,0 +1,1371 @@ +#define LOG_LINE_COUNT 1024 +#define LOG_LINE_SIZE 1024 +#define PANE_WIDTH 27 +#define PROC_FIELD_WIDTH 21 +#define PROC_PAGE_LINES 12 + +#define CTRL(x) (x & 0x1f) + +#if defined(NDEBUG) +#define MIN_FPS 30 +#define MAX_FPS 60 +#else +#define MIN_FPS 5 +#define MAX_FPS 10 +#endif + +enum { + PAGE_CORE, + PAGE_PROCESS, + PAGE_WORLD, + PAGE_IPC, + PAGE_LOG, + PAGE_COUNT, +}; + +enum { + PAIR_NOUSE, + PAIR_NORMAL, + PAIR_HEADER, + PAIR_WARN, + PAIR_LIVE_PROC, + PAIR_SELECTED_PROC, + PAIR_FREE_CELL, + PAIR_ALLOC_CELL, + PAIR_MEM_BLOCK_START, + PAIR_SELECTED_MB1, + PAIR_SELECTED_MB2, + PAIR_SELECTED_IP, + PAIR_SELECTED_SP, +}; + +// GFX globals +uint64_t g_gfx_vsiz; // zoom level +uint64_t *g_gfx_inst; // instruction channel +uint64_t *g_gfx_mall; // allocated state channel +uint64_t *g_gfx_mbst; // memory block start channel +uint64_t *g_gfx_mb0s; // selected organism's memory block #1 channel +uint64_t *g_gfx_mb1s; // selected organism's memory block #2 channel +uint64_t *g_gfx_ipas; // selected organism's IP channel +uint64_t *g_gfx_spas; // selected organism's SP channel + +// UI globals +bool g_exit; +bool g_running; +unsigned g_core; +unsigned g_page; +bool g_proc_genes; +uint64_t g_proc_scroll; +uint64_t g_proc_field_scroll; +uint64_t g_proc_gene_scroll; +uint64_t g_proc_selected; +uint64_t g_wrld_pos; +uint64_t g_wrld_zoom; +bool g_wcursor_mode; +int g_wcursor_x; +int g_wcursor_y; +uint64_t g_wcursor_pointed; +uint64_t g_log_cnt; +unsigned g_log_ptr; +unsigned g_log_scroll; +bool g_log_warns[LOG_LINE_COUNT]; +time_t g_log_times[LOG_LINE_COUNT]; +char g_logs[LOG_LINE_COUNT][LOG_LINE_SIZE]; +uint64_t g_vlin; +uint64_t g_vsiz; +uint64_t g_vlin_rng; +uint64_t g_vsiz_rng; +uint64_t g_ivpt_scroll; +char *g_line_buff; +uint64_t g_step_block; + +const wchar_t *g_zoomed_symbols = ( + L"⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟" + L"⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿" + L"⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟" + L"⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿" +); + +// ---------------------------------------------------------------------------- +// GFX functions +// ---------------------------------------------------------------------------- +void gfx_init(uint64_t vsiz) { + assert(vsiz); + + g_gfx_vsiz = vsiz; + + g_gfx_inst = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mall = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mbst = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mb0s = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_mb1s = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_ipas = calloc(g_gfx_vsiz, sizeof(uint64_t)); + g_gfx_spas = calloc(g_gfx_vsiz, sizeof(uint64_t)); + + assert(g_gfx_inst); + assert(g_gfx_mall); + assert(g_gfx_mbst); + assert(g_gfx_mb0s); + assert(g_gfx_mb1s); + assert(g_gfx_ipas); + assert(g_gfx_spas); +} + +void gfx_free() { + if (g_gfx_vsiz == 0) { + return; + } + + assert(g_gfx_inst); + assert(g_gfx_mall); + assert(g_gfx_mbst); + assert(g_gfx_mb0s); + assert(g_gfx_mb1s); + assert(g_gfx_ipas); + assert(g_gfx_spas); + + g_gfx_vsiz = 0; + + free(g_gfx_inst); + free(g_gfx_mall); + free(g_gfx_mbst); + free(g_gfx_mb0s); + free(g_gfx_mb1s); + free(g_gfx_ipas); + free(g_gfx_spas); + + g_gfx_inst = NULL; + g_gfx_mall = NULL; + g_gfx_mbst = NULL; + g_gfx_mb0s = NULL; + g_gfx_mb1s = NULL; + g_gfx_ipas = NULL; + g_gfx_spas = NULL; +} + +void gfx_resize(uint64_t vsiz) { + assert(vsiz); + + gfx_free(); + gfx_init(vsiz); +} + +void gfx_render_inst(const struct Core *core, uint64_t pos, uint64_t zoom) { + assert(core); + + for (uint64_t i = 0; i < g_gfx_vsiz; ++i) { + g_gfx_inst[i] = 0; + g_gfx_mall[i] = 0; + + for (uint64_t j = 0; j < zoom; ++j) { + uint64_t addr = pos + (i * zoom) + j; + + g_gfx_inst[i] += mvec_get_byte(core, addr); + g_gfx_mall[i] += mvec_is_alloc(core, addr) ? 1 : 0; + } + } +} + +void gfx_clear_array(uint64_t *arry) { + assert(arry); + memset(arry, 0, g_gfx_vsiz * sizeof(uint64_t)); +} + +#if defined(MVEC_LOOP) +void gfx_accumulate_pixel(uint64_t pos, uint64_t zoom, uint64_t pixa, uint64_t *arry) { + assert(arry); + + uint64_t beg_mod = pos % MVEC_SIZE; + uint64_t end_mod = beg_mod + (g_gfx_vsiz * zoom); + uint64_t pix_mod = pixa % MVEC_SIZE; + +#if !defined(NDEBUG) + uint64_t inc_cnt = 0; +#endif + + while (pix_mod < end_mod) { + if (pix_mod >= beg_mod && pix_mod < end_mod) { + uint64_t pixi = (pix_mod - beg_mod) / zoom; + assert(pixi < g_gfx_vsiz); + arry[pixi]++; + +#if !defined(NDEBUG) + inc_cnt++; +#endif + } + + pix_mod += MVEC_SIZE; + } + +#if !defined(NDEBUG) + if (zoom != 1) { + assert(inc_cnt <= 2); + } +#endif +} +#endif + +#if !defined(MVEC_LOOP) +void gfx_accumulate_pixel(uint64_t pos, uint64_t zoom, uint64_t pixa, uint64_t *arry) { + assert(arry); + + uint64_t end = pos + (g_gfx_vsiz * zoom); + + if (pixa < pos || pixa >= end) { + return; + } + + uint64_t pixi = (pixa - pos) / zoom; + assert(pixi < g_gfx_vsiz); + arry[pixi]++; +} +#endif + +void gfx_render_mbst(const struct Core *core, uint64_t pos, uint64_t zoom) { + assert(core); + + gfx_clear_array(g_gfx_mbst); + + for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) { + uint64_t mb0a = arch_proc_mb0_addr(core, pix); + uint64_t mb1a = arch_proc_mb1_addr(core, pix); + + gfx_accumulate_pixel(pos, zoom, mb0a, g_gfx_mbst); + gfx_accumulate_pixel(pos, zoom, mb1a, g_gfx_mbst); + } +} + +void gfx_render_mb0s(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + + gfx_clear_array(g_gfx_mb0s); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + uint64_t mb0a = arch_proc_mb0_addr(core, psel); + uint64_t mb0s = arch_proc_mb0_size(core, psel); + + for (uint64_t i = 0; i < mb0s; ++i) { + gfx_accumulate_pixel(pos, zoom, mb0a + i, g_gfx_mb0s); + } +} + +void gfx_render_mb1s(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + + gfx_clear_array(g_gfx_mb1s); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + uint64_t mb1a = arch_proc_mb1_addr(core, psel); + uint64_t mb1s = arch_proc_mb1_size(core, psel); + + for (uint64_t i = 0; i < mb1s; ++i) { + gfx_accumulate_pixel(pos, zoom, mb1a + i, g_gfx_mb1s); + } +} + +void gfx_render_ipas(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + + gfx_clear_array(g_gfx_ipas); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + uint64_t ipa = arch_proc_ip_addr(core, psel); + + gfx_accumulate_pixel(pos, zoom, ipa, g_gfx_ipas); +} + +void gfx_render_spas(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + + gfx_clear_array(g_gfx_spas); + + if (psel < core->pfst || psel > core->plst) { + return; + } + + uint64_t spa = arch_proc_sp_addr(core, psel); + + gfx_accumulate_pixel(pos, zoom, spa, g_gfx_spas); +} + +void gfx_render(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { + assert(core); + + gfx_render_inst(core, pos, zoom); + gfx_render_mbst(core, pos, zoom); + gfx_render_mb0s(core, pos, zoom, psel); + gfx_render_mb1s(core, pos, zoom, psel); + gfx_render_ipas(core, pos, zoom, psel); + gfx_render_spas(core, pos, zoom, psel); +} + +// ---------------------------------------------------------------------------- +// UI generic functions +// ---------------------------------------------------------------------------- +void ui_line_buff_free() { + if (g_line_buff) { + free(g_line_buff); + } + + g_line_buff = NULL; +} + +void ui_line_buff_resize() { + ui_line_buff_free(); + + g_line_buff = calloc(COLS + 1, sizeof(char)); +} + +void ui_line(bool clear, int line, int color, int attr, const char *format, ...) { + assert(line >= 0); + assert(format); + + if (line >= LINES) { + return; + } + + if (clear) { + move(line, 0); + clrtoeol(); + } + + va_list args; + + attron(COLOR_PAIR(color) | attr); + va_start(args, format); + + vsnprintf(g_line_buff, COLS, format, args); + mvprintw(line, 1, g_line_buff); + + va_end(args); + attroff(COLOR_PAIR(color) | attr); +} + +void ui_clear_line(int l) { + ui_line(true, l, PAIR_NORMAL, A_NORMAL, ""); +} + +void ui_field(int line, int col, int color, int attr, const char *format, ...) { + assert(line >= 0); + assert(col >= 0); + assert(format); + + if (line >= LINES || col >= COLS) { + return; + } + + va_list args; + + attron(COLOR_PAIR(color) | attr); + va_start(args, format); + + vsnprintf(g_line_buff, COLS - col, format, args); + mvprintw(line, col, g_line_buff); + + va_end(args); + attroff(COLOR_PAIR(color) | attr); +} + +void ui_str_field(int l, const char *label, const char *value) { + assert(label); + assert(value); + ui_line(false, l, PAIR_NORMAL, A_NORMAL, "%s : %18s", label, value); +} + +void ui_ulx_field(int l, const char *label, uint64_t value) { + assert(label); + ui_line(false, l, PAIR_NORMAL, A_NORMAL, "%-4s : %#18lx", label, value); +} + +// ---------------------------------------------------------------------------- +// Core page functions +// ---------------------------------------------------------------------------- +void ui_print_core(int l) { + ui_line(false, ++l, PAIR_HEADER, A_BOLD, "CORE [%d]", g_core); + ui_ulx_field(++l, "cycl", g_cores[g_core].cycl); + ui_ulx_field(++l, "mall", g_cores[g_core].mall); + ui_ulx_field(++l, "mut0", g_cores[g_core].muta[0]); + ui_ulx_field(++l, "mut1", g_cores[g_core].muta[1]); + ui_ulx_field(++l, "mut2", g_cores[g_core].muta[2]); + ui_ulx_field(++l, "mut3", g_cores[g_core].muta[3]); + ui_ulx_field(++l, "pnum", g_cores[g_core].pnum); + ui_ulx_field(++l, "pcap", g_cores[g_core].pcap); + ui_ulx_field(++l, "pfst", g_cores[g_core].pfst); + ui_ulx_field(++l, "plst", g_cores[g_core].plst); + ui_ulx_field(++l, "pcur", g_cores[g_core].pcur); + ui_ulx_field(++l, "psli", g_cores[g_core].psli); + ui_ulx_field(++l, "ivpt", g_cores[g_core].ivpt); + + ++l; + +#if CORE_FIELD_COUNT != 0 + ui_line(false, ++l, PAIR_HEADER, A_BOLD, "ARCH SPECIFIC"); + +#define CORE_FIELD(type, name, suffix) ui_ulx_field(++l, #name, (uint64_t)g_cores[g_core].name); + CORE_FIELDS +#undef CORE_FIELD +#endif +} + +// ---------------------------------------------------------------------------- +// Process page functions +// ---------------------------------------------------------------------------- +int ui_proc_pair(uint64_t pix) { + if (pix == g_proc_selected) { + return PAIR_SELECTED_PROC; + } else if (mvec_proc_is_live(&g_cores[g_core], pix)) { + return PAIR_LIVE_PROC; + } else { + return PAIR_NORMAL; + } +} + +const char *ui_proc_state(uint64_t pix) { + return mvec_proc_is_live(&g_cores[g_core], pix) ? "live" : "dead"; +} + +void ui_print_process_genome_header(int l) { + ui_line(false, l++, PAIR_NORMAL, A_NORMAL, "%s : %18s : %s", "stat", "pix", "genome"); +} + +void ui_print_process_gene(int l, int gcol, uint64_t gidx, uint64_t mba, uint64_t pix, int pair) { + assert(gcol >= PANE_WIDTH + 2); + assert(gcol < COLS); + assert(mvec_proc_is_live(&g_cores[g_core], pix)); + assert(pair == PAIR_SELECTED_MB1 || pair == PAIR_SELECTED_MB2); + + const struct Core *core = &g_cores[g_core]; + + uint64_t addr = mba + gidx; + uint8_t byte = mvec_get_byte(core, addr); + + wchar_t gsym[2] = { arch_symbol(byte), L'\0' }; + cchar_t cchar = { 0 }; + + int pair_cell; + + if (arch_proc_ip_addr(core, pix) == addr) { + pair_cell = PAIR_SELECTED_IP; + } else if (arch_proc_sp_addr(core, pix) == addr) { + pair_cell = PAIR_SELECTED_SP; + } else { + pair_cell = pair; + } + + setcchar(&cchar, gsym, 0, pair_cell, NULL); + mvadd_wch(l, gcol, &cchar); +} + +void ui_print_process_genes(int l, uint64_t pix) { + ui_line(true, l, ui_proc_pair(pix), A_NORMAL, "%s : %#18lx :", ui_proc_state(pix), pix); + + if (!mvec_proc_is_live(&g_cores[g_core], pix)) { + return; + } + + const struct Core *core = &g_cores[g_core]; + + int scol = PANE_WIDTH + 2; + int gcol = scol - g_proc_gene_scroll; + uint64_t mb0a = arch_proc_mb0_addr(core, pix); + uint64_t mb0s = arch_proc_mb0_size(core, pix); + uint64_t mb1a = arch_proc_mb1_addr(core, pix); + uint64_t mb1s = arch_proc_mb1_size(core, pix); + + for (uint64_t gidx = 0; gidx < mb0s && gcol < COLS; ++gidx, ++gcol) { + if (gcol >= scol) { + ui_print_process_gene(l, gcol, gidx, mb0a, pix, PAIR_SELECTED_MB1); + } + } + + for (uint64_t gidx = 0; gidx < mb1s && gcol < COLS; ++gidx, ++gcol) { + if (gcol >= scol) { + ui_print_process_gene(l, gcol, gidx, mb1a, pix, PAIR_SELECTED_MB2); + } + } + + clrtoeol(); +} + +void ui_print_process_field_header_element(int l, int fidx, const char *name) { + assert(fidx >= 0); + assert(name); + + if (fidx < (int)g_proc_field_scroll) { + return; + } + + int foff = fidx - g_proc_field_scroll; + int fcol = foff * PROC_FIELD_WIDTH + PANE_WIDTH - 1; + + ui_field(l, fcol, PAIR_NORMAL, A_NORMAL, " : %18s", name); +} + +void ui_print_process_field_header(int l) { + ui_line(true, l, PAIR_NORMAL, A_NORMAL, "%s : %18s", "stat", "pix"); + + int fidx = 0; + +#define PROC_FIELD(type, name) ui_print_process_field_header_element(l, fidx++, #name); + PROC_FIELDS +#undef PROC_FIELD +} + +void ui_print_process_field_element(int l, int fidx, int fclr, uint64_t field) { + assert(fidx >= 0); + + if (fidx < (int)g_proc_field_scroll) { + return; + } + + int foff = fidx - g_proc_field_scroll; + int fcol = foff * PROC_FIELD_WIDTH + PANE_WIDTH - 1; + + ui_field(l, fcol, fclr, A_NORMAL, " : %#18lx", field); +} + +void ui_print_process_fields(int l, uint64_t pix) { + ui_line(true, l, ui_proc_pair(pix), A_NORMAL, "%s : %#18lx", ui_proc_state(pix), pix); + + const struct Proc *proc = proc_get(&g_cores[g_core], pix); + + int fidx = 0; + int fclr = ui_proc_pair(pix); + +#define PROC_FIELD(type, name) ui_print_process_field_element(l, fidx++, fclr, proc->name); + PROC_FIELDS +#undef PROC_FIELD +} + +void ui_print_process(int l) { + l++; + + ui_line(true, l++, PAIR_HEADER, A_BOLD, + "PROCESS [vs:%#lx | ps:%#lx | pf:%#lx | pl:%#lx | fs:%#lx | gs:%#lx]", + g_proc_scroll, + g_proc_selected, + g_cores[g_core].pfst, + g_cores[g_core].plst, + g_proc_field_scroll, + g_proc_gene_scroll + ); + + uint64_t pix = g_proc_scroll; + + if (g_proc_genes) { + ui_print_process_genome_header(l++); + + while (l < LINES) { + ui_print_process_genes(l++, pix++); + } + } else { + ui_print_process_field_header(l++); + + while (l < LINES) { + ui_print_process_fields(l++, pix++); + } + } +} + +// ---------------------------------------------------------------------------- +// World page functions +// ---------------------------------------------------------------------------- +void ui_world_resize() { + assert(g_wrld_zoom); + + g_vlin = 0; + g_vsiz = 0; + g_vlin_rng = 0; + g_vsiz_rng = 0; + + if (COLS > PANE_WIDTH) { + g_vlin = COLS - PANE_WIDTH; + g_vsiz = LINES * g_vlin; + g_vlin_rng = g_vlin * g_wrld_zoom; + g_vsiz_rng = g_vsiz * g_wrld_zoom; + + gfx_resize(g_vsiz); + } +} + +#if defined(MVEC_LOOP) +void ui_print_cell(uint64_t i, uint64_t r, uint64_t x, uint64_t y) { +#else +void ui_print_cell(uint64_t i, uint64_t r, uint64_t x, uint64_t y, uint64_t a) { +#endif + wchar_t inst_nstr[2] = { L'\0', L'\0' }; + cchar_t cchar = { 0 }; + uint64_t inst_avrg = g_gfx_inst[i] / g_wrld_zoom; + + if (g_wrld_zoom == 1) { + inst_nstr[0] = arch_symbol((uint8_t)inst_avrg); + } else { + inst_nstr[0] = g_zoomed_symbols[(uint8_t)inst_avrg]; + } + + int pair_cell; + +#if defined(MVEC_LOOP) + if (g_wcursor_mode && r == (uint64_t)g_wcursor_x && y == (uint64_t)g_wcursor_y) { +#else + if (a >= MVEC_SIZE || (g_wcursor_mode && r == (uint64_t)g_wcursor_x && y == (uint64_t)g_wcursor_y)) { +#endif + pair_cell = PAIR_NORMAL; + } else if (g_wcursor_mode && r == (uint64_t)g_wcursor_x && y == (uint64_t)g_wcursor_y) { + pair_cell = PAIR_NORMAL; + } else if (g_gfx_ipas[i] != 0) { + pair_cell = PAIR_SELECTED_IP; + } else if (g_gfx_spas[i] != 0) { + pair_cell = PAIR_SELECTED_SP; + } else if (g_gfx_mb0s[i] != 0) { + pair_cell = PAIR_SELECTED_MB1; + } else if (g_gfx_mb1s[i] != 0) { + pair_cell = PAIR_SELECTED_MB2; + } else if (g_gfx_mbst[i] != 0) { + pair_cell = PAIR_MEM_BLOCK_START; + } else if (g_gfx_mall[i] != 0) { + pair_cell = PAIR_ALLOC_CELL; + } else { + pair_cell = PAIR_FREE_CELL; + } + + setcchar(&cchar, inst_nstr, 0, pair_cell, NULL); + mvadd_wch(y, x, &cchar); +} + +void ui_print_wcursor_bar() { + ui_clear_line(LINES - 1); + + const struct Core *core = &g_cores[g_core]; + + char cownr[PROC_FIELD_WIDTH]; + + uint64_t cpos = g_vlin * g_wcursor_y + g_wcursor_x; + uint64_t caddr = cpos * g_wrld_zoom + g_wrld_pos; + uint8_t cbyte = mvec_get_byte(core, caddr); + + if (mvec_is_alloc(core, caddr)) { + g_wcursor_pointed = mvec_get_owner(core, caddr); + snprintf(cownr, PROC_FIELD_WIDTH, "%#lx", g_wcursor_pointed); + } else { + g_wcursor_pointed = (uint64_t)(-1); + snprintf(cownr, PROC_FIELD_WIDTH, "-"); + } + + mvprintw( + LINES - 1, + 1, + "cursor | x:%#x | y:%#x | addr:%#lx | isum:%#lx | iavr:%#lx | mall:%#lx | mbst:%#lx | mnem:<%s> | ownr:%s", + g_wcursor_x, + g_wcursor_y, + caddr, + g_gfx_inst[cpos], + g_gfx_inst[cpos] / g_wrld_zoom, + g_gfx_mall[cpos], + g_gfx_mbst[cpos], + arch_mnemonic(cbyte), + cownr + ); +} + +void ui_print_world(int l) { + l++; + + ui_line(false, l++, PAIR_HEADER, A_BOLD, "WORLD"); + ui_ulx_field(l++, "wrlp", g_wrld_pos); + ui_ulx_field(l++, "wrlz", g_wrld_zoom); + ui_ulx_field(l++, "psel", g_proc_selected); + ui_ulx_field(l++, "pabs", g_proc_selected % g_cores[g_core].pcap); + ui_ulx_field(l++, "vrng", g_vsiz_rng); + ui_str_field(l++, "curs", g_wcursor_mode ? "on" : "off"); + + l++; + + ui_line(false, l++, PAIR_HEADER, A_BOLD, "SELECTED"); + + const struct Proc *psel = proc_get(&g_cores[g_core], g_proc_selected); + +#define PROC_FIELD(type, name) ui_ulx_field(l++, #name, psel->name); + PROC_FIELDS +#undef PROC_FIELD + + if (!g_vlin) { + return; + } + + gfx_render(&g_cores[g_core], g_wrld_pos, g_wrld_zoom, g_proc_selected); + + if (g_wcursor_mode) { + int xmax = g_vlin - 1; + int ymax = LINES - 2; + + g_wcursor_x = (g_wcursor_x < xmax) ? g_wcursor_x : xmax; + g_wcursor_y = (g_wcursor_y < ymax) ? g_wcursor_y : ymax; + } + + for (uint64_t i = 0; i < g_vsiz; ++i) { + uint64_t r = i % g_vlin; + uint64_t x = r + PANE_WIDTH; + uint64_t y = i / g_vlin; + +#if defined(MVEC_LOOP) + ui_print_cell(i, r, x, y); +#else + uint64_t a = g_wrld_pos + (i * g_wrld_zoom); + ui_print_cell(i, r, x, y, a); +#endif + } + + if (g_wcursor_mode) { + ui_print_wcursor_bar(); + } +} + +// ---------------------------------------------------------------------------- +// IPC page functions +// ---------------------------------------------------------------------------- +void ui_print_ipc_field(int l, uint64_t i, int color) { + uint8_t iinst = g_cores[g_core].iviv[i]; + uint64_t iaddr = g_cores[g_core].ivav[i]; + + ui_field(l, PANE_WIDTH, color, A_NORMAL, "%#18x : %#18x : %#18x", i, iinst, iaddr); +} + +void ui_print_ipc_data() { + ui_field(0, PANE_WIDTH, PAIR_NORMAL, A_NORMAL, "%18s : %18s : %18s", "ipci", "inst", "addr"); + + int l = 1 - g_ivpt_scroll; + + for (uint64_t i = 0; i < SYNC_INTERVAL; ++i) { + if (i == g_cores[g_core].ivpt) { + if (l >= 1) { + ui_print_ipc_field(l++, i, PAIR_SELECTED_PROC); + } + + continue; + } + + uint8_t iinst = g_cores[g_core].iviv[i]; + + if ((iinst & IPC_FLAG) != 0) { + if (l >= 1) { + ui_print_ipc_field(l++, i, PAIR_LIVE_PROC); + } + + continue; + } + } + + for (; l < LINES; ++l) { + if (l >= 1) { + move(l, PANE_WIDTH); + clrtoeol(); + } + } +} + +void ui_print_ipc(int l) { + l++; + + const struct Core *core = &g_cores[g_core]; + + ui_line(true, l++, PAIR_HEADER, A_BOLD, "IPC [%#lx]", g_ivpt_scroll); + ui_ulx_field(l++, "ivpt", core->ivpt); + ui_ulx_field(l++, "ivpi", core->iviv[core->ivpt]); + ui_ulx_field(l++, "ivpa", core->ivav[core->ivpt]); + + ui_print_ipc_data(); +} + +// ---------------------------------------------------------------------------- +// Log page functions +// ---------------------------------------------------------------------------- +void ui_info_impl(const char *format, ...) { + g_log_warns[g_log_ptr] = false; + g_log_times[g_log_ptr] = time(NULL); + + va_list args; + va_start(args, format); + vsnprintf(g_logs[g_log_ptr], LOG_LINE_SIZE, format, args); + va_end(args); + + g_log_cnt++; + g_log_ptr = (g_log_ptr + 1) % LOG_LINE_COUNT; +} + +void ui_warn_impl(const char *format, ...) { + g_log_warns[g_log_ptr] = true; + g_log_times[g_log_ptr] = time(NULL); + + va_list args; + va_start(args, format); + vsnprintf(g_logs[g_log_ptr], LOG_LINE_SIZE, format, args); + va_end(args); + + g_log_cnt++; + g_log_ptr = (g_log_ptr + 1) % LOG_LINE_COUNT; +} + +void ui_clear_log_line(int line) { + assert(line >= 0 && line < LINES); + move(line, PANE_WIDTH); + clrtoeol(); +} + +void ui_print_log_line(unsigned lptr, int line) { + assert(lptr < LOG_LINE_COUNT); + assert(line >= 0 && line < LINES); + ui_clear_log_line(line); + + if (strlen(g_logs[lptr])) { + struct tm tm = *localtime(&g_log_times[lptr]); + + ui_field( + line, + PANE_WIDTH, + PAIR_NORMAL, + A_NORMAL, + " %d-%02d-%02d %02d:%02d:%02d", + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec + ); + + ui_field( + line, + PANE_WIDTH + 22, + g_log_warns[lptr] ? PAIR_WARN : PAIR_HEADER, + A_NORMAL, + g_log_warns[lptr] ? "[WARN]" : "[INFO]" + ); + + ui_field( + line, + PANE_WIDTH + 29, + PAIR_NORMAL, + A_NORMAL, + g_logs[lptr] + ); + } +} + +void ui_print_log(int l) { + l++; + + ui_line(true, l++, PAIR_HEADER, A_BOLD, "LOG"); + ui_ulx_field(l++, "lscr", g_log_scroll); + ui_ulx_field(l++, "lcnt", g_log_cnt); + ui_ulx_field(l++, "lptr", g_log_ptr); + + unsigned lptr = g_log_ptr; + int line = LINES + g_log_scroll; + + while (line) { + lptr = (lptr - 1 + LOG_LINE_COUNT) % LOG_LINE_COUNT; + line--; + + if (line < LINES) { + ui_print_log_line(lptr, line); + } + + if (lptr == g_log_ptr) { + break; + } + } + + while (line) { + line--; + ui_clear_log_line(line); + } +} + +// ---------------------------------------------------------------------------- +// Main print function +// ---------------------------------------------------------------------------- +void ui_print() { + int l = 1; + + ui_line(false, l++, PAIR_HEADER, A_BOLD, "SALIS [%d:%d]", g_core, CORES); + ui_str_field(l++, "name", NAME); + ui_ulx_field(l++, "seed", SEED); +#if defined(MUTA_FLIP) + ui_str_field(l++, "fbit", "yes"); +#else + ui_str_field(l++, "fbit", "no"); +#endif + ui_ulx_field(l++, "asav", AUTOSAVE_INTERVAL); + ui_str_field(l++, "arch", ARCH); + ui_ulx_field(l++, "size", MVEC_SIZE); + ui_ulx_field(l++, "syni", SYNC_INTERVAL); + ui_ulx_field(l++, "step", g_steps); + ui_ulx_field(l++, "sync", g_syncs); + ui_ulx_field(l++, "step", g_step_block); + + switch (g_page) { + case PAGE_CORE: + ui_print_core(l); + break; + case PAGE_PROCESS: + ui_print_process(l); + break; + case PAGE_WORLD: + ui_print_world(l); + break; + case PAGE_IPC: + ui_print_ipc(l); + break; + case PAGE_LOG: + ui_print_log(l); + break; + default: + break; + } +} + +// ---------------------------------------------------------------------------- +// Control function +// ---------------------------------------------------------------------------- +void ev_vscroll(int ev) { + switch (g_page) { + case PAGE_PROCESS: + switch (ev) { + case 'W': + g_proc_scroll += (LINES > PROC_PAGE_LINES) ? LINES - PROC_PAGE_LINES : 0; + break; + case 'S': + g_proc_scroll -= (LINES > PROC_PAGE_LINES) ? LINES - PROC_PAGE_LINES : 0; + break; + case 'w': + g_proc_scroll += 1; + break; + case 's': + g_proc_scroll -= 1; + break; + case 'q': + g_proc_scroll = 0; + break; + default: + break; + } + + break; + case PAGE_WORLD: { + switch (ev) { + case 'W': + g_wrld_pos += g_vsiz_rng; + break; + case 'S': + g_wrld_pos -= g_vsiz_rng; + break; + case 'w': + g_wrld_pos += g_vlin_rng; + break; + case 's': +#if defined(MVEC_LOOP) + g_wrld_pos -= g_vlin_rng; +#else + if (g_wrld_pos < g_vlin_rng) { + g_wrld_pos = 0; + } else { + g_wrld_pos -= g_vlin_rng; + } +#endif + break; + case 'q': + g_wrld_pos = 0; + break; + default: + break; + } + + break; + } + case PAGE_IPC: + switch (ev) { + case 'W': + g_ivpt_scroll += LINES; + break; + case 'S': + g_ivpt_scroll -= g_ivpt_scroll < (uint64_t)LINES ? g_ivpt_scroll : (uint64_t)LINES; + break; + case 'w': + g_ivpt_scroll += 1; + break; + case 's': + g_ivpt_scroll -= g_ivpt_scroll ? 1 : 0; + break; + case 'q': + g_ivpt_scroll = 0; + break; + } + + break; + case PAGE_LOG: + switch (ev) { + case 'W': + g_log_scroll += LINES; + g_log_scroll = g_log_scroll >= LOG_LINE_COUNT ? LOG_LINE_COUNT - 1 : g_log_scroll; + break; + case 'S': + g_log_scroll -= g_log_scroll < (uint64_t)LINES ? g_log_scroll : (uint64_t)LINES; + break; + case 'w': + g_log_scroll += 1; + g_log_scroll = g_log_scroll >= LOG_LINE_COUNT ? LOG_LINE_COUNT - 1 : g_log_scroll; + break; + case 's': + g_log_scroll -= g_log_scroll ? 1 : 0; + break; + case 'q': + g_log_scroll = 0; + break; + } + + break; + default: + break; + } +} + +void ev_hscroll(int ev) { + switch (g_page) { + case PAGE_PROCESS: { + uint64_t *hs_var = g_proc_genes ? &g_proc_gene_scroll : &g_proc_field_scroll; + + switch (ev) { + case 'A': + *hs_var = 0; + break; + case 'a': + *hs_var -= *hs_var ? 1 : 0; + break; + case 'd': + (*hs_var)++; + break; + default: + break; + } + + break; + } + + case PAGE_WORLD: + switch (ev) { + case 'a': +#if defined(MVEC_LOOP) + g_wrld_pos -= g_wrld_zoom; +#else + if (g_wrld_pos < g_wrld_zoom) { + g_wrld_pos = 0; + } else { + g_wrld_pos -= g_wrld_zoom; + } +#endif + break; + case 'd': + g_wrld_pos += g_wrld_zoom; + break; + default: + break; + } + + break; + default: + break; + } +} + +void ev_zoom(int ev) { + switch (g_page) { + case PAGE_WORLD: + switch (ev) { + case 'x': + g_wrld_zoom *= (g_vlin != 0 && g_vsiz_rng < MVEC_SIZE) ? 2 : 1; + ui_world_resize(); + break; + case 'z': + g_wrld_zoom /= (g_wrld_zoom != 1) ? 2 : 1; + ui_world_resize(); + break; + default: + break; + } + + break; + default: + break; + } +} + +void ev_move_wcursor(int ev) { + switch (ev) { + case KEY_UP: + g_wcursor_y -= (g_wcursor_y != 0) ? 1 : 0; + break; + case KEY_DOWN: + g_wcursor_y += (g_wcursor_y < LINES - 2) ? 1 : 0; + break; + case KEY_LEFT: + g_wcursor_x -= (g_wcursor_x != 0) ? 1 : 0; + break; + case KEY_RIGHT: + g_wcursor_x += ((uint64_t)g_wcursor_x < g_vlin - 1) ? 1 : 0; + break; + default: + break; + } +} + +void ev_sel_proc(int ev) { + if (g_page != PAGE_PROCESS && g_page != PAGE_WORLD) { + return; + } + + switch (ev) { + case 'o': + g_proc_selected -= 1; + break; + case 'p': + g_proc_selected += 1; + break; + case 'f': + g_proc_selected = g_cores[g_core].pfst; + break; + case 'l': + g_proc_selected = g_cores[g_core].plst; + break; + default: + break; + } +} + +void ev_goto_sel_proc() { + switch (g_page) { + case PAGE_PROCESS: + g_proc_scroll = g_proc_selected; + break; + case PAGE_WORLD: + g_wrld_pos = g_cores[g_core].pvec[g_proc_selected % g_cores[g_core].pcap].mb0a; + break; + default: + break; + } +} + +void ev_handle() { + int ev = getch(); + + if (g_page == PAGE_WORLD && g_wcursor_mode) { + switch (ev) { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + ev_move_wcursor(ev); + return; + case '\n': + if (g_wcursor_pointed != (uint64_t)(-1)) { + g_proc_selected = g_wcursor_pointed; + } + + break; + default: + break; + } + } + + switch (ev) { + case CTRL('c'): + g_exit = true; + break; + case KEY_SLEFT: + clear(); + g_core = (g_core + CORES - 1) % CORES; + break; + case KEY_SRIGHT: + clear(); + g_core = (g_core + 1) % CORES; + break; + case KEY_LEFT: + clear(); + g_page = (g_page + PAGE_COUNT - 1) % PAGE_COUNT; + break; + case KEY_RIGHT: + clear(); + g_page = (g_page + 1) % PAGE_COUNT; + break; + case KEY_RESIZE: + clear(); + ui_line_buff_resize(); + ui_world_resize(); + + if (g_vlin) { + while (g_vsiz_rng >= MVEC_SIZE * 2 && g_wrld_zoom != 1) { + g_wrld_zoom /= 2; + ui_world_resize(); + } + } + + g_wcursor_mode = false; + break; + case 'W': + case 'S': + case 'w': + case 's': + case 'q': + ev_vscroll(ev); + break; + case 'A': + case 'a': + case 'd': + ev_hscroll(ev); + break; + case 'z': + case 'x': + ev_zoom(ev); + break; + case 'o': + case 'p': + case 'f': + case 'l': + ev_sel_proc(ev); + break; + case 'k': + ev_goto_sel_proc(); + break; + case 'g': + if (g_page == PAGE_PROCESS) { + clear(); + g_proc_genes = !g_proc_genes; + } + + break; + case 'c': + if (g_page == PAGE_WORLD) { + clear(); + + if (g_vlin == 0) { + g_wcursor_mode = false; + } else { + g_wcursor_mode = !g_wcursor_mode; + } + } + + break; + case ' ': + g_running = !g_running; + nodelay(stdscr, g_running); + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '0': + if (!g_running) { + uint64_t cycles = 1 << (((ev - '0') ? (ev - '0') : 10) - 1); + salis_step(cycles); + } + + break; + default: + break; + } +} + +// ---------------------------------------------------------------------------- +// Main functions +// ---------------------------------------------------------------------------- +void init() { + setlocale(LC_ALL, ""); + + initscr(); + raw(); + noecho(); + curs_set(0); + keypad(stdscr, TRUE); + + start_color(); + init_color(COLOR_BLACK, 0, 0, 0); + + init_pair(PAIR_NORMAL, COLOR_WHITE, COLOR_BLACK); + init_pair(PAIR_HEADER, COLOR_BLUE, COLOR_BLACK); + init_pair(PAIR_WARN, COLOR_RED, COLOR_BLACK); + init_pair(PAIR_LIVE_PROC, COLOR_BLUE, COLOR_BLACK); + init_pair(PAIR_SELECTED_PROC, COLOR_YELLOW, COLOR_BLACK); + init_pair(PAIR_FREE_CELL, COLOR_BLACK, COLOR_BLUE); + init_pair(PAIR_ALLOC_CELL, COLOR_BLACK, COLOR_CYAN); + init_pair(PAIR_MEM_BLOCK_START, COLOR_BLACK, COLOR_WHITE); + init_pair(PAIR_SELECTED_MB1, COLOR_BLACK, COLOR_YELLOW); + init_pair(PAIR_SELECTED_MB2, COLOR_BLACK, COLOR_GREEN); + init_pair(PAIR_SELECTED_IP, COLOR_BLACK, COLOR_RED); + init_pair(PAIR_SELECTED_SP, COLOR_BLACK, COLOR_MAGENTA); + + g_info = ui_info_impl; + g_warn = ui_warn_impl; + +#if defined(COMMAND_NEW) + salis_init(); +#elif defined(COMMAND_LOAD) + salis_load(); +#endif + + g_wrld_zoom = 1; + g_step_block = 1; + + ui_line_buff_resize(); + ui_world_resize(); +} + +void exec() { + while (!g_exit) { + if (g_running) { + clock_t beg = clock(); + salis_step(g_step_block - (g_steps % g_step_block)); + clock_t end = clock(); + + if ((end - beg) < (CLOCKS_PER_SEC / MIN_FPS)) { + g_step_block <<= 1; + } + + if ((end - beg) >= (CLOCKS_PER_SEC / MAX_FPS) && g_step_block != 1) { + g_step_block >>= 1; + } + } + + ui_print(); + ev_handle(); + } +} + +void quit() { + gfx_free(); + ui_line_buff_free(); + salis_save(SIM_PATH); + salis_free(); + endwin(); +} + +int main() { + init(); + exec(); + quit(); + + return 0; +} diff --git a/ui/curses/ui.j2.c b/ui/curses/ui.j2.c deleted file mode 100644 index 2158eeb..0000000 --- a/ui/curses/ui.j2.c +++ /dev/null @@ -1,1386 +0,0 @@ -// Author: Paul Oliver -// Project: Salis - -// Implements a curses TUI for the Salis simulator. -// World view renders the contents of the VM memory buffer into a 7 channel image. -// It supports zooming in and out, condensing the state of several bytes of memory -// into single pixels (terminal cells). When zoomed in, each pixel represents a -// single byte in memory. - -{% set pane_width = 27 %} -{% set proc_field_width = 21 %} -{% set proc_page_lines = 12 %} - -{% set log_line_size = 1024 %} -{% set log_line_count = 1024 %} - -{% macro ctrl(x) %}('{{ x }}' & 0x1f){% endmacro %} - -{% if not args.optimized %} - {% set min_fps = 5 %} - {% set max_fps = 10 %} -{% else %} - {% set min_fps = 30 %} - {% set max_fps = 60 %} -{% endif %} - -// pages -enum { - PAGE_CORE, - PAGE_PROCESS, - PAGE_WORLD, - PAGE_IPC, - PAGE_LOG, - PAGE_COUNT, -}; - -// color pairs -enum { - PAIR_NOUSE, - PAIR_NORMAL, - PAIR_HEADER, - PAIR_WARN, - PAIR_LIVE_PROC, - PAIR_SELECTED_PROC, - PAIR_FREE_CELL, - PAIR_ALLOC_CELL, - PAIR_MEM_BLOCK_START, - PAIR_SELECTED_MB1, - PAIR_SELECTED_MB2, - PAIR_SELECTED_IP, - PAIR_SELECTED_SP, -}; - -// GFX globals -uint64_t g_gfx_vsiz; // zoom level -uint64_t *g_gfx_inst; // instruction channel -uint64_t *g_gfx_mall; // allocated state channel -uint64_t *g_gfx_mbst; // memory block start channel -uint64_t *g_gfx_mb0s; // selected organism's memory block #1 channel -uint64_t *g_gfx_mb1s; // selected organism's memory block #2 channel -uint64_t *g_gfx_ipas; // selected organism's IP channel -uint64_t *g_gfx_spas; // selected organism's SP channel - -// TUI globals -bool g_exit; -bool g_running; -unsigned g_core; -unsigned g_page; -bool g_proc_genes; -uint64_t g_proc_scroll; -uint64_t g_proc_field_scroll; -uint64_t g_proc_gene_scroll; -uint64_t g_proc_selected; -uint64_t g_wrld_pos; -uint64_t g_wrld_zoom; -bool g_wcursor_mode; -int g_wcursor_x; -int g_wcursor_y; -uint64_t g_wcursor_pointed; -uint64_t g_log_cnt; -unsigned g_log_ptr; -unsigned g_log_scroll; -bool g_log_warns[{{ log_line_count }}]; -time_t g_log_times[{{ log_line_count }}]; -char g_logs[{{ log_line_count }}][{{ log_line_size }}]; -uint64_t g_vlin; -uint64_t g_vsiz; -uint64_t g_vlin_rng; -uint64_t g_vsiz_rng; -uint64_t g_ivpt_scroll; -char *g_line_buff; -uint64_t g_step_block; - -const wchar_t *g_zoomed_symbols = ( - L"⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟" - L"⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿" - L"⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟" - L"⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿" -); - -// ---------------------------------------------------------------------------- -// GFX functions -// ---------------------------------------------------------------------------- -void gfx_init(uint64_t vsiz) { - assert(vsiz); - - g_gfx_vsiz = vsiz; - - g_gfx_inst = calloc(g_gfx_vsiz, sizeof(uint64_t)); - g_gfx_mall = calloc(g_gfx_vsiz, sizeof(uint64_t)); - g_gfx_mbst = calloc(g_gfx_vsiz, sizeof(uint64_t)); - g_gfx_mb0s = calloc(g_gfx_vsiz, sizeof(uint64_t)); - g_gfx_mb1s = calloc(g_gfx_vsiz, sizeof(uint64_t)); - g_gfx_ipas = calloc(g_gfx_vsiz, sizeof(uint64_t)); - g_gfx_spas = calloc(g_gfx_vsiz, sizeof(uint64_t)); - - assert(g_gfx_inst); - assert(g_gfx_mall); - assert(g_gfx_mbst); - assert(g_gfx_mb0s); - assert(g_gfx_mb1s); - assert(g_gfx_ipas); - assert(g_gfx_spas); -} - -void gfx_free() { - if (g_gfx_vsiz == 0) { - return; - } - - assert(g_gfx_inst); - assert(g_gfx_mall); - assert(g_gfx_mbst); - assert(g_gfx_mb0s); - assert(g_gfx_mb1s); - assert(g_gfx_ipas); - assert(g_gfx_spas); - - g_gfx_vsiz = 0; - - free(g_gfx_inst); - free(g_gfx_mall); - free(g_gfx_mbst); - free(g_gfx_mb0s); - free(g_gfx_mb1s); - free(g_gfx_ipas); - free(g_gfx_spas); - - g_gfx_inst = NULL; - g_gfx_mall = NULL; - g_gfx_mbst = NULL; - g_gfx_mb0s = NULL; - g_gfx_mb1s = NULL; - g_gfx_ipas = NULL; - g_gfx_spas = NULL; -} - -void gfx_resize(uint64_t vsiz) { - assert(vsiz); - - gfx_free(); - gfx_init(vsiz); -} - -void gfx_render_inst(const struct Core *core, uint64_t pos, uint64_t zoom) { - assert(core); - - for (uint64_t i = 0; i < g_gfx_vsiz; ++i) { - g_gfx_inst[i] = 0; - g_gfx_mall[i] = 0; - - for (uint64_t j = 0; j < zoom; ++j) { - uint64_t addr = pos + (i * zoom) + j; - - g_gfx_inst[i] += mvec_get_byte(core, addr); - g_gfx_mall[i] += mvec_is_alloc(core, addr) ? 1 : 0; - } - } -} - -void gfx_clear_array(uint64_t *arry) { - assert(arry); - memset(arry, 0, g_gfx_vsiz * sizeof(uint64_t)); -} - -{% if arch_vars.mvec_loop %} -void gfx_accumulate_pixel(uint64_t pos, uint64_t zoom, uint64_t pixa, uint64_t *arry) { - assert(arry); - - uint64_t beg_mod = pos % {{ mvec_size }}; - uint64_t end_mod = beg_mod + (g_gfx_vsiz * zoom); - uint64_t pix_mod = pixa % {{ mvec_size }}; - - {% if not args.optimized %} - uint64_t inc_cnt = 0; - {% endif %} - - while (pix_mod < end_mod) { - if (pix_mod >= beg_mod && pix_mod < end_mod) { - uint64_t pixi = (pix_mod - beg_mod) / zoom; - assert(pixi < g_gfx_vsiz); - arry[pixi]++; - - {% if not args.optimized %} - inc_cnt++; - {% endif %} - } - - pix_mod += {{ mvec_size }}; - } - - {% if not args.optimized %} - if (zoom != 1) { - assert(inc_cnt <= 2); - } - {% endif %} -} -{% endif %} - -{% if not arch_vars.mvec_loop %} -void gfx_accumulate_pixel(uint64_t pos, uint64_t zoom, uint64_t pixa, uint64_t *arry) { - assert(arry); - - uint64_t end = pos + (g_gfx_vsiz * zoom); - - if (pixa < pos || pixa >= end) { - return; - } - - uint64_t pixi = (pixa - pos) / zoom; - assert(pixi < g_gfx_vsiz); - arry[pixi]++; -} -{% endif %} - -void gfx_render_mbst(const struct Core *core, uint64_t pos, uint64_t zoom) { - assert(core); - - gfx_clear_array(g_gfx_mbst); - - for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) { - uint64_t mb0a = arch_proc_mb0_addr(core, pix); - uint64_t mb1a = arch_proc_mb1_addr(core, pix); - - gfx_accumulate_pixel(pos, zoom, mb0a, g_gfx_mbst); - gfx_accumulate_pixel(pos, zoom, mb1a, g_gfx_mbst); - } -} - -void gfx_render_mb0s(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { - assert(core); - - gfx_clear_array(g_gfx_mb0s); - - if (psel < core->pfst || psel > core->plst) { - return; - } - - uint64_t mb0a = arch_proc_mb0_addr(core, psel); - uint64_t mb0s = arch_proc_mb0_size(core, psel); - - for (uint64_t i = 0; i < mb0s; ++i) { - gfx_accumulate_pixel(pos, zoom, mb0a + i, g_gfx_mb0s); - } -} - -void gfx_render_mb1s(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { - assert(core); - - gfx_clear_array(g_gfx_mb1s); - - if (psel < core->pfst || psel > core->plst) { - return; - } - - uint64_t mb1a = arch_proc_mb1_addr(core, psel); - uint64_t mb1s = arch_proc_mb1_size(core, psel); - - for (uint64_t i = 0; i < mb1s; ++i) { - gfx_accumulate_pixel(pos, zoom, mb1a + i, g_gfx_mb1s); - } -} - -void gfx_render_ipas(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { - assert(core); - - gfx_clear_array(g_gfx_ipas); - - if (psel < core->pfst || psel > core->plst) { - return; - } - - uint64_t ipa = arch_proc_ip_addr(core, psel); - - gfx_accumulate_pixel(pos, zoom, ipa, g_gfx_ipas); -} - -void gfx_render_spas(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { - assert(core); - - gfx_clear_array(g_gfx_spas); - - if (psel < core->pfst || psel > core->plst) { - return; - } - - uint64_t spa = arch_proc_sp_addr(core, psel); - - gfx_accumulate_pixel(pos, zoom, spa, g_gfx_spas); -} - -void gfx_render(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t psel) { - assert(core); - - gfx_render_inst(core, pos, zoom); - gfx_render_mbst(core, pos, zoom); - gfx_render_mb0s(core, pos, zoom, psel); - gfx_render_mb1s(core, pos, zoom, psel); - gfx_render_ipas(core, pos, zoom, psel); - gfx_render_spas(core, pos, zoom, psel); -} - -// ---------------------------------------------------------------------------- -// TUI generic functions -// ---------------------------------------------------------------------------- -void ui_line_buff_free() { - if (g_line_buff) { - free(g_line_buff); - } - - g_line_buff = NULL; -} - -void ui_line_buff_resize() { - ui_line_buff_free(); - - g_line_buff = calloc(COLS + 1, sizeof(char)); -} - -void ui_line(bool clear, int line, int color, int attr, const char *format, ...) { - assert(line >= 0); - assert(format); - - if (line >= LINES) { - return; - } - - if (clear) { - move(line, 0); - clrtoeol(); - } - - va_list args; - - attron(COLOR_PAIR(color) | attr); - va_start(args, format); - - vsnprintf(g_line_buff, COLS, format, args); - mvprintw(line, 1, g_line_buff); - - va_end(args); - attroff(COLOR_PAIR(color) | attr); -} - -void ui_clear_line(int l) { - ui_line(true, l, PAIR_NORMAL, A_NORMAL, ""); -} - -void ui_field(int line, int col, int color, int attr, const char *format, ...) { - assert(line >= 0); - assert(col >= 0); - assert(format); - - if (line >= LINES || col >= COLS) { - return; - } - - va_list args; - - attron(COLOR_PAIR(color) | attr); - va_start(args, format); - - vsnprintf(g_line_buff, COLS - col, format, args); - mvprintw(line, col, g_line_buff); - - va_end(args); - attroff(COLOR_PAIR(color) | attr); -} - -void ui_str_field(int l, const char *label, const char *value) { - assert(label); - assert(value); - ui_line(false, l, PAIR_NORMAL, A_NORMAL, "%s : %18s", label, value); -} - -void ui_ulx_field(int l, const char *label, uint64_t value) { - assert(label); - ui_line(false, l, PAIR_NORMAL, A_NORMAL, "%-4s : %#18lx", label, value); -} - -// ---------------------------------------------------------------------------- -// Core page functions -// ---------------------------------------------------------------------------- -void ui_print_core(int l) { - ui_line(false, ++l, PAIR_HEADER, A_BOLD, "CORE [%d]", g_core); - ui_ulx_field(++l, "cycl", g_cores[g_core].cycl); - ui_ulx_field(++l, "mall", g_cores[g_core].mall); - ui_ulx_field(++l, "mut0", g_cores[g_core].muta[0]); - ui_ulx_field(++l, "mut1", g_cores[g_core].muta[1]); - ui_ulx_field(++l, "mut2", g_cores[g_core].muta[2]); - ui_ulx_field(++l, "mut3", g_cores[g_core].muta[3]); - ui_ulx_field(++l, "pnum", g_cores[g_core].pnum); - ui_ulx_field(++l, "pcap", g_cores[g_core].pcap); - ui_ulx_field(++l, "pfst", g_cores[g_core].pfst); - ui_ulx_field(++l, "plst", g_cores[g_core].plst); - ui_ulx_field(++l, "pcur", g_cores[g_core].pcur); - ui_ulx_field(++l, "psli", g_cores[g_core].psli); - ui_ulx_field(++l, "ivpt", g_cores[g_core].ivpt); - - ++l; - - {% if arch_vars.core_fields|length %} - ui_line(false, ++l, PAIR_HEADER, A_BOLD, "ARCH SPECIFIC"); - {% for type, name, print in arch_vars.core_fields if print %} - {% if type == "uint64_t" %} - ui_ulx_field(++l, "{{ name }}", g_cores[g_core].{{ name }}); - {% endif %} - {% endfor %} - {% endif %} -} - -// ---------------------------------------------------------------------------- -// Process page functions -// ---------------------------------------------------------------------------- -int ui_proc_pair(uint64_t pix) { - if (pix == g_proc_selected) { - return PAIR_SELECTED_PROC; - } else if (mvec_proc_is_live(&g_cores[g_core], pix)) { - return PAIR_LIVE_PROC; - } else { - return PAIR_NORMAL; - } -} - -const char *ui_proc_state(uint64_t pix) { - return mvec_proc_is_live(&g_cores[g_core], pix) ? "live" : "dead"; -} - -void ui_print_process_genome_header(int l) { - ui_line(false, l++, PAIR_NORMAL, A_NORMAL, "%s : %18s : %s", "stat", "pix", "genome"); -} - -void ui_print_process_gene(int l, int gcol, uint64_t gidx, uint64_t mba, uint64_t pix, int pair) { - assert(gcol >= {{ pane_width }} + 2); - assert(gcol < COLS); - assert(mvec_proc_is_live(&g_cores[g_core], pix)); - assert(pair == PAIR_SELECTED_MB1 || pair == PAIR_SELECTED_MB2); - - const struct Core *core = &g_cores[g_core]; - - uint64_t addr = mba + gidx; - uint8_t byte = mvec_get_byte(core, addr); - - wchar_t gsym[2] = { arch_symbol(byte), L'\0' }; - cchar_t cchar = { 0 }; - - int pair_cell; - - if (arch_proc_ip_addr(core, pix) == addr) { - pair_cell = PAIR_SELECTED_IP; - } else if (arch_proc_sp_addr(core, pix) == addr) { - pair_cell = PAIR_SELECTED_SP; - } else { - pair_cell = pair; - } - - setcchar(&cchar, gsym, 0, pair_cell, NULL); - mvadd_wch(l, gcol, &cchar); -} - -void ui_print_process_genes(int l, uint64_t pix) { - ui_line(true, l, ui_proc_pair(pix), A_NORMAL, "%s : %#18lx :", ui_proc_state(pix), pix); - - if (!mvec_proc_is_live(&g_cores[g_core], pix)) { - return; - } - - const struct Core *core = &g_cores[g_core]; - - int scol = {{ pane_width }} + 2; - int gcol = scol - g_proc_gene_scroll; - uint64_t mb0a = arch_proc_mb0_addr(core, pix); - uint64_t mb0s = arch_proc_mb0_size(core, pix); - uint64_t mb1a = arch_proc_mb1_addr(core, pix); - uint64_t mb1s = arch_proc_mb1_size(core, pix); - - for (uint64_t gidx = 0; gidx < mb0s && gcol < COLS; ++gidx, ++gcol) { - if (gcol >= scol) { - ui_print_process_gene(l, gcol, gidx, mb0a, pix, PAIR_SELECTED_MB1); - } - } - - for (uint64_t gidx = 0; gidx < mb1s && gcol < COLS; ++gidx, ++gcol) { - if (gcol >= scol) { - ui_print_process_gene(l, gcol, gidx, mb1a, pix, PAIR_SELECTED_MB2); - } - } - - clrtoeol(); -} - -void ui_print_process_field_header_element(int l, int fidx, const char *name) { - assert(fidx >= 0); - assert(name); - - if (fidx < (int)g_proc_field_scroll) { - return; - } - - int foff = fidx - g_proc_field_scroll; - int fcol = foff * {{ proc_field_width }} + {{ pane_width }} - 1; - - ui_field(l, fcol, PAIR_NORMAL, A_NORMAL, " : %18s", name); -} - -void ui_print_process_field_header(int l) { - ui_line(true, l, PAIR_NORMAL, A_NORMAL, "%s : %18s", "stat", "pix"); - - int fidx = 0; - - {% for _, val in arch_vars.proc_fields %} - ui_print_process_field_header_element(l, fidx++, "{{ val }}"); - {% endfor %} -} - -void ui_print_process_field_element(int l, int fidx, int fclr, uint64_t field) { - assert(fidx >= 0); - - if (fidx < (int)g_proc_field_scroll) { - return; - } - - int foff = fidx - g_proc_field_scroll; - int fcol = foff * {{ proc_field_width }} + {{ pane_width }} - 1; - - ui_field(l, fcol, fclr, A_NORMAL, " : %#18lx", field); -} - -void ui_print_process_fields(int l, uint64_t pix) { - ui_line(true, l, ui_proc_pair(pix), A_NORMAL, "%s : %#18lx", ui_proc_state(pix), pix); - - const struct Proc *proc = proc_get(&g_cores[g_core], pix); - - int fidx = 0; - int fclr = ui_proc_pair(pix); - - {% for _, val in arch_vars.proc_fields %} - ui_print_process_field_element(l, fidx++, fclr, proc->{{ val }}); - {% endfor %} -} - -void ui_print_process(int l) { - l++; - - ui_line(true, l++, PAIR_HEADER, A_BOLD, - "PROCESS [vs:%#lx | ps:%#lx | pf:%#lx | pl:%#lx | fs:%#lx | gs:%#lx]", - g_proc_scroll, - g_proc_selected, - g_cores[g_core].pfst, - g_cores[g_core].plst, - g_proc_field_scroll, - g_proc_gene_scroll - ); - - uint64_t pix = g_proc_scroll; - - if (g_proc_genes) { - ui_print_process_genome_header(l++); - - while (l < LINES) { - ui_print_process_genes(l++, pix++); - } - } else { - ui_print_process_field_header(l++); - - while (l < LINES) { - ui_print_process_fields(l++, pix++); - } - } -} - -// ---------------------------------------------------------------------------- -// World page functions -// ---------------------------------------------------------------------------- -void ui_world_resize() { - assert(g_wrld_zoom); - - g_vlin = 0; - g_vsiz = 0; - g_vlin_rng = 0; - g_vsiz_rng = 0; - - if (COLS > {{ pane_width }}) { - g_vlin = COLS - {{ pane_width }}; - g_vsiz = LINES * g_vlin; - g_vlin_rng = g_vlin * g_wrld_zoom; - g_vsiz_rng = g_vsiz * g_wrld_zoom; - - gfx_resize(g_vsiz); - } -} - -{% if arch_vars.mvec_loop %} -void ui_print_cell(uint64_t i, uint64_t r, uint64_t x, uint64_t y) { -{% else %} -void ui_print_cell(uint64_t i, uint64_t r, uint64_t x, uint64_t y, uint64_t a) { -{% endif %} - wchar_t inst_nstr[2] = { L'\0', L'\0' }; - cchar_t cchar = { 0 }; - uint64_t inst_avrg = g_gfx_inst[i] / g_wrld_zoom; - - if (g_wrld_zoom == 1) { - inst_nstr[0] = arch_symbol((uint8_t)inst_avrg); - } else { - inst_nstr[0] = g_zoomed_symbols[(uint8_t)inst_avrg]; - } - - int pair_cell; - - {% if arch_vars.mvec_loop %} - if (g_wcursor_mode && r == (uint64_t)g_wcursor_x && y == (uint64_t)g_wcursor_y) { - {% else %} - if (a >= {{ mvec_size }} || (g_wcursor_mode && r == (uint64_t)g_wcursor_x && y == (uint64_t)g_wcursor_y)) { - {% endif %} - pair_cell = PAIR_NORMAL; - } else if (g_wcursor_mode && r == (uint64_t)g_wcursor_x && y == (uint64_t)g_wcursor_y) { - pair_cell = PAIR_NORMAL; - } else if (g_gfx_ipas[i] != 0) { - pair_cell = PAIR_SELECTED_IP; - } else if (g_gfx_spas[i] != 0) { - pair_cell = PAIR_SELECTED_SP; - } else if (g_gfx_mb0s[i] != 0) { - pair_cell = PAIR_SELECTED_MB1; - } else if (g_gfx_mb1s[i] != 0) { - pair_cell = PAIR_SELECTED_MB2; - } else if (g_gfx_mbst[i] != 0) { - pair_cell = PAIR_MEM_BLOCK_START; - } else if (g_gfx_mall[i] != 0) { - pair_cell = PAIR_ALLOC_CELL; - } else { - pair_cell = PAIR_FREE_CELL; - } - - setcchar(&cchar, inst_nstr, 0, pair_cell, NULL); - mvadd_wch(y, x, &cchar); -} - -void ui_print_wcursor_bar() { - ui_clear_line(LINES - 1); - - const struct Core *core = &g_cores[g_core]; - - char cownr[{{ proc_field_width }}]; - - uint64_t cpos = g_vlin * g_wcursor_y + g_wcursor_x; - uint64_t caddr = cpos * g_wrld_zoom + g_wrld_pos; - uint8_t cbyte = mvec_get_byte(core, caddr); - - if (mvec_is_alloc(core, caddr)) { - g_wcursor_pointed = mvec_get_owner(core, caddr); - snprintf(cownr, {{ proc_field_width }}, "%#lx", g_wcursor_pointed); - } else { - g_wcursor_pointed = (uint64_t)(-1); - snprintf(cownr, {{ proc_field_width }}, "-"); - } - - mvprintw( - LINES - 1, - 1, - "cursor | x:%#x | y:%#x | addr:%#lx | isum:%#lx | iavr:%#lx | mall:%#lx | mbst:%#lx | mnem:<%s> | ownr:%s", - g_wcursor_x, - g_wcursor_y, - caddr, - g_gfx_inst[cpos], - g_gfx_inst[cpos] / g_wrld_zoom, - g_gfx_mall[cpos], - g_gfx_mbst[cpos], - arch_mnemonic(cbyte), - cownr - ); -} - -void ui_print_world(int l) { - l++; - - ui_line(false, l++, PAIR_HEADER, A_BOLD, "WORLD"); - ui_ulx_field(l++, "wrlp", g_wrld_pos); - ui_ulx_field(l++, "wrlz", g_wrld_zoom); - ui_ulx_field(l++, "psel", g_proc_selected); - ui_ulx_field(l++, "pabs", g_proc_selected % g_cores[g_core].pcap); - ui_ulx_field(l++, "vrng", g_vsiz_rng); - ui_str_field(l++, "curs", g_wcursor_mode ? "on" : "off"); - - l++; - - ui_line(false, l++, PAIR_HEADER, A_BOLD, "SELECTED"); - - const struct Proc *psel = proc_get(&g_cores[g_core], g_proc_selected); - - {% for _, val in arch_vars.proc_fields %} - ui_ulx_field(l++, "{{ val }}", psel->{{ val }}); - {% endfor %} - - if (!g_vlin) { - return; - } - - gfx_render(&g_cores[g_core], g_wrld_pos, g_wrld_zoom, g_proc_selected); - - if (g_wcursor_mode) { - int xmax = g_vlin - 1; - int ymax = LINES - 2; - - g_wcursor_x = (g_wcursor_x < xmax) ? g_wcursor_x : xmax; - g_wcursor_y = (g_wcursor_y < ymax) ? g_wcursor_y : ymax; - } - - for (uint64_t i = 0; i < g_vsiz; ++i) { - uint64_t r = i % g_vlin; - uint64_t x = r + {{ pane_width }}; - uint64_t y = i / g_vlin; - - {% if arch_vars.mvec_loop %} - ui_print_cell(i, r, x, y); - {% else %} - uint64_t a = g_wrld_pos + (i * g_wrld_zoom); - - ui_print_cell(i, r, x, y, a); - {% endif %} - } - - if (g_wcursor_mode) { - ui_print_wcursor_bar(); - } -} - -// ---------------------------------------------------------------------------- -// IPC page functions -// ---------------------------------------------------------------------------- -void ui_print_ipc_field(int l, uint64_t i, int color) { - uint8_t iinst = g_cores[g_core].iviv[i]; - uint64_t iaddr = g_cores[g_core].ivav[i]; - - ui_field(l, {{ pane_width }}, color, A_NORMAL, "%#18x : %#18x : %#18x", i, iinst, iaddr); -} - -void ui_print_ipc_data() { - ui_field(0, {{ pane_width }}, PAIR_NORMAL, A_NORMAL, "%18s : %18s : %18s", "ipci", "inst", "addr"); - - int l = 1 - g_ivpt_scroll; - - for (uint64_t i = 0; i < {{ sync_interval }}; ++i) { - if (i == g_cores[g_core].ivpt) { - if (l >= 1) { - ui_print_ipc_field(l++, i, PAIR_SELECTED_PROC); - } - - continue; - } - - uint8_t iinst = g_cores[g_core].iviv[i]; - - if ((iinst & {{ ipc_flag }}) != 0) { - if (l >= 1) { - ui_print_ipc_field(l++, i, PAIR_LIVE_PROC); - } - - continue; - } - } - - for (; l < LINES; ++l) { - if (l >= 1) { - move(l, {{ pane_width }}); - clrtoeol(); - } - } -} - -void ui_print_ipc(int l) { - l++; - - const struct Core *core = &g_cores[g_core]; - - ui_line(true, l++, PAIR_HEADER, A_BOLD, "IPC [%#lx]", g_ivpt_scroll); - ui_ulx_field(l++, "ivpt", core->ivpt); - ui_ulx_field(l++, "ivpi", core->iviv[core->ivpt]); - ui_ulx_field(l++, "ivpa", core->ivav[core->ivpt]); - - ui_print_ipc_data(); -} - -// ---------------------------------------------------------------------------- -// Log page functions -// ---------------------------------------------------------------------------- -void ui_info_impl(const char *format, ...) { - g_log_warns[g_log_ptr] = false; - g_log_times[g_log_ptr] = time(NULL); - - va_list args; - va_start(args, format); - vsnprintf(g_logs[g_log_ptr], {{ log_line_size }}, format, args); - va_end(args); - - g_log_cnt++; - g_log_ptr = (g_log_ptr + 1) % {{ log_line_count }}; -} - -void ui_warn_impl(const char *format, ...) { - g_log_warns[g_log_ptr] = true; - g_log_times[g_log_ptr] = time(NULL); - - va_list args; - va_start(args, format); - vsnprintf(g_logs[g_log_ptr], {{ log_line_size }}, format, args); - va_end(args); - - g_log_cnt++; - g_log_ptr = (g_log_ptr + 1) % {{ log_line_count }}; -} - -void ui_clear_log_line(int line) { - assert(line >= 0 && line < LINES); - move(line, {{ pane_width }}); - clrtoeol(); -} - -void ui_print_log_line(unsigned lptr, int line) { - assert(lptr < {{ log_line_count }}); - assert(line >= 0 && line < LINES); - ui_clear_log_line(line); - - // Prints a log entry - if (strlen(g_logs[lptr])) { - struct tm tm = *localtime(&g_log_times[lptr]); - - // Timestamp - ui_field( - line, - {{ pane_width }}, - PAIR_NORMAL, - A_NORMAL, - ": %d-%02d-%02d %02d:%02d:%02d", - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday, - tm.tm_hour, - tm.tm_min, - tm.tm_sec - ); - - // Level - ui_field( - line, - {{ pane_width }} + 22, - g_log_warns[lptr] ? PAIR_WARN : PAIR_HEADER, - A_NORMAL, - g_log_warns[lptr] ? "WARN:" : "INFO:" - ); - - // Message - ui_field( - line, - {{ pane_width }} + 28, - PAIR_NORMAL, - A_NORMAL, - g_logs[lptr] - ); - } -} - -void ui_print_log(int l) { - l++; - - ui_line(true, l++, PAIR_HEADER, A_BOLD, "LOG"); - ui_ulx_field(l++, "lscr", g_log_scroll); - ui_ulx_field(l++, "lcnt", g_log_cnt); - ui_ulx_field(l++, "lptr", g_log_ptr); - - unsigned lptr = g_log_ptr; - int line = LINES + g_log_scroll; - - while (line) { - lptr = (lptr - 1 + {{ log_line_count }}) % {{ log_line_count }}; - line--; - - if (line < LINES) { - ui_print_log_line(lptr, line); - } - - if (lptr == g_log_ptr) { - break; - } - } - - while (line) { - line--; - ui_clear_log_line(line); - } -} - -// ---------------------------------------------------------------------------- -// Main print function -// ---------------------------------------------------------------------------- -void ui_print() { - int l = 1; - - ui_line(false, l++, PAIR_HEADER, A_BOLD, "SALIS [%d:%d]", g_core, {{ args.cores }}); - ui_str_field(l++, "name", "{{ args.name }}"); - ui_ulx_field(l++, "seed", {{ args.seed }}); - ui_str_field(l++, "fbit", "{{ "yes" if args.muta_flip else "no" }}"); - ui_ulx_field(l++, "asav", {{ auto_save_interval }}); - ui_str_field(l++, "arch", "{{ args.arch }}"); - ui_ulx_field(l++, "size", {{ mvec_size }}); - ui_ulx_field(l++, "syni", {{ sync_interval }}); - ui_ulx_field(l++, "step", g_steps); - ui_ulx_field(l++, "sync", g_syncs); - ui_ulx_field(l++, "step", g_step_block); - - switch (g_page) { - case PAGE_CORE: - ui_print_core(l); - break; - case PAGE_PROCESS: - ui_print_process(l); - break; - case PAGE_WORLD: - ui_print_world(l); - break; - case PAGE_IPC: - ui_print_ipc(l); - break; - case PAGE_LOG: - ui_print_log(l); - break; - default: - break; - } -} - -// ---------------------------------------------------------------------------- -// Control function -// ---------------------------------------------------------------------------- -void ev_vscroll(int ev) { - switch (g_page) { - case PAGE_PROCESS: - switch (ev) { - case 'W': - g_proc_scroll += (LINES > {{ proc_page_lines }}) ? LINES - {{ proc_page_lines }} : 0; - break; - case 'S': - g_proc_scroll -= (LINES > {{ proc_page_lines }}) ? LINES - {{ proc_page_lines }} : 0; - break; - case 'w': - g_proc_scroll += 1; - break; - case 's': - g_proc_scroll -= 1; - break; - case 'q': - g_proc_scroll = 0; - break; - default: - break; - } - - break; - case PAGE_WORLD: { - switch (ev) { - case 'W': - g_wrld_pos += g_vsiz_rng; - break; - case 'S': - g_wrld_pos -= g_vsiz_rng; - break; - case 'w': - g_wrld_pos += g_vlin_rng; - break; - case 's': - {% if arch_vars.mvec_loop %} - g_wrld_pos -= g_vlin_rng; - {% else %} - if (g_wrld_pos < g_vlin_rng) { - g_wrld_pos = 0; - } else { - g_wrld_pos -= g_vlin_rng; - } - {% endif %} - break; - case 'q': - g_wrld_pos = 0; - break; - default: - break; - } - - break; - } - case PAGE_IPC: - switch (ev) { - case 'W': - g_ivpt_scroll += LINES; - break; - case 'S': - g_ivpt_scroll -= g_ivpt_scroll < (uint64_t)LINES ? g_ivpt_scroll : (uint64_t)LINES; - break; - case 'w': - g_ivpt_scroll += 1; - break; - case 's': - g_ivpt_scroll -= g_ivpt_scroll ? 1 : 0; - break; - case 'q': - g_ivpt_scroll = 0; - break; - } - - break; - case PAGE_LOG: - switch (ev) { - case 'W': - g_log_scroll += LINES; - g_log_scroll = g_log_scroll >= {{ log_line_count }} ? {{ log_line_count }} - 1 : g_log_scroll; - break; - case 'S': - g_log_scroll -= g_log_scroll < (uint64_t)LINES ? g_log_scroll : (uint64_t)LINES; - break; - case 'w': - g_log_scroll += 1; - g_log_scroll = g_log_scroll >= {{ log_line_count }} ? {{ log_line_count }} - 1 : g_log_scroll; - break; - case 's': - g_log_scroll -= g_log_scroll ? 1 : 0; - break; - case 'q': - g_log_scroll = 0; - break; - } - - break; - default: - break; - } -} - -void ev_hscroll(int ev) { - switch (g_page) { - case PAGE_PROCESS: { - uint64_t *hs_var = g_proc_genes ? &g_proc_gene_scroll : &g_proc_field_scroll; - - switch (ev) { - case 'A': - *hs_var = 0; - break; - case 'a': - *hs_var -= *hs_var ? 1 : 0; - break; - case 'd': - (*hs_var)++; - break; - default: - break; - } - - break; - } - - case PAGE_WORLD: - switch (ev) { - case 'a': - {% if arch_vars.mvec_loop %} - g_wrld_pos -= g_wrld_zoom; - {% else %} - if (g_wrld_pos < g_wrld_zoom) { - g_wrld_pos = 0; - } else { - g_wrld_pos -= g_wrld_zoom; - } - {% endif %} - break; - case 'd': - g_wrld_pos += g_wrld_zoom; - break; - default: - break; - } - - break; - default: - break; - } -} - -void ev_zoom(int ev) { - switch (g_page) { - case PAGE_WORLD: - switch (ev) { - case 'x': - g_wrld_zoom *= (g_vlin != 0 && g_vsiz_rng < {{ mvec_size }}) ? 2 : 1; - ui_world_resize(); - break; - case 'z': - g_wrld_zoom /= (g_wrld_zoom != 1) ? 2 : 1; - ui_world_resize(); - break; - default: - break; - } - - break; - default: - break; - } -} - -void ev_move_wcursor(int ev) { - switch (ev) { - case KEY_UP: - g_wcursor_y -= (g_wcursor_y != 0) ? 1 : 0; - break; - case KEY_DOWN: - g_wcursor_y += (g_wcursor_y < LINES - 2) ? 1 : 0; - break; - case KEY_LEFT: - g_wcursor_x -= (g_wcursor_x != 0) ? 1 : 0; - break; - case KEY_RIGHT: - g_wcursor_x += ((uint64_t)g_wcursor_x < g_vlin - 1) ? 1 : 0; - break; - default: - break; - } -} - -void ev_sel_proc(int ev) { - if (g_page != PAGE_PROCESS && g_page != PAGE_WORLD) { - return; - } - - switch (ev) { - case 'o': - g_proc_selected -= 1; - break; - case 'p': - g_proc_selected += 1; - break; - case 'f': - g_proc_selected = g_cores[g_core].pfst; - break; - case 'l': - g_proc_selected = g_cores[g_core].plst; - break; - default: - break; - } -} - -void ev_goto_sel_proc() { - switch (g_page) { - case PAGE_PROCESS: - g_proc_scroll = g_proc_selected; - break; - case PAGE_WORLD: - g_wrld_pos = g_cores[g_core].pvec[g_proc_selected % g_cores[g_core].pcap].mb0a; - break; - default: - break; - } -} - -void ev_handle() { - int ev = getch(); - - if (g_page == PAGE_WORLD && g_wcursor_mode) { - switch (ev) { - case KEY_UP: - case KEY_DOWN: - case KEY_LEFT: - case KEY_RIGHT: - ev_move_wcursor(ev); - return; - case '\n': - if (g_wcursor_pointed != (uint64_t)(-1)) { - g_proc_selected = g_wcursor_pointed; - } - - break; - default: - break; - } - } - - switch (ev) { - case {{ ctrl('c') }}: - g_exit = true; - break; - case KEY_SLEFT: - clear(); - g_core = (g_core + {{ args.cores }} - 1) % {{ args.cores }}; - break; - case KEY_SRIGHT: - clear(); - g_core = (g_core + 1) % {{ args.cores }}; - break; - case KEY_LEFT: - clear(); - g_page = (g_page + PAGE_COUNT - 1) % PAGE_COUNT; - break; - case KEY_RIGHT: - clear(); - g_page = (g_page + 1) % PAGE_COUNT; - break; - case KEY_RESIZE: - clear(); - ui_line_buff_resize(); - ui_world_resize(); - - if (g_vlin) { - while (g_vsiz_rng >= {{ mvec_size }} * 2 && g_wrld_zoom != 1) { - g_wrld_zoom /= 2; - ui_world_resize(); - } - } - - g_wcursor_mode = false; - break; - case 'W': - case 'S': - case 'w': - case 's': - case 'q': - ev_vscroll(ev); - break; - case 'A': - case 'a': - case 'd': - ev_hscroll(ev); - break; - case 'z': - case 'x': - ev_zoom(ev); - break; - case 'o': - case 'p': - case 'f': - case 'l': - ev_sel_proc(ev); - break; - case 'k': - ev_goto_sel_proc(); - break; - case 'g': - if (g_page == PAGE_PROCESS) { - clear(); - g_proc_genes = !g_proc_genes; - } - - break; - case 'c': - if (g_page == PAGE_WORLD) { - clear(); - - if (g_vlin == 0) { - g_wcursor_mode = false; - } else { - g_wcursor_mode = !g_wcursor_mode; - } - } - - break; - case ' ': - g_running = !g_running; - nodelay(stdscr, g_running); - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - if (!g_running) { - uint64_t cycles = 1 << (((ev - '0') ? (ev - '0') : 10) - 1); - salis_step(cycles); - } - - break; - default: - break; - } -} - -// ---------------------------------------------------------------------------- -// Main functions -// ---------------------------------------------------------------------------- -void init() { - setlocale(LC_ALL, ""); - - initscr(); - raw(); - noecho(); - curs_set(0); - keypad(stdscr, TRUE); - - start_color(); - init_color(COLOR_BLACK, 0, 0, 0); - - init_pair(PAIR_NORMAL, COLOR_WHITE, COLOR_BLACK ); - init_pair(PAIR_HEADER, COLOR_BLUE, COLOR_BLACK ); - init_pair(PAIR_WARN, COLOR_RED, COLOR_BLACK ); - init_pair(PAIR_LIVE_PROC, COLOR_BLUE, COLOR_BLACK ); - init_pair(PAIR_SELECTED_PROC, COLOR_YELLOW, COLOR_BLACK ); - init_pair(PAIR_FREE_CELL, COLOR_BLACK, COLOR_BLUE ); - init_pair(PAIR_ALLOC_CELL, COLOR_BLACK, COLOR_CYAN ); - init_pair(PAIR_MEM_BLOCK_START, COLOR_BLACK, COLOR_WHITE ); - init_pair(PAIR_SELECTED_MB1, COLOR_BLACK, COLOR_YELLOW ); - init_pair(PAIR_SELECTED_MB2, COLOR_BLACK, COLOR_GREEN ); - init_pair(PAIR_SELECTED_IP, COLOR_BLACK, COLOR_RED ); - init_pair(PAIR_SELECTED_SP, COLOR_BLACK, COLOR_MAGENTA); - - // Install loggers - g_info = ui_info_impl; - g_warn = ui_warn_impl; - - {% if args.command == "new" %} - salis_init(); - {% elif args.command == "load" %} - salis_load(); - {% endif %} - - g_wrld_zoom = 1; - g_step_block = 1; - - ui_line_buff_resize(); - ui_world_resize(); -} - -void exec() { - while (!g_exit) { - if (g_running) { - clock_t beg = clock(); - salis_step(g_step_block - (g_steps % g_step_block)); - clock_t end = clock(); - - if ((end - beg) < (CLOCKS_PER_SEC / {{ min_fps }})) { - g_step_block <<= 1; - } - - if ((end - beg) >= (CLOCKS_PER_SEC / {{ max_fps }}) && g_step_block != 1) { - g_step_block >>= 1; - } - } - - ui_print(); - ev_handle(); - } -} - -void quit() { - gfx_free(); - ui_line_buff_free(); - salis_save("{{ sim_path }}"); - salis_free(); - endwin(); -} - -int main() { - init(); - exec(); - quit(); - - return 0; -} diff --git a/ui/curses/ui_vars.py b/ui/curses/ui_vars.py index 97d2c07..54f62e3 100644 --- a/ui/curses/ui_vars.py +++ b/ui/curses/ui_vars.py @@ -1,5 +1,5 @@ -def gen_ui_vars(_): - return { - "flags": ["-lncurses", "-DNCURSES_WIDECHAR=1"], - "includes": ["curses.h", "locale.h", "time.h"], - } +class UIVars: + def __init__(self, _): + self.includes = {"curses.h", "locale.h", "time.h"} + self.defines = {"-DNCURSES_WIDECHAR=1"} + self.links = {"-lncurses"} diff --git a/ui/daemon/ui.c b/ui/daemon/ui.c new file mode 100644 index 0000000..1f6c35c --- /dev/null +++ b/ui/daemon/ui.c @@ -0,0 +1,79 @@ +volatile bool g_running; +uint64_t g_step_block; + +void info_impl(const char *restrict fmt, ...) { + assert(fmt); + printf("\033[1;34m[INFO]\033[0m "); + + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + printf("\n"); +} + +void warn_impl(const char *restrict fmt, ...) { + assert(fmt); + printf("\033[1;33m[WARN]\033[0m "); + + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + printf("\n"); +} + +void sig_handler(int signo) { + (void)signo; + + if (g_running) { + g_warn("Signal received, will stop simulator soon..."); + g_running = false; + } +} + +void step_block() { + clock_t beg = clock(); + salis_step(g_step_block - (g_steps % g_step_block)); + clock_t end = clock(); + + if ((end - beg) < (CLOCKS_PER_SEC * 4)) { + g_step_block <<= 1; + } + + if ((end - beg) >= (CLOCKS_PER_SEC * 2) && g_step_block != 1) { + g_step_block >>= 1; + } + + g_info("Simulator running on step '%#lx'", g_steps); +} + +int main() { + g_info = info_impl; + g_warn = warn_impl; + +#if defined(COMMAND_NEW) + salis_init(); +#elif defined(COMMAND_LOAD) + salis_load(); +#endif + + g_running = true; + g_step_block = 1; + + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + while (g_running) { + step_block(); + } + + g_info("Saving simulation..."); + salis_save(SIM_PATH); + salis_free(); + + g_info("Exiting salis..."); + return 0; +} diff --git a/ui/daemon/ui.j2.c b/ui/daemon/ui.j2.c deleted file mode 100644 index 02df79b..0000000 --- a/ui/daemon/ui.j2.c +++ /dev/null @@ -1,86 +0,0 @@ -// Author: Paul Oliver -// Project: Salis - -// Lightweight UI for the Salis simulator with minimal output. -// Can be interrupted through OS signals. -// Ideal for running Salis in the background. - -volatile bool g_running; -uint64_t g_step_block; - -void info_impl(const char *restrict fmt, ...) { - assert(fmt); - printf("\033[1;34mINFO:\033[0m "); - - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - - printf("\n"); -} - -void warn_impl(const char *restrict fmt, ...) { - assert(fmt); - printf("\033[1;31mWARN:\033[0m "); - - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - - printf("\n"); -} - -void sig_handler(int signo) { - (void)signo; - - if (g_running) { - g_warn("Signal received, will stop simulator soon..."); - g_running = false; - } -} - -void step_block() { - clock_t beg = clock(); - salis_step(g_step_block - (g_steps % g_step_block)); - clock_t end = clock(); - - if ((end - beg) < (CLOCKS_PER_SEC * 4)) { - g_step_block <<= 1; - } - - if ((end - beg) >= (CLOCKS_PER_SEC * 2) && g_step_block != 1) { - g_step_block >>= 1; - } - - g_info("Simulator running on step '%#lx'", g_steps); -} - -int main() { - g_info = info_impl; - g_warn = warn_impl; - - {% if args.command == "new" %} - salis_init(); - {% elif args.command == "load" %} - salis_load(); - {% endif %} - - g_running = true; - g_step_block = 1; - - signal(SIGINT, sig_handler); - signal(SIGTERM, sig_handler); - - while (g_running) { - step_block(); - } - - g_info("Saving simulation..."); - salis_save("{{ sim_path }}"); - salis_free(); - - g_info("Exiting salis..."); - return 0; -} diff --git a/ui/daemon/ui_vars.py b/ui/daemon/ui_vars.py index bb6be7c..5b3d372 100644 --- a/ui/daemon/ui_vars.py +++ b/ui/daemon/ui_vars.py @@ -1,5 +1,5 @@ -def gen_ui_vars(_): - return { - "flags": [], - "includes": ["signal.h", "stdio.h", "unistd.h"], - } +class UIVars: + def __init__(self, _): + self.includes = {"signal.h", "stdio.h", "unistd.h"} + self.defines = set() + self.links = set() -- cgit v1.2.3-70-g09d2