diff options
| author | Paul Oliver <contact@pauloliver.dev> | 2025-12-03 22:14:38 +0100 |
|---|---|---|
| committer | Paul Oliver <contact@pauloliver.dev> | 2025-12-08 06:45:59 +0100 |
| commit | 0fb1497a62332e0db45f94b4f195cb37183678cb (patch) | |
| tree | 0926e7c04415e69e7ad5c105f79eb4625ae9145f | |
| parent | c7c5925d86fd3e36069ee3689b1c0a1f6df600f9 (diff) | |
Improve SQL handling & aggregate memory events (WIP)data_improvements
| -rw-r--r-- | arch/dummy/arch.j2.c | 6 | ||||
| -rw-r--r-- | arch/dummy/arch_vars.py | 43 | ||||
| -rw-r--r-- | arch/salis-v1/arch.j2.c | 252 | ||||
| -rw-r--r-- | arch/salis-v1/arch_vars.py | 236 | ||||
| -rw-r--r-- | core.j2.c | 65 | ||||
| -rwxr-xr-x | salis.py | 21 | ||||
| -rw-r--r-- | ui/curses/ui.j2.c | 11 | ||||
| -rw-r--r-- | ui/curses/ui_vars.py | 7 | ||||
| -rw-r--r-- | ui/daemon/ui_vars.py | 7 |
9 files changed, 406 insertions, 242 deletions
diff --git a/arch/dummy/arch.j2.c b/arch/dummy/arch.j2.c index c331b34..f51494f 100644 --- a/arch/dummy/arch.j2.c +++ b/arch/dummy/arch.j2.c @@ -28,6 +28,12 @@ void arch_core_init(struct Core *core) { } {% 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); diff --git a/arch/dummy/arch_vars.py b/arch/dummy/arch_vars.py index e121ca5..bc97ea9 100644 --- a/arch/dummy/arch_vars.py +++ b/arch/dummy/arch_vars.py @@ -1,23 +1,26 @@ -core_fields = [] -mvec_loop = True +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"), -] + "proc_fields": [ + ("uint64_t", "ip"), + ("uint64_t", "sp"), + ("uint64_t", "mb0a"), + ("uint64_t", "mb0s"), + ("uint64_t", "mb1a"), + ("uint64_t", "mb1s"), + ], -inst_set = [ - (["dummy", f"{i:02x}"], symbol) - for i, symbol in enumerate( - "⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟" - "⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿" - "⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟" - "⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿" - ) -] + "inst_set": [ + (["dummy", f"{i:02x}"], symbol) + for i, symbol in enumerate( + "⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟" + "⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿" + "⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟" + "⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿" + ) + ], -inst_count = len(inst_set) + "inst_count": 2 ** 7, + } diff --git a/arch/salis-v1/arch.j2.c b/arch/salis-v1/arch.j2.c index 9c3ea45..06a701d 100644 --- a/arch/salis-v1/arch.j2.c +++ b/arch/salis-v1/arch.j2.c @@ -33,6 +33,11 @@ void arch_core_init(struct Core *core) { } {% 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); @@ -47,6 +52,7 @@ void arch_core_save(FILE *f, const struct Core *core) { 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 %} @@ -64,6 +70,7 @@ void arch_core_load(FILE *f, struct Core *core) { 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 %} @@ -119,6 +126,9 @@ void _free_memory_block(struct Core *core, uint64_t addr, uint64_t size) { for (uint64_t i = 0; i < size; ++i) { mvec_free(core, addr + i); + + // Record deallocation event + ++core->aeva[addr]; } } @@ -388,6 +398,9 @@ void _alloc(struct Core *core, uint64_t pix, bool fwrd) { // 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; } @@ -828,12 +841,17 @@ const char *arch_mnemonic(uint8_t inst) { return NULL; } +// ---------------------------------------------------------------------------- +// Data aggregation functions +// ---------------------------------------------------------------------------- {% if data_push_path is defined %} void arch_push_data_header() { assert(g_sim_data); - // General trends from all cores will be queried together - const char *trend_sql = ( + // 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) %} @@ -855,37 +873,54 @@ void arch_push_data_header() { ");" ); - g_info("Generating 'trend' table in SQLite database"); - salis_exec_sql(trend_sql); + // Creates core-specific instruction data tables + char *iprefs[] = { "pop", "exe", "wrt" }; + int iprefs_cnt = sizeof(iprefs) / sizeof(iprefs[0]); - // Core-specific instruction data will be queried separately - // A table is created for each core - {% for t in ["pop", "exe", "wrt"] %} - {% for i in range(args.cores) %} - const char *{{ t }}_sql_{{ i }} = ( - "create table {{ t }}_{{ i }} (" - "step int not null, " - // Cycle data allows normalizing against each core's cycle speed - {% for j in range(args.cores) %} - "cycl_{{ j }} int not null, " - {% endfor %} - {% for j in arch_vars.inst_set %} - "inst_{{ j[0]|join(' ') }} int not null{% if not loop.last %},{% endif %} " - {% endfor %} - ");" - ); + 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 + ); + } + } - g_info("Generating '{{ t }}_{{ i }}' table in SQLite database"); - salis_exec_sql({{ t }}_sql_{{ i }}); - {% endfor %} - {% endfor %} + // 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 + // Measure current instruction population and average memory block sizes uint64_t ipop[{{ args.cores }}][{{ arch_vars.inst_count }}] = { 0 }; double amb0[{{ args.cores }}] = { 0 }; @@ -920,11 +955,10 @@ void arch_push_data_line() { {% endif %} } - // Insert new row - char *trend_sql = NULL; - - asprintf( - &trend_sql, + // 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) %} @@ -950,7 +984,7 @@ void arch_push_data_line() { {% endfor %} ");", g_steps, - {% for i in range(args.cores) %} + {% for i in range(args.cores) +%} g_cores[{{ i }}].cycl, g_cores[{{ i }}].mall, g_cores[{{ i }}].pnum, @@ -965,59 +999,118 @@ void arch_push_data_line() { g_cores[{{ i }}].wmb0, g_cores[{{ i }}].wmb1, g_cores[{{ i }}].wdea{% if not loop.last %},{% endif %} - {% endfor %} + {% endfor +%} ); - g_info("Pushing row to 'trend' table in SQLite database"); - salis_exec_sql(trend_sql); - free(trend_sql); + // Insert row into instruction data tables + char *iprefs[] = { "pop", "exe", "wrt" }; + int iprefs_cnt = sizeof(iprefs) / sizeof(iprefs[0]); - {% for t in ["pop", "exe", "wrt"] %} - {% for i in range(args.cores) %} + 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; + } - {% if t == "pop" %} - // Reference instruction population vector that was - // manually generated above - {% set table = "ipop[%d]"|format(i) %} - {% else %} - {% set table = "g_cores[%d].i%s"|format(i, t) %} - {% endif %} + 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 %} + ); + } + } - char *{{ t }}_sql_{{ i }} = NULL; + // Insert row into memory event tables + char *eprefs[] = { "aev" }; + int eprefs_cnt = sizeof(eprefs) / sizeof(eprefs[0]); - asprintf( - &{{ t }}_sql_{{ i }}, - "insert into {{ t }}_{{ i }} (" - "step, " - {% for j in range(args.cores) %} - "cycl_{{ j }}, " - {% endfor %} - {% for j in arch_vars.inst_set %} - "inst_{{ j[0]|join(' ') }}{% 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 %} - ");", - g_steps, - {% for j in range(args.cores) %} - g_cores[{{ j }}].cycl, - {% endfor %} - {% for j in range(arch_vars.inst_count) %} - {{ table }}[{{ j }}]{% if not loop.last %},{% endif %} - {% endfor %} - ); + // Event run-length data array is defined as static + // This prevents heap errors + static uint64_t erl_data[{{ mvec_size }} * 2]; - g_info("Pushing row to '{{ t }}_{{ i }}' table in SQLite database"); - salis_exec_sql({{ t }}_sql_{{ i }}); - free({{ t }}_sql_{{ i }}); - {% endfor %} - {% endfor %} + 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) { @@ -1033,6 +1126,9 @@ void arch_push_data_line() { 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 index f469ad6..25687ce 100644 --- a/arch/salis-v1/arch_vars.py +++ b/arch/salis-v1/arch_vars.py @@ -1,119 +1,125 @@ -mvec_loop = False +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"), -] + # 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"), -] + # 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 = len(inst_set) + "inst_count": 2 ** 6, -# Extra fields used exclusively for data aggregation -core_fields = [ - ("uint64_t", f"iexe[{inst_count}]"), - ("uint64_t", f"iwrt[{inst_count}]"), - ("uint64_t", "emb0"), - ("uint64_t", "emb1"), - ("uint64_t", "eliv"), - ("uint64_t", "edea"), - ("uint64_t", "wmb0"), - ("uint64_t", "wmb1"), - ("uint64_t", "wdea"), -] + # 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), + ], + } @@ -39,7 +39,7 @@ struct Core { uint8_t *iviv; // Architecture specific custom fields - {% for type, val in arch_vars.core_fields %} + {% for type, val, _ in arch_vars.core_fields %} {{ type }} {{ val }}; {% endfor %} @@ -73,6 +73,8 @@ void (*g_warn)(const char *fmt, ...); 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 %} @@ -610,27 +612,58 @@ void salis_auto_save() { {% endif %} {% if data_push_path is defined %} -void salis_exec_sql(const char *sql) { - assert(sql); +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); + } - int sql_res; - char *sql_err; + // 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; + } - while ((sql_res = sqlite3_exec(g_sim_data, sql, NULL, NULL, &sql_err)) == SQLITE_BUSY) { g_warn("SQLite database returned error '%d' with message:", sql_res); - g_warn(sql_err); - sqlite3_free(sql_err); + g_warn(sqlite3_errmsg(g_sim_data)); - switch (sql_res) { - case SQLITE_BUSY: - // Only handle busy database errors + if (sql_res == SQLITE_BUSY) { g_info("Will retry query..."); continue; - default: - // Application should fail on all other error conditions - assert(false); } + + // Fail on unhandled error + assert(false); } + + sqlite3_finalize(sql_stmt); } {% endif %} @@ -659,7 +692,7 @@ void salis_init() { // 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("pragma journal_mode=wal;"); + salis_exec_sql(0, NULL, NULL, "pragma journal_mode=wal;"); arch_push_data_header(); arch_push_data_line(); @@ -871,6 +904,8 @@ void salis_free() { {% 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); @@ -202,13 +202,15 @@ if args.command in ["new"]: arch_path = f"arch/{args.arch}" info("Loading architecture specific variables from:", f"{arch_path}/arch_vars.py") sys.path.append(arch_path) -import arch_vars +from arch_vars import gen_arch_vars +arch_vars = gen_arch_vars(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") sys.path.append(ui_path) - import ui_vars + from ui_vars import gen_ui_vars + ui_vars = gen_ui_vars(args) # ------------------------------------------------------------------------------ # Fill in template variables @@ -266,7 +268,7 @@ if args.command in ["load", "new"]: else: warn("Save file compression disabled") - includes.extend(ui_vars.includes) + includes.extend(ui_vars["includes"]) # ------------------------------------------------------------------------------ # Assemble ancestor organism into byte array @@ -293,7 +295,7 @@ if args.command in ["bench", "new"] and args.anc is not None: 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 @@ -341,14 +343,13 @@ build_cmd = ["gcc", salis_src, "-o", salis_bin, "-Wall", "-Wextra", "-Werror", " build_cmd.extend(["-O3", "-DNDEBUG"] if args.optimized else ["-ggdb"]) if args.command in ["load", "new"]: - build_cmd.extend(ui_vars.flags) + build_cmd.extend(ui_vars["flags"]) - # Enable POSIX extensions (open_memstream) + # 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 []) - - # Enable GNU extensions (asprintf) - # This allows managing large SQL strings more easily - build_cmd.extend(["-lsqlite3", "-D_GNU_SOURCE"] if args.data_push_pow != 0 else []) + build_cmd.extend(["-lsqlite3"] if args.data_push_pow != 0 else []) info("Using build command:", " ".join(build_cmd)) subprocess.run(build_cmd, check=True) diff --git a/ui/curses/ui.j2.c b/ui/curses/ui.j2.c index ddeaf3b..2158eeb 100644 --- a/ui/curses/ui.j2.c +++ b/ui/curses/ui.j2.c @@ -416,6 +416,17 @@ void ui_print_core(int l) { 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 %} } // ---------------------------------------------------------------------------- diff --git a/ui/curses/ui_vars.py b/ui/curses/ui_vars.py index 4dfdc10..97d2c07 100644 --- a/ui/curses/ui_vars.py +++ b/ui/curses/ui_vars.py @@ -1,2 +1,5 @@ -flags = ["-lncurses", "-DNCURSES_WIDECHAR=1"] -includes = ["curses.h", "locale.h", "time.h"] +def gen_ui_vars(_): + return { + "flags": ["-lncurses", "-DNCURSES_WIDECHAR=1"], + "includes": ["curses.h", "locale.h", "time.h"], + } diff --git a/ui/daemon/ui_vars.py b/ui/daemon/ui_vars.py index 9d0fc33..bb6be7c 100644 --- a/ui/daemon/ui_vars.py +++ b/ui/daemon/ui_vars.py @@ -1,2 +1,5 @@ -flags = [] -includes = ["signal.h", "stdio.h", "unistd.h"] +def gen_ui_vars(_): + return { + "flags": [], + "includes": ["signal.h", "stdio.h", "unistd.h"], + } |
