stage2 提供近乎完整的功能但出现严重性能问题 添加stage0的原生性能记录 stage1添加更多内置函数 nob重构代码使其更加健壮

This commit is contained in:
zzy committed 2026-09-19 18:08:43 +08:00
1 parent b5a7a811b3
commit e02b0c633a
35 files changed
+14018 -216

No files matched your search

+141
View File
@@ -5,12 +5,15 @@
*/
#include "spl_vm.h"
#include "include/core_map.h"
#include "spl_mcode.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void spl_vm_profile_free(spl_vm_t *vm);
#if defined(_WIN32) || defined(_WIN64)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -566,6 +569,9 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
vec_init(vm->fn_breakpoints);
vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0;
vm->steps = 0;
vm->profile = NULL;
vm->profile_interval = 0;
vm->prog = NULL;
vm->trace = 0;
vm->debug = 1;
@@ -585,6 +591,7 @@ void spl_vm_drop(spl_vm_t *vm) {
free(vm->fn_breakpoints.data[i]);
vec_free(vm->fn_breakpoints);
vec_free(vm->breakpoints);
spl_vm_profile_free(vm);
}
// FIXME
@@ -643,6 +650,7 @@ void spl_vm_skip_breakpoint(spl_vm_t *vm) {
/* 前向声明(定义在文件尾部 dump 区域) */
static const char *func_name_by_ip(spl_prog_t *prog, spl_vm_val_t ip);
static void spl_vm_profile_free(spl_vm_t *vm);
/* 函数名断点命中:addr 所在函数名是否在断点表 */
static int fn_breakpoint_hit(spl_vm_t *vm, spl_vm_val_t addr) {
@@ -766,6 +774,136 @@ int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv,
* Returns: 0 = still running, 1 = halted, 2 = breakpoint (SPL_DBG), -1 = error
* ================================================================ */
/* ================= native 采样 profiler =================
* 每隔 interval 条指令采样一次当前调用栈(root;...;leaf),累积计数。
* 输出折叠格式(folded)供火焰图工具使用,以及每函数 self 采样表。 */
static int func_index_by_ip(spl_prog_t *prog, spl_vm_val_t ip) {
if (!prog)
return -1;
isize lo = 0, hi = (isize)vec_size(prog->funcs) - 1;
while (lo <= hi) {
isize mid = (lo + hi) / 2;
spl_vm_func_t *f = &vec_at(prog->funcs, (usize)mid);
if (ip < f->address)
hi = mid - 1;
else if (ip >= f->address + f->ninsns)
lo = mid + 1;
else
return (int)mid;
}
for (usize i = 0; i < vec_size(prog->funcs); i++) {
spl_vm_func_t *f = &vec_at(prog->funcs, i);
if (ip >= f->address && ip < f->address + f->ninsns)
return (int)i;
}
return -1;
}
static void spl_vm_sample(spl_vm_t *vm) {
spl_prof_t *p = (spl_prof_t *)vm->profile;
spl_prog_t *prog = vm->prog;
if (!p || !prog)
return;
char buf[8192];
usize len = 0;
for (isize i = 0; i < vm->cp; i++) {
intptr_t s = (intptr_t)vm->frames.data[i].saved_ip;
if (s <= 0)
continue;
int fi = func_index_by_ip(prog, (spl_vm_val_t)(s - 1));
const char *n = fi >= 0 ? vec_at(prog->funcs, (usize)fi).name : "?";
size_t l = strlen(n);
if (len + l + 2 < sizeof(buf)) {
if (len)
buf[len++] = ';';
memcpy(buf + len, n, l);
len += l;
}
}
int leaf = func_index_by_ip(prog, vm->ip > 0 ? vm->ip - 1 : 0);
const char *ln = leaf >= 0 ? vec_at(prog->funcs, (usize)leaf).name : "?";
size_t ll = strlen(ln);
if (len + ll + 1 < sizeof(buf)) {
if (len)
buf[len++] = ';';
memcpy(buf + len, ln, ll);
len += ll;
}
buf[len] = 0;
usize old = 0;
if (map_get(p->stacks, buf, &old)) {
map_put(p->stacks, buf, old + 1);
} else {
map_put(p->stacks, strdup(buf), (usize)1);
}
if (leaf >= 0 && (usize)leaf < vec_size(p->self_samples))
p->self_samples.data[leaf]++;
p->samples++;
}
void spl_vm_profile_enable(spl_vm_t *vm, usize interval) {
if (!vm)
return;
spl_prof_t *p = (spl_prof_t *)malloc(sizeof(*p));
if (!p)
return;
memset(p, 0, sizeof(*p));
map_init(p->stacks, MAP_HASH_STR, MAP_CMP_STR);
vec_init(p->self_samples);
if (vm->prog) {
usize n = vec_size(vm->prog->funcs);
for (usize i = 0; i < n; i++)
vec_push(p->self_samples, (usize)0);
}
vm->profile = p;
vm->profile_interval = interval ? interval : 100000;
}
static void spl_vm_profile_free(spl_vm_t *vm) {
spl_prof_t *p = (spl_prof_t *)vm->profile;
if (!p)
return;
map_for(p->stacks, i) { free((void *)p->stacks.data[i].key); }
map_free(p->stacks);
vec_free(p->self_samples);
free(p);
vm->profile = NULL;
}
void spl_vm_profile_dump_folded(spl_vm_t *vm, const char *path) {
spl_prof_t *p = vm ? (spl_prof_t *)vm->profile : NULL;
if (!p || !path)
return;
FILE *f = fopen(path, "wb");
if (!f)
return;
map_for(p->stacks, i) { fprintf(f, "%s %zu\n", p->stacks.data[i].key, p->stacks.data[i].val); }
fclose(f);
}
void spl_vm_profile_dump_table(spl_vm_t *vm, const char *path) {
spl_prof_t *p = vm ? (spl_prof_t *)vm->profile : NULL;
if (!p || !path || !vm->prog)
return;
FILE *f = fopen(path, "wb");
if (!f)
return;
fprintf(f, "samples=%zu interval=%zu\n", p->samples, vm->profile_interval);
fprintf(f, "func\tself_samples\tpercent\n");
for (usize i = 0; i < vec_size(vm->prog->funcs); i++) {
usize c = i < vec_size(p->self_samples) ? p->self_samples.data[i] : 0;
if (c == 0)
continue;
spl_vm_func_t *fn = &vec_at(vm->prog->funcs, i);
fprintf(f, "%s\t%zu\t%.2f\n", fn->name, c,
p->samples ? (100.0 * (double)c / (double)p->samples) : 0.0);
}
fclose(f);
}
int spl_vm_run_once(spl_vm_t *vm) {
const spl_vm_ins_t *ins;
spl_prog_t *prog;
@@ -792,6 +930,9 @@ int spl_vm_run_once(spl_vm_t *vm) {
ins = &vec_at(prog->insns, vm->ip);
vm->ip++;
vm->steps++;
if (vm->profile && vm->profile_interval && (vm->steps % vm->profile_interval) == 0)
spl_vm_sample(vm);
if (vm->trace) {
fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1,