add quickjs cpu profiling
This commit is contained in:
parent
ef802bb6f2
commit
90940b42f5
|
@ -1509,10 +1509,8 @@ bbox.fromobjs = function(objs)
|
||||||
|
|
||||||
/* VECTORS */
|
/* VECTORS */
|
||||||
var Vector = {};
|
var Vector = {};
|
||||||
Vector.length = function(v) {
|
Vector.length = function(v) { return Math.hypot(...v); }
|
||||||
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
|
||||||
return Math.sqrt(sum);
|
|
||||||
}
|
|
||||||
Vector.norm = function(v) {
|
Vector.norm = function(v) {
|
||||||
var len = Vector.length(v);
|
var len = Vector.length(v);
|
||||||
if (!len) return [0,0];
|
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.ms = function(t) { return t/1000000; }
|
||||||
profile.secs = function(t) { return t/1000000000; }
|
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 */
|
/* These controls are available during editing, and during play of debug builds */
|
||||||
debug.inputs = {};
|
debug.inputs = {};
|
||||||
debug.inputs.f1 = function () { debug.draw_phys = !debug.draw_phys; };
|
debug.inputs.f1 = function () { debug.draw_phys = !debug.draw_phys; };
|
||||||
|
|
|
@ -651,6 +651,7 @@ prosperon.clipboardpaste = function (str) {};
|
||||||
prosperon.quit = function () {
|
prosperon.quit = function () {
|
||||||
say(profile.printreport(profcache, "USE REPORT"));
|
say(profile.printreport(profcache, "USE REPORT"));
|
||||||
say(profile.printreport(entityreport, "ENTITY REPORT"));
|
say(profile.printreport(entityreport, "ENTITY REPORT"));
|
||||||
|
if (prosperon.quit_hook) prosperon.quit_hook();
|
||||||
|
|
||||||
console.info("QUITTING");
|
console.info("QUITTING");
|
||||||
for (var i in debug.log.time)
|
for (var i in debug.log.time)
|
||||||
|
|
|
@ -89,8 +89,7 @@ emitter.step = function(dt)
|
||||||
// update all particles
|
// update all particles
|
||||||
for (var p of Object.values(this.particles)) {
|
for (var p of Object.values(this.particles)) {
|
||||||
p.time += dt;
|
p.time += dt;
|
||||||
|
this.step_hook?.(p);
|
||||||
this.step_hook(p);
|
|
||||||
|
|
||||||
if (p.time >= p.life) {
|
if (p.time >= p.life) {
|
||||||
this.die_hook(p);
|
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 sps = Object.values(allsprites);
|
||||||
var sprite_buckets = {};
|
var sprite_buckets = {};
|
||||||
|
@ -514,7 +515,7 @@ render.sprites = function(gridsize = 1)
|
||||||
render.draw(shape.quad, sprite_ssbo, sparray.length);
|
render.draw(shape.quad, sprite_ssbo, sparray.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}});
|
||||||
|
|
||||||
render.circle = function(pos, radius, color) {
|
render.circle = function(pos, radius, color) {
|
||||||
check_flush();
|
check_flush();
|
||||||
|
|
|
@ -1194,10 +1194,21 @@ JSC_CCALL(vector_inflate,
|
||||||
arrfree(p);
|
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[] = {
|
static const JSCFunctionListEntry js_vector_funcs[] = {
|
||||||
MIST_FUNC_DEF(vector,dot,2),
|
MIST_FUNC_DEF(vector,dot,2),
|
||||||
MIST_FUNC_DEF(vector,project,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])))
|
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()))
|
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[] = {
|
static const JSCFunctionListEntry js_profile_funcs[] = {
|
||||||
MIST_FUNC_DEF(profile,now,0),
|
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)))
|
JSC_SCALL(io_exists, ret = boolean2js(fexists(str)))
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "jsffi.h"
|
#include "jsffi.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
|
#include <sokol/sokol_time.h>
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern "C" {
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
extern JSContext *js;
|
extern JSContext *js;
|
||||||
|
extern JSRuntime *rt;
|
||||||
|
|
||||||
struct phys_cbs {
|
struct phys_cbs {
|
||||||
JSValue begin;
|
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
|
/* must be large enough to have a negligible runtime cost and small
|
||||||
enough to call the interrupt callback often. */
|
enough to call the interrupt callback often. */
|
||||||
#define JS_INTERRUPT_COUNTER_INIT 10000
|
static int JS_INTERRUPT_COUNTER_INIT = 1000;
|
||||||
|
|
||||||
struct JSContext {
|
struct JSContext {
|
||||||
JSGCObjectHeader header; /* must come first */
|
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 free(p) free_is_forbidden(p)
|
||||||
#define realloc(p,s) realloc_is_forbidden(p,s)
|
#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_handler = cb;
|
||||||
rt->interrupt_opaque = opaque;
|
rt->interrupt_opaque = opaque;
|
||||||
|
JS_INTERRUPT_COUNTER_INIT = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
|
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 */
|
/* return != 0 if the JS code needs to be interrupted */
|
||||||
typedef int JSInterruptHandler(JSRuntime *rt, void *opaque);
|
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 */
|
/* if can_block is TRUE, Atomics.wait() can be used */
|
||||||
void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);
|
void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);
|
||||||
/* set the [IsHTMLDDA] internal slot */
|
/* set the [IsHTMLDDA] internal slot */
|
||||||
|
|
Loading…
Reference in a new issue