diff options
Diffstat (limited to 'arch/salis-v1')
| -rw-r--r-- | arch/salis-v1/arch.j2.c | 329 | ||||
| -rw-r--r-- | arch/salis-v1/arch_vars.py | 27 |
2 files changed, 264 insertions, 92 deletions
diff --git a/arch/salis-v1/arch.j2.c b/arch/salis-v1/arch.j2.c index f2b9990..5d2f58a 100644 --- a/arch/salis-v1/arch.j2.c +++ b/arch/salis-v1/arch.j2.c @@ -4,8 +4,6 @@ // Based on the original salis-v1 VM architecture: // https://git.pauloliver.dev/salis-v1/about/ -{% set inst_count = arch_vars.inst_set|length %} - enum { {% for i in arch_vars.inst_set %} {{ i[0]|join(' ') }}, @@ -13,7 +11,7 @@ enum { }; {% if args.command in ["bench", "new"] and anc_bytes is defined %} -void arch_anc_init(struct Core *core) { +void arch_core_init(struct Core *core) { assert(core); {% if arch_vars.mvec_loop %} @@ -35,6 +33,40 @@ void arch_anc_init(struct Core *core) { } {% endif %} +{% 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); +} +{% 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); +} +{% endif %} + uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); @@ -108,7 +140,7 @@ void arch_on_proc_kill(struct Core *core) { uint8_t _get_inst(const struct Core *core, uint64_t addr) { assert(core); - return mvec_get_inst(core, addr) % {{ inst_count }}; + return mvec_get_inst(core, addr) % {{ arch_vars.inst_count }}; } void _increment_ip(struct Core *core, uint64_t pix) { @@ -122,35 +154,35 @@ void _increment_ip(struct Core *core, uint64_t pix) { } 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(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 < {{ inst_count }}); + assert(inst < {{ arch_vars.inst_count }}); return _is_between(inst, keya, keyp); } bool _is_lock(uint8_t inst) { - assert(inst < {{ inst_count }}); + assert(inst < {{ arch_vars.inst_count }}); return _is_between(inst, loka, lokp); } bool _is_rmod(uint8_t inst) { - assert(inst < {{ inst_count }}); + assert(inst < {{ arch_vars.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(key < {{ arch_vars.inst_count }}); + assert(lock < {{ arch_vars.inst_count }}); assert(_is_key(key)); return (key - keya) == (lock - loka); @@ -597,6 +629,20 @@ void _write(struct Core *core, uint64_t pix) { 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 }}); } @@ -638,6 +684,20 @@ void arch_proc_step(struct Core *core, uint64_t 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)) { @@ -747,7 +807,7 @@ void arch_validate_proc(const struct Core *core, uint64_t pix) { {% endif %} wchar_t arch_symbol(uint8_t inst) { - switch (inst % {{ inst_count }}) { + switch (inst % {{ arch_vars.inst_count }}) { {% for i in arch_vars.inst_set %} case {{ i[0]|join(' ') }}: return L'{{ i[1] }}'; {% endfor %} @@ -758,7 +818,7 @@ wchar_t arch_symbol(uint8_t inst) { } const char *arch_mnemonic(uint8_t inst) { - switch (inst % {{ inst_count }}) { + switch (inst % {{ arch_vars.inst_count }}) { {% for i in arch_vars.inst_set %} case {{ i[0]|join(' ') }}: return "{{ i[0]|join(' ') }}"; {% endfor %} @@ -769,82 +829,125 @@ const char *arch_mnemonic(uint8_t inst) { } {% if data_push_path is defined %} +void _exec_sql(const char *sql) { + assert(sql); + + int sql_res; + char *sql_err; + + 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); + + switch (sql_res) { + case SQLITE_BUSY: + // Only handle busy database errors + g_info("Will retry query..."); + continue; + default: + // Application should fail on all other error conditions + assert(false); + } + } +} + void arch_push_data_header() { assert(g_sim_data); - const char *sql = ( - "create table trend(" + // General trends from all cores will be queried together + const char *trend_sql = ( + "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, " - "avrg_mb0s_{{ i }} real not null, " - "avrg_mb1s_{{ i }} real not null, " - {% set outer_loop = loop %} - {% for j in arch_vars.inst_set %} - "inst_{{ j[0]|join(' ') }}_{{ i }} int not null{% if not outer_loop.last or not loop.last %},{% endif %} " - {% endfor %} + "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 %} ");" ); g_info("Generating 'trend' table in SQLite database"); + _exec_sql(trend_sql); + + // 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 %} + ");" + ); - int sql_res; - char *sql_err; - - // Only handle busy database errors - // Application should fail on all other error conditions - while ((sql_res = sqlite3_exec(g_sim_data, sql, NULL, NULL, &sql_err)) == SQLITE_BUSY) { - g_warn("Busy SQLite database returned error '%d' with message:", sql_res); - g_warn(sql_err); - - sqlite3_free(sql_err); - - g_info("Will retry query..."); - } - - assert(sql_res == 0); + g_info("Generating '{{ t }}_{{ i }}' table in SQLite database"); + _exec_sql({{ t }}_sql_{{ i }}); + {% endfor %} + {% endfor %} } void arch_push_data_line() { assert(g_sim_data); - // Gather data on all cores - uint64_t inst_total[{{ args.cores }}][{{ inst_count }}] = { 0 }; + // Measure current instruction population and + // average memory block sizes + uint64_t ipop[{{ args.cores }}][{{ arch_vars.inst_count }}] = { 0 }; - double avrg_mb0s[{{ args.cores }}] = { 0 }; - double avrg_mb1s[{{ args.cores }}] = { 0 }; + double amb0[{{ args.cores }}] = { 0 }; + double amb1[{{ args.cores }}] = { 0 }; for (int i = 0; i < {{ args.cores }}; ++i) { - const struct Core *core = &g_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; - // Count number of instructions for (uint64_t j = 0; j < {{ mvec_size }}; ++j) { - uint8_t inst = mvec_get_inst(core, j) % {{ inst_count }}; - ++inst_total[i][inst]; + ++ipop[i][_get_inst(core, j)]; } - // Avregare memory block sizes - for (uint64_t j = core->pfst; j <= core->plst; ++j) { - const struct Proc *proc = proc_get(core, j); + {% if not args.optimized %} + // Make sure the counting was done right + uint64_t pop_tot = 0; - avrg_mb0s[i] += (double)proc->mb0s; - avrg_mb1s[i] += (double)proc->mb1s; + for (int j = 0; j < {{ arch_vars.inst_count }}; ++j) { + pop_tot += ipop[i][j]; } - avrg_mb0s[i] /= core->pnum; - avrg_mb1s[i] /= core->pnum; + assert(pop_tot == {{ mvec_size }}); + {% endif %} } // Insert new row - char *sql = NULL; + char *trend_sql = NULL; asprintf( - &sql, + &trend_sql, "insert into trend (" "step, " {% for i in range(args.cores) %} @@ -853,21 +956,20 @@ void arch_push_data_line() { "pnum_{{ i }}, " "pfst_{{ i }}, " "plst_{{ i }}, " - "avrg_mb0s_{{ i }}, " - "avrg_mb1s_{{ i }}, " - {% set outer_loop = loop %} - {% for j in arch_vars.inst_set %} - "inst_{{ j[0]|join(' ') }}_{{ i }}{% if not outer_loop.last or not loop.last %},{% endif %} " - {% endfor %} + "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, " - {% set outer_loop = loop %} - {% for _ in arch_vars.inst_set %} - "%ld{% if not outer_loop.last or not loop.last %},{% endif %} " - {% endfor %} + "%ld, %ld, %ld, %ld, %ld, %f, %f, %ld, %ld, %ld, %ld, %ld, %ld, %ld{% if not loop.last %},{% endif %} " {% endfor %} ");", g_steps, @@ -877,34 +979,83 @@ void arch_push_data_line() { g_cores[{{ i }}].pnum, g_cores[{{ i }}].pfst, g_cores[{{ i }}].plst, - avrg_mb0s[{{ i }}], - avrg_mb1s[{{ i }}], - {% set outer_loop = loop %} - {% for j in arch_vars.inst_set %} - inst_total[{{ i }}][{{ j[0]|join(' ') }}]{% if not outer_loop.last or not loop.last %},{% endif %} // inst - {% endfor %} + 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 %} ); g_info("Pushing row to 'trend' table in SQLite database"); + _exec_sql(trend_sql); + free(trend_sql); - int sql_res; - char *sql_err; + {% for t in ["pop", "exe", "wrt"] %} + {% for i in range(args.cores) %} - // Only handle busy database errors - // Application should fail on all other error conditions - while ((sql_res = sqlite3_exec(g_sim_data, sql, NULL, NULL, &sql_err)) == SQLITE_BUSY) { - g_warn("Busy SQLite database returned error '%d' with message:", sql_res); - g_warn(sql_err); + {% 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 %} - sqlite3_free(sql_err); + char *{{ t }}_sql_{{ i }} = NULL; - g_info("Will retry query..."); - } + 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 %} + ); - assert(sql_res == 0); + g_info("Pushing row to '{{ t }}_{{ i }}' table in SQLite database"); + _exec_sql({{ t }}_sql_{{ i }}); + free({{ t }}_sql_{{ i }}); + {% endfor %} + {% endfor %} - // Free query string returned by 'asprintf()' - free(sql); + // 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; + } } {% endif %} diff --git a/arch/salis-v1/arch_vars.py b/arch/salis-v1/arch_vars.py index 07301c3..f469ad6 100644 --- a/arch/salis-v1/arch_vars.py +++ b/arch/salis-v1/arch_vars.py @@ -1,6 +1,12 @@ -core_fields = [] -mvec_loop = False +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"), @@ -22,7 +28,7 @@ proc_fields = [ ("uint64_t", "s7"), ] -# salis-v1 instruction set +# Salis-v1 instruction set inst_set = [ (["noop"], " "), (["nop0"], "0"), @@ -96,3 +102,18 @@ inst_set = [ (["loko"], "O"), (["lokp"], "P"), ] + +inst_count = len(inst_set) + +# 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"), +] |
