aboutsummaryrefslogtreecommitdiff
path: root/arch/salis-v1/arch.j2.c
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2025-11-25 03:20:16 +0100
committerPaul Oliver <contact@pauloliver.dev>2025-11-25 03:20:22 +0100
commitfcf5746e8defdacba2284581a6521f72096891c5 (patch)
treec4403553aa627fc890cfc1b072bea8a471e157e0 /arch/salis-v1/arch.j2.c
parenta86ef805982aac5f7de5b5f01b3f6de90dd1030d (diff)
Aggregates data on organisms IO activity
Diffstat (limited to 'arch/salis-v1/arch.j2.c')
-rw-r--r--arch/salis-v1/arch.j2.c329
1 files changed, 240 insertions, 89 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 %}