This commit is contained in:
dzaima 2022-05-29 22:02:50 +03:00
parent 5b2d221d0b
commit e2fda60745
8 changed files with 241 additions and 21 deletions

View File

@ -10,6 +10,10 @@ Execute the contents of the file as if it were REPL input (but allowing multilin
Execute the expression, but don't print its result. Execute the expression, but don't print its result.
## `)profile expr` / `)profile@frequency expr`
Profile the expression at the given sampling frequency, or 5000 samples/second by default
## `)t expr` / `)time expr` / `)t:n expr` / `)time:n expr` ## `)t expr` / `)time expr` / `)t:n expr` / `)time:n expr`
Time the argument expression. `n` specifies the number of times to repeat. Exists to allow not escaping quotes and less overhead for timing very fast & small expressions. Time the argument expression. `n` specifies the number of times to repeat. Exists to allow not escaping quotes and less overhead for timing very fast & small expressions.

View File

@ -339,6 +339,22 @@ B gid2str(i32 n) {
return r; return r;
} }
void* profiler_makeMap() {
return m_b2i(64);
}
i32 profiler_index(void** mapRaw, B comp) {
H_b2i* map = *(H_b2i**)mapRaw;
i32 r;
bool had; u64 p = mk_b2i(&map, comp, &had);
if (had) r = map->a[p].val;
else r = map->a[p].val = map->pop-1;
*(H_b2i**)mapRaw = map;
return r;
}
void profiler_freeMap(void* mapRaw) {
free_b2i((H_b2i*)mapRaw);
}
void fun_gcFn() { void fun_gcFn() {

View File

@ -150,7 +150,7 @@ void fprint(FILE* f, B x) {
} }
else if (isVar(x)) fprintf(f, "(var d=%d i=%d)", (u16)(x.u>>32), (i32)x.u); else if (isVar(x)) fprintf(f, "(var d=%d i=%d)", (u16)(x.u>>32), (i32)x.u);
else if (isExt(x)) fprintf(f, "(extvar d=%d i=%d)", (u16)(x.u>>32), (i32)x.u); else if (isExt(x)) fprintf(f, "(extvar d=%d i=%d)", (u16)(x.u>>32), (i32)x.u);
else if (x.u==bi_N.u) fprintf(f, "·"); else if (x.u==bi_N.u) fprintf(f, "(native ·)");
else if (x.u==bi_optOut.u) fprintf(f, "(value optimized out)"); else if (x.u==bi_optOut.u) fprintf(f, "(value optimized out)");
else if (x.u==bi_noVar.u) fprintf(f, "(unset variable placeholder)"); else if (x.u==bi_noVar.u) fprintf(f, "(unset variable placeholder)");
else if (x.u==bi_okHdr.u) fprintf(f, "(accepted SETH placeholder)"); else if (x.u==bi_okHdr.u) fprintf(f, "(accepted SETH placeholder)");

View File

@ -36,7 +36,7 @@ __attribute__((optnone))
static void* mmap_nvm(u64 sz) { static void* mmap_nvm(u64 sz) {
u64 near = (u64)&bqn_exec; u64 near = (u64)&bqn_exec;
u64 MAX_DIST = 1ULL<<30; u64 MAX_DIST = 1ULL<<30;
if (near < MAX_DIST) return mmap(NULL, sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON|MAP_32BIT, -1, 0); if (near < MAX_DIST) return mmap(NULL, sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS|MAP_32BIT, -1, 0);
u64 ps = getPageSize(); u64 ps = getPageSize();
i32 attempt = 0; i32 attempt = 0;
@ -50,7 +50,7 @@ static void* mmap_nvm(u64 sz) {
#ifdef MAP_FIXED_NOREPLACE #ifdef MAP_FIXED_NOREPLACE
noreplace|= MAP_FIXED_NOREPLACE; noreplace|= MAP_FIXED_NOREPLACE;
#endif #endif
void* c = mmap((void*)loc, sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON|noreplace, -1, 0); void* c = mmap((void*)loc, sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS|noreplace, -1, 0);
if (c==NULL) continue; if (c==NULL) continue;
i64 dist = (i64)near - (i64)c; i64 dist = (i64)near - (i64)c;
@ -241,7 +241,7 @@ u32 perfid = 0;
#endif #endif
static void* nvm_alloc(u64 sz) { static void* nvm_alloc(u64 sz) {
// void* r = mmap(NULL, sz, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON|MAP_32BIT, -1, 0); // void* r = mmap(NULL, sz, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_32BIT, -1, 0);
// if (r==MAP_FAILED) thrM("JIT: Failed to allocate executable memory"); // if (r==MAP_FAILED) thrM("JIT: Failed to allocate executable memory");
// return r; // return r;
I8Arr* src = mmX_allocN(fsizeof(I8Arr,a,u8,sz), t_i8arr); I8Arr* src = mmX_allocN(fsizeof(I8Arr,a,u8,sz), t_i8arr);

View File

@ -116,11 +116,11 @@ Block* load_compObj(B x, B src, B path, Scope* sc) { // consumes x,src
} }
#include "gen/src" #include "gen/src"
#if RT_SRC #if RT_SRC
Block* load_compImport(B bc, B objs, B blocks, B bodies, B inds, B src) { // consumes all Block* load_compImport(char* name, B bc, B objs, B blocks, B bodies, B inds, B src) { // consumes all
return compile(bc, objs, blocks, bodies, inds, bi_N, src, m_str8l("(precompiled)"), NULL); return compile(bc, objs, blocks, bodies, inds, bi_N, src, m_str8l(name), NULL);
} }
#else #else
Block* load_compImport(B bc, B objs, B blocks, B bodies) { // consumes all Block* load_compImport(char* name, B bc, B objs, B blocks, B bodies) { // consumes all
return compile(bc, objs, blocks, bodies, bi_N, bi_N, bi_N, bi_N, NULL); return compile(bc, objs, blocks, bodies, bi_N, bi_N, bi_N, bi_N, NULL);
} }
#endif #endif
@ -350,14 +350,14 @@ void load_init() { // very last init function
#ifndef ALL_R0 #ifndef ALL_R0
B runtime_0[] = {bi_floor,bi_ceil,bi_stile,bi_lt,bi_gt,bi_ne,bi_ge,bi_rtack,bi_ltack,bi_join,bi_pair,bi_take,bi_drop,bi_select,bi_const,bi_swap,bi_each,bi_fold,bi_atop,bi_over,bi_before,bi_after,bi_cond,bi_repeat}; B runtime_0[] = {bi_floor,bi_ceil,bi_stile,bi_lt,bi_gt,bi_ne,bi_ge,bi_rtack,bi_ltack,bi_join,bi_pair,bi_take,bi_drop,bi_select,bi_const,bi_swap,bi_each,bi_fold,bi_atop,bi_over,bi_before,bi_after,bi_cond,bi_repeat};
#else #else
Block* runtime0_b = load_compImport( Block* runtime0_b = load_compImport("r0.bqn",
#include "gen/runtime0" #include "gen/runtime0"
); );
B r0r = evalFunBlock(runtime0_b, 0); ptr_dec(runtime0_b); B r0r = evalFunBlock(runtime0_b, 0); ptr_dec(runtime0_b);
B* runtime_0 = toHArr(r0r)->a; B* runtime_0 = toHArr(r0r)->a;
#endif #endif
Block* runtime_b = load_compImport( Block* runtime_b = load_compImport("r1.bqn",
#include "gen/runtime1" #include "gen/runtime1"
); );
@ -458,7 +458,7 @@ void load_init() { // very last init function
#else // use compiler #else // use compiler
B prevAsrt = runtime[n_asrt]; B prevAsrt = runtime[n_asrt];
runtime[n_asrt] = bi_casrt; // horrible but GC is off so it's fiiiiiine runtime[n_asrt] = bi_casrt; // horrible but GC is off so it's fiiiiiine
Block* comp_b = load_compImport( Block* comp_b = load_compImport("c.bqn",
#include "gen/compiles" #include "gen/compiles"
); );
runtime[n_asrt] = prevAsrt; runtime[n_asrt] = prevAsrt;
@ -469,7 +469,7 @@ void load_init() { // very last init function
#if FORMATTER #if FORMATTER
Block* fmt_b = load_compImport( Block* fmt_b = load_compImport("f.bqn",
#include "gen/formatter" #include "gen/formatter"
); );
B fmtM = evalFunBlock(fmt_b, 0); ptr_dec(fmt_b); B fmtM = evalFunBlock(fmt_b, 0); ptr_dec(fmt_b);

View File

@ -38,7 +38,22 @@ static bool isCmd(char* s, char** e, const char* cmd) {
*e = s; *e = s;
return true; return true;
} }
bool profiler_alloc(void);
bool profiler_start(i64 hz);
bool profiler_stop(void);
void profiler_free(void);
void profiler_displayResults(void);
i64 readInt(char** p) {
char* c = *p;
i64 am = 0;
while (*c>='0' & *c<='9') {
am = am*10 + (*c - '0');
c++;
}
*p = c;
return am;
}
void cbqn_runLine0(char* ln, i64 read) { void cbqn_runLine0(char* ln, i64 read) {
if (ln[0]==10) return; if (ln[0]==10) return;
if (ln[read-1]==10) ln[--read] = 0; if (ln[read-1]==10) ln[--read] = 0;
@ -46,6 +61,7 @@ void cbqn_runLine0(char* ln, i64 read) {
B code; B code;
int output; // 0-no; 1-formatter; 2-internal int output; // 0-no; 1-formatter; 2-internal
i32 time = 0; i32 time = 0;
i64 profile = -1;
if (ln[0] == ')') { if (ln[0] == ')') {
char* cmdS = ln+1; char* cmdS = ln+1;
char* cmdE; char* cmdE;
@ -60,13 +76,16 @@ void cbqn_runLine0(char* ln, i64 read) {
code = fromUTF8l(cmdE); code = fromUTF8l(cmdE);
time = -1; time = -1;
output = 0; output = 0;
} else if (isCmd(cmdS, &cmdE, "profile ") || isCmd(cmdS, &cmdE, "profile@")) {
char* cpos = cmdE;
profile = '@'==*(cpos-1)? readInt(&cpos) : 5000;
if (profile==0) { printf("Cannot profile with 0hz sampling frequency\n"); return; }
if (profile>999999) { printf("Cannot profile with >999999hz frequency\n"); return; }
code = fromUTF8l(cmdE);
output = 0;
} else if (isCmd(cmdS, &cmdE, "t:") || isCmd(cmdS, &cmdE, "time:")) { } else if (isCmd(cmdS, &cmdE, "t:") || isCmd(cmdS, &cmdE, "time:")) {
char* repE = cmdE; char* repE = cmdE;
i64 am = 0; i64 am = readInt(&repE);
while (*repE>='0' & *repE<='9') {
am = am*10 + (*repE - '0');
repE++;
}
if (repE==cmdE) { printf("time command not given repetition count\n"); return; } if (repE==cmdE) { printf("time command not given repetition count\n"); return; }
if (am==0) { printf("repetition count was zero\n"); return; } if (am==0) { printf("repetition count was zero\n"); return; }
code = fromUTF8l(repE); code = fromUTF8l(repE);
@ -187,9 +206,16 @@ void cbqn_runLine0(char* ln, i64 read) {
else if (t<1e6) printf("%.4gus\n", t/1e3); else if (t<1e6) printf("%.4gus\n", t/1e3);
else if (t<1e9) printf("%.4gms\n", t/1e6); else if (t<1e9) printf("%.4gms\n", t/1e6);
else printf("%.5gs\n", t/1e9); else printf("%.5gs\n", t/1e9);
} else { } else if (profile>0) {
res = execBlockInline(block, gsc); if (CATCH) { profiler_stop(); profiler_free(); rethrow(); }
} if (profiler_alloc() && profiler_start(profile)) {
res = execBlockInline(block, gsc);
profiler_stop();
profiler_displayResults();
profiler_free();
}
popCatch();
} else res = execBlockInline(block, gsc);
ptr_dec(block); ptr_dec(block);
if (output) { if (output) {

View File

@ -6,7 +6,7 @@
#define alSize BN(alSize) #define alSize BN(alSize)
#ifndef MMAP #ifndef MMAP
usz getPageSize(); usz getPageSize();
#define MMAP(SZ) mmap(NULL, (SZ)+getPageSize(), PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0) #define MMAP(SZ) mmap(NULL, (SZ)+getPageSize(), PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
#endif #endif
typedef struct AllocInfo { typedef struct AllocInfo {

176
src/vm.c
View File

@ -996,7 +996,7 @@ static void allocStack(void** curr, void** start, void** end, i32 elSize, i32 co
#if NO_MMAP #if NO_MMAP
void* mem = calloc(sz+ps, 1); void* mem = calloc(sz+ps, 1);
#else #else
void* mem = mmap(NULL, sz+ps, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0); void* mem = mmap(NULL, sz+ps, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (*curr == MAP_FAILED) err("Failed to allocate stack"); if (*curr == MAP_FAILED) err("Failed to allocate stack");
#endif #endif
*curr = *start = mem; *curr = *start = mem;
@ -1231,6 +1231,180 @@ NOINLINE void vm_pstLive() {
vm_pst(envStart, envCurr+1); vm_pst(envStart, envCurr+1);
} }
#if __has_include(<sys/time.h>) && __has_include(<signal.h>) && !NO_MMAP
#include <sys/time.h>
#include <signal.h>
#define PROFILE_BUFFER (1ULL<<29)
typedef struct Profiler_ent {
Comp* comp;
usz bcPos;
} Profiler_ent;
Profiler_ent* profiler_buf_s;
Profiler_ent* profiler_buf_c;
Profiler_ent* profiler_buf_e;
bool profile_buf_full;
void profiler_sigHandler(int x) {
Profiler_ent* bn = profiler_buf_c+1;
if (RARE(bn>=profiler_buf_e)) {
profile_buf_full = true;
return;
}
if (envCurr<envStart) return;
Env e = *envCurr;
Comp* comp = e.sc->body->bl->comp;
i32 bcPos = e.pos&1? ((u32)e.pos)>>1 : BCPOS(e.sc->body, (u32*)e.pos);
*profiler_buf_c = (Profiler_ent){.comp = ptr_inc(comp), .bcPos = bcPos};
profiler_buf_c = bn;
}
static bool setHandler(bool b) {
struct sigaction act = {};
act.sa_handler = b? profiler_sigHandler : SIG_DFL;
if (sigaction(SIGALRM/*SIGPROF*/, &act, NULL)) {
printf("Failed to set profiling signal handler\n");
return false;
}
return true;
}
static bool setTimer(i64 us) {
struct itimerval timer;
timer.it_value.tv_sec=0;
timer.it_value.tv_usec=us;
timer.it_interval.tv_sec=0;
timer.it_interval.tv_usec=us;
if (setitimer(ITIMER_REAL/*ITIMER_PROF*/, &timer, NULL)) {
printf("Failed to start sampling timer\n");
return false;
}
return true;
}
void* profiler_makeMap();
i32 profiler_index(void* mapRaw, B comp);
void profiler_freeMap(void* mapRaw);
bool profiler_alloc() {
profiler_buf_s = profiler_buf_c = mmap(NULL, PROFILE_BUFFER, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (profiler_buf_s == MAP_FAILED) {
fprintf(stderr, "Failed to allocate profiler buffer\n");
return false;
}
profiler_buf_e = profiler_buf_s+PROFILE_BUFFER;
profile_buf_full = false;
return true;
}
void profiler_free() {
munmap(profiler_buf_s, PROFILE_BUFFER);
}
bool profiler_active;
bool profiler_start(i64 hz) {
i64 us = 999999/hz;
profiler_active = true;
return setHandler(true) && setTimer(us);
}
bool profiler_stop() {
if (!profiler_active) return false;
profiler_active = false;
if (profile_buf_full) fprintf(stderr, "Profiler buffer ran out in the middle of execution. Only timings of the start of profiling will be shown.\n");
return setTimer(0) && setHandler(false);
}
usz profiler_getResults(B* compListRes, B* mapListRes, bool keyPath) {
Profiler_ent* c = profiler_buf_s;
B compList = emptyHVec();
B mapList = emptyHVec();
usz compCount = 0;
void* map = profiler_makeMap();
while (c!=profiler_buf_c) {
usz bcPos = c->bcPos;
Comp* comp = c->comp;
B path = comp->path;
if (!q_N(path) && !q_N(comp->src)) {
i32 idx = profiler_index(&map, q_N(path)? tag(comp, OBJ_TAG) : path);
if (idx == compCount) {
compList = vec_addN(compList, tag(comp, OBJ_TAG));
i32* rp;
usz ia = a(comp->src)->ia;
mapList = vec_addN(mapList, m_i32arrv(&rp, ia));
for (i32 i = 0; i < ia; i++) rp[i] = 0;
compCount++;
}
B inds = IGetU(comp->indices, 0); usz cs = o2s(IGetU(inds,bcPos));
// B inde = IGetU(comp->indices, 1); usz ce = o2s(IGetU(inde,bcPos));
i32* cMap = i32arr_ptr(IGetU(mapList, idx));
// for (usz i = cs; i <= ce; i++) cMap[i]++;
cMap[cs]++;
}
c++;
}
profiler_freeMap(map);
*compListRes = compList;
*mapListRes = mapList;
return compCount;
}
void profiler_displayResults() {
printf("Got "N64u" samples\n", (u64)(profiler_buf_c-profiler_buf_s));
B compList, mapList;
usz compCount = profiler_getResults(&compList, &mapList, true);
SGetU(compList) SGetU(mapList)
for (usz i = 0; i < compCount; i++) {
Comp* c = c(Comp, GetU(compList, i));
i32* m = i32arr_ptr(GetU(mapList, i));
if (!q_N(c->src)) {
if (q_N(c->path)) printf("unknown:");
else printRaw(c->path);
printf(":\n");
B src = c->src;
SGetU(src)
usz sia = a(src)->ia;
usz pi = 0;
i32 curr = 0;
for (usz i = 0; i < sia; i++) {
u32 c = o2cu(GetU(src, i));
curr+= m[i];
if (c=='\n' || i==sia-1) {
Arr* sl = TI(src,slice)(inc(src), pi, i-pi); arr_shVec(sl);
if (curr==0) printf("");
else printf("%6d│", curr);
printRaw(taga(sl));
printf("\n");
ptr_dec(sl);
curr = 0;
pi = i+1;
}
}
}
}
dec(compList);
dec(mapList);
}
#else
bool profiler_alloc() {
printf("Profiler not supported\n");
return false;
}
bool profiler_start(i64 hz) { return false; }
bool profiler_stop() { return false; }
void profiler_free() { thrM("Profiler not supported"); }
usz profiler_getResults(B* compListRes, B* mapListRes, bool keyPath) { thrM("Profiler not supported"); }
void profiler_displayResults() { thrM("Profiler not supported"); }
#endif
void unwindEnv(Env* envNew) { void unwindEnv(Env* envNew) {
assert(envNew<=envCurr); assert(envNew<=envCurr);
while (envCurr!=envNew) { while (envCurr!=envNew) {