aboutsummaryrefslogtreecommitdiff
path: root/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'core.c')
-rw-r--r--core.c1222
1 files changed, 0 insertions, 1222 deletions
diff --git a/core.c b/core.c
deleted file mode 100644
index b6b5609..0000000
--- a/core.c
+++ /dev/null
@@ -1,1222 +0,0 @@
-#include <assert.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <threads.h>
-
-#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
-
-#if defined(COMPRESS) || defined(DATA_PUSH_PATH)
-#include "data/compress.c"
-#endif
-
-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;
-
-#if defined(DATA_PUSH_PATH)
- uint64_t emb0; // executions within mb0 counter
- uint64_t emb1; // executions within mb1 counter
- uint64_t eliv; // executions within not-owned live code counter (parasites)
- uint64_t edea; // executions within dead code counter
-
- uint64_t aeva[MVEC_SIZE]; // allocation events array
- uint64_t eeva[MVEC_SIZE]; // execution events array
-
-#define CORE_DATA_FIELD(type, name, suff) type name suff;
- CORE_DATA_FIELDS
-#undef CORE_FIELD
-#endif
-
-#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)
-#if defined(COMMAND_NEW)
-void arch_push_data_header();
-#endif
-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;
-#if defined(DATA_PUSH_PATH)
- // Record deallocation event
- ++core->aeva[mvec_loop(addr)];
-#endif
-#else
- assert(addr < MVEC_SIZE);
- core->mvec[addr] |= MALL_FLAG;
-#if defined(DATA_PUSH_PATH)
- // Record deallocation event
- ++core->aeva[addr];
-#endif
-#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;
-#if defined(DATA_PUSH_PATH)
- // Record deallocation event
- ++core->aeva[mvec_loop(addr)];
-#endif
-#else
- assert(addr < MVEC_SIZE);
- core->mvec[addr] ^= MALL_FLAG;
-#if defined(DATA_PUSH_PATH)
- // Record deallocation event
- ++core->aeva[addr];
-#endif
-#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);
-#if defined(DATA_PUSH_PATH)
- 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);
-#endif
-
- 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);
-#if defined(DATA_PUSH_PATH)
- fwrite(core->aeva, sizeof(uint64_t), MVEC_SIZE, f);
- fwrite(core->eeva, sizeof(uint64_t), MVEC_SIZE, f);
-#endif
-
- 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);
-#if defined(DATA_PUSH_PATH)
- 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);
-#endif
-
- 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);
-#if defined(DATA_PUSH_PATH)
- fread(core->aeva, sizeof(uint64_t), MVEC_SIZE, f);
- fread(core->eeva, sizeof(uint64_t), MVEC_SIZE, f);
-#endif
-
- 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);
-
-#if defined(DATA_PUSH_PATH)
- // Save execution event locations in database
- assert(mvec_proc_is_live(core, core->pcur));
-
- uint64_t pcur_ip = arch_proc_ip_addr(core, core->pcur);
-
- if (mvec_is_in_mb0_of_proc(core, pcur_ip, core->pcur)) {
- ++core->emb0;
- } else if (mvec_is_in_mb1_of_proc(core, pcur_ip, core->pcur)) {
- ++core->emb1;
- } else if (mvec_is_alloc(core, pcur_ip)) {
- ++core->eliv;
- } else {
- ++core->edea;
- }
-
-#if defined(MVEC_LOOP)
- core->eeva[mvec_loop(pcur_ip)]++;
-#else
- if (pcur_ip < MVEC_SIZE) {
- core->eeva[pcur_ip]++;
- }
-#endif
-#endif
-
- 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 };
- salis_deflate(&strm, size, (Bytef *)in, (Bytef *)out);
-
- FILE *fx = fopen(path, "wb");
- assert(fx);
-
- fwrite(&size, sizeof(size_t), 1, fx);
- fwrite(out, sizeof(char), strm.total_out, fx);
- fclose(fx);
-
- salis_deflate_end(&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(DATA_PUSH_PATH)
-#if defined(COMMAND_NEW)
-void salis_push_data_header() {
- assert(g_sim_data);
-
- g_info("Creating 'general' table in SQLite database");
- salis_exec_sql(
- 0, NULL, NULL,
- "create table general ("
-#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, "
- FOR_CORES
-#undef FOR_CORE
- "step int not null"
- ");"
- );
-
- // Memory events
- char *eprefs[] = { "aev", "eev" };
- 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
- );
- }
- }
-
- arch_push_data_header();
-}
-#endif
-
-void salis_push_data_line() {
- assert(g_sim_data);
-
- // Measure average membory 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) {
- amb0[i] += (double)arch_proc_mb0_size(core, j);
- amb1[i] += (double)arch_proc_mb1_size(core, j);
- }
-
- amb0[i] /= core->pnum;
- amb1[i] /= core->pnum;
- }
-
- g_info("Pushing row to 'general' table in SQLite database");
- salis_exec_sql(
- 0, NULL, NULL,
- "insert into general ("
-#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 ", "
- FOR_CORES
-#undef FOR_CORE
- "step"
- ") values ("
-#define FOR_CORE(i) "%ld, %ld, %ld, %ld, %ld, %f, %f, %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,
- FOR_CORES
-#undef FOR_CORE
- g_steps
- );
-
- // TODO: insert execute memory events
- char *eprefs[] = { "aev", "eev" };
- int eprefs_cnt = sizeof(eprefs) / sizeof(eprefs[0]);
-
- for (int i = 0; i < CORES; ++i) {
- for (int j = 0; j < eprefs_cnt; ++j) {
- uint64_t *in = NULL;
-
- if (!strcmp("aev", eprefs[j])) {
- in = g_cores[i].aeva;
- } else if (!strcmp("eev", eprefs[j])) {
- in = g_cores[i].eeva;
- }
-
- // Compress event data
- size_t size = sizeof(uint64_t) * MVEC_SIZE;
- char *out = malloc(size);
- assert(out);
-
- z_stream strm = { 0 };
- salis_deflate(&strm, size, (Bytef *)in, (Bytef *)out);
-
- // 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
- );
-
- salis_deflate_end(&strm);
- free(out);
- }
- }
-
- // Reset data aggregation fields
- for (int i = 0; i < CORES; ++i) {
- struct Core *core = &g_cores[i];
-
- core->emb0 = 0;
- core->emb1 = 0;
- core->eliv = 0;
- core->edea = 0;
-
- memset(core->aeva, 0, sizeof(uint64_t) * MVEC_SIZE);
- memset(core->eeva, 0, sizeof(uint64_t) * MVEC_SIZE);
- }
-
- // Push arch-specific data
- arch_push_data_line();
-}
-#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;");
-
- // Initialize database
- salis_push_data_header();
- salis_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 };
- salis_inflate(&strm, x_size, size, (Bytef *)in, (Bytef *)out);
- salis_inflate_end(&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) {
- salis_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