add quickjs cpu profiling
This commit is contained in:
parent
ef802bb6f2
commit
90940b42f5
|
@ -1509,10 +1509,8 @@ bbox.fromobjs = function(objs)
|
|||
|
||||
/* VECTORS */
|
||||
var Vector = {};
|
||||
Vector.length = function(v) {
|
||||
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
Vector.length = function(v) { return Math.hypot(...v); }
|
||||
|
||||
Vector.norm = function(v) {
|
||||
var len = Vector.length(v);
|
||||
if (!len) return [0,0];
|
||||
|
|
|
@ -79,6 +79,65 @@ profile.cpu = function(fn, times = 1, q = "unnamed") {
|
|||
profile.ms = function(t) { return t/1000000; }
|
||||
profile.secs = function(t) { return t/1000000000; }
|
||||
|
||||
|
||||
var callgraph = {};
|
||||
var st = profile.now();
|
||||
|
||||
function add_callgraph(line, time) {
|
||||
callgraph[line] ??= 0;
|
||||
callgraph[line] += time;
|
||||
}
|
||||
|
||||
profile.gather(500, function() {
|
||||
var time = profile.now()-st;
|
||||
|
||||
var err = new Error();
|
||||
var stack = err.stack.split("\n");
|
||||
stack = stack.slice(1);
|
||||
stack = stack.map(x => x.slice(7).split(' '));
|
||||
var lines = stack.map(x => x[1]).filter(x => x);
|
||||
lines = lines.map(x => x.slice(1,x.length-1));
|
||||
|
||||
lines.forEach(x => add_callgraph(x,time));
|
||||
st = profile.now();
|
||||
|
||||
profile.gather_rate(400+Math.random()*200);
|
||||
});
|
||||
|
||||
var filecache = {};
|
||||
function get_line(file, line) {
|
||||
var text = filecache[file];
|
||||
if (!text) {
|
||||
var f = io.slurp(file);
|
||||
if (!f) {
|
||||
filecache[file] = "undefined";
|
||||
return filecache[file];
|
||||
}
|
||||
filecache[file] = io.slurp(file).split('\n');
|
||||
text = filecache[file];
|
||||
}
|
||||
|
||||
if (typeof text === 'string') return text;
|
||||
text = text[Number(line)-1];
|
||||
if (!text) return "NULL";
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
prosperon.quit_hook = function()
|
||||
{
|
||||
var e = Object.entries(callgraph);
|
||||
e = e.sort((a,b) => {
|
||||
if (a[1] > b[1]) return -1;
|
||||
return 1;
|
||||
});
|
||||
|
||||
e.forEach(x => {
|
||||
var ffs = x[0].split(':');
|
||||
var time = profile.best_t(x[1]);
|
||||
say(x[0] + '::' + time + ':: ' + get_line(ffs[0], ffs[1]));
|
||||
});
|
||||
}
|
||||
|
||||
/* These controls are available during editing, and during play of debug builds */
|
||||
debug.inputs = {};
|
||||
debug.inputs.f1 = function () { debug.draw_phys = !debug.draw_phys; };
|
||||
|
|
|
@ -651,6 +651,7 @@ prosperon.clipboardpaste = function (str) {};
|
|||
prosperon.quit = function () {
|
||||
say(profile.printreport(profcache, "USE REPORT"));
|
||||
say(profile.printreport(entityreport, "ENTITY REPORT"));
|
||||
if (prosperon.quit_hook) prosperon.quit_hook();
|
||||
|
||||
console.info("QUITTING");
|
||||
for (var i in debug.log.time)
|
||||
|
|
|
@ -89,8 +89,7 @@ emitter.step = function(dt)
|
|||
// update all particles
|
||||
for (var p of Object.values(this.particles)) {
|
||||
p.time += dt;
|
||||
|
||||
this.step_hook(p);
|
||||
this.step_hook?.(p);
|
||||
|
||||
if (p.time >= p.life) {
|
||||
this.die_hook(p);
|
||||
|
|
|
@ -492,7 +492,8 @@ render.init = function() {
|
|||
}
|
||||
}
|
||||
|
||||
render.sprites = function(gridsize = 1)
|
||||
render.mixin({
|
||||
sprites(gridsize = 1)
|
||||
{
|
||||
var sps = Object.values(allsprites);
|
||||
var sprite_buckets = {};
|
||||
|
@ -514,7 +515,7 @@ render.sprites = function(gridsize = 1)
|
|||
render.draw(shape.quad, sprite_ssbo, sparray.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}});
|
||||
|
||||
render.circle = function(pos, radius, color) {
|
||||
check_flush();
|
||||
|
|
|
@ -1194,10 +1194,21 @@ JSC_CCALL(vector_inflate,
|
|||
arrfree(p);
|
||||
)
|
||||
|
||||
JSC_CCALL(vector_rotate,
|
||||
HMM_Vec2 vec = js2vec2(argv[0]);
|
||||
float r = HMM_LenV2(vec);
|
||||
double angle = js2angle(argv[1]);
|
||||
angle += atan2(vec.y,vec.x);
|
||||
vec.x = r*cos(angle);
|
||||
vec.y = r*sin(angle);
|
||||
return vec22js(vec);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_vector_funcs[] = {
|
||||
MIST_FUNC_DEF(vector,dot,2),
|
||||
MIST_FUNC_DEF(vector,project,2),
|
||||
MIST_FUNC_DEF(vector, inflate, 2)
|
||||
MIST_FUNC_DEF(vector, inflate, 2),
|
||||
MIST_FUNC_DEF(vector, rotate, 2)
|
||||
};
|
||||
|
||||
JSC_CCALL(game_engine_start, engine_start(argv[0],argv[1], js2number(argv[2]), js2number(argv[3])))
|
||||
|
@ -1299,8 +1310,27 @@ static const JSCFunctionListEntry js_audio_funcs[] = {
|
|||
|
||||
JSC_CCALL(profile_now, return number2js(stm_now()))
|
||||
|
||||
static JSValue instr_v = JS_UNDEFINED;
|
||||
int iiihandle(JSRuntime *rt, void *data)
|
||||
{
|
||||
script_call_sym(instr_v, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSC_CCALL(profile_gather,
|
||||
int count = js2number(argv[0]);
|
||||
instr_v = JS_DupValue(js, argv[1]);
|
||||
JS_SetInterruptHandler(rt, iiihandle, NULL, count);
|
||||
)
|
||||
|
||||
JSC_CCALL(profile_gather_rate,
|
||||
JS_SetInterruptRate(js2number(argv[0]));
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_profile_funcs[] = {
|
||||
MIST_FUNC_DEF(profile,now,0),
|
||||
MIST_FUNC_DEF(profile,gather,2),
|
||||
MIST_FUNC_DEF(profile,gather_rate,1)
|
||||
};
|
||||
|
||||
JSC_SCALL(io_exists, ret = boolean2js(fexists(str)))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "jsffi.h"
|
||||
#include "stb_ds.h"
|
||||
#include "resources.h"
|
||||
#include <sokol/sokol_time.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ extern "C" {
|
|||
#include <time.h>
|
||||
|
||||
extern JSContext *js;
|
||||
extern JSRuntime *rt;
|
||||
|
||||
struct phys_cbs {
|
||||
JSValue begin;
|
||||
|
|
10
source/engine/thirdparty/quickjs/quickjs.c
vendored
10
source/engine/thirdparty/quickjs/quickjs.c
vendored
|
@ -429,7 +429,7 @@ typedef enum {
|
|||
|
||||
/* must be large enough to have a negligible runtime cost and small
|
||||
enough to call the interrupt callback often. */
|
||||
#define JS_INTERRUPT_COUNTER_INIT 10000
|
||||
static int JS_INTERRUPT_COUNTER_INIT = 1000;
|
||||
|
||||
struct JSContext {
|
||||
JSGCObjectHeader header; /* must come first */
|
||||
|
@ -1813,10 +1813,16 @@ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
|
|||
#define free(p) free_is_forbidden(p)
|
||||
#define realloc(p,s) realloc_is_forbidden(p,s)
|
||||
|
||||
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
|
||||
void JS_SetInterruptRate(int count)
|
||||
{
|
||||
JS_INTERRUPT_COUNTER_INIT = count;
|
||||
}
|
||||
|
||||
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque, int count)
|
||||
{
|
||||
rt->interrupt_handler = cb;
|
||||
rt->interrupt_opaque = opaque;
|
||||
JS_INTERRUPT_COUNTER_INIT = count;
|
||||
}
|
||||
|
||||
void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
|
||||
|
|
3
source/engine/thirdparty/quickjs/quickjs.h
vendored
3
source/engine/thirdparty/quickjs/quickjs.h
vendored
|
@ -855,7 +855,8 @@ void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTrac
|
|||
|
||||
/* return != 0 if the JS code needs to be interrupted */
|
||||
typedef int JSInterruptHandler(JSRuntime *rt, void *opaque);
|
||||
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque);
|
||||
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque, int count);
|
||||
void JS_SetInterruptRate(int count);
|
||||
/* if can_block is TRUE, Atomics.wait() can be used */
|
||||
void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);
|
||||
/* set the [IsHTMLDDA] internal slot */
|
||||
|
|
Loading…
Reference in a new issue