add profiling
This commit is contained in:
parent
90940b42f5
commit
cb6f64925e
9
docs/engine_tour/profiling.md
Normal file
9
docs/engine_tour/profiling.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Profiling
|
||||||
|
|
||||||
|
There are a handful of profiling methods available to you.
|
||||||
|
|
||||||
|
## Frame by frame profile
|
||||||
|
|
||||||
|
## Cpu instrumentation
|
||||||
|
|
||||||
|
## Game stats
|
|
@ -12,6 +12,7 @@ actor.spawn = function(script, config, callback){
|
||||||
padawan.timers = [];
|
padawan.timers = [];
|
||||||
padawan.master = this;
|
padawan.master = this;
|
||||||
Object.hide(padawan, "master", "timers", "padawans");
|
Object.hide(padawan, "master", "timers", "padawans");
|
||||||
|
padawan.toString = function() { return script; }
|
||||||
check_registers(padawan);
|
check_registers(padawan);
|
||||||
this.padawans.push(padawan);
|
this.padawans.push(padawan);
|
||||||
return padawan;
|
return padawan;
|
||||||
|
|
|
@ -1033,6 +1033,19 @@ value: function(b) {
|
||||||
return c;
|
return c;
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
/*Object.defineProperty(Array.prototype, 'concat', {
|
||||||
|
value: function(b) {
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < this.length; i++)
|
||||||
|
result.push(this[i]);
|
||||||
|
|
||||||
|
for (var i = 0; i < b.length; i++)
|
||||||
|
result.push(b[i]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, 'normalized', {
|
Object.defineProperty(Array.prototype, 'normalized', {
|
||||||
value: function() {
|
value: function() {
|
||||||
var c = this.slice();
|
var c = this.slice();
|
||||||
|
@ -1377,6 +1390,7 @@ Math.rad2turn = function(x) { return x/Math.TAU; };
|
||||||
Math.turn2deg = function(x) { return x*360; };
|
Math.turn2deg = function(x) { return x*360; };
|
||||||
Math.deg2turn = function(x) { return x/360; };
|
Math.deg2turn = function(x) { return x/360; };
|
||||||
Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); };
|
Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); };
|
||||||
|
Math.variate = function(n, pct) { return n + (Math.random_range(-pct,pct)*n); }
|
||||||
|
|
||||||
/* BOUNDINGBOXES */
|
/* BOUNDINGBOXES */
|
||||||
var bbox = {};
|
var bbox = {};
|
||||||
|
|
|
@ -64,80 +64,6 @@ var Gizmos = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
profile.cpu = function(fn, times = 1, q = "unnamed") {
|
|
||||||
var start = profile.now();
|
|
||||||
for (var i = 0; i < times; i++)
|
|
||||||
fn();
|
|
||||||
|
|
||||||
var elapsed = profile.now() - start;
|
|
||||||
var avgt = profile.best_t(elapsed/times);
|
|
||||||
var totalt = profile.best_t(elapsed);
|
|
||||||
|
|
||||||
say(`profile [${q}]: ${profile.best_t(avgt)} average [${profile.best_t(totalt)} for ${times} loops]`);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
/* 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; };
|
||||||
|
|
|
@ -110,37 +110,7 @@ Resources.find_script = function (file) {
|
||||||
return find_ext(file, Resources.scripts);
|
return find_ext(file, Resources.scripts);
|
||||||
};
|
};
|
||||||
|
|
||||||
profile.best_t = function (t) {
|
var t_units = ["ns", "us", "ms", "s", "m", "h"];
|
||||||
var qq = "ns";
|
|
||||||
if (t > 1000) {
|
|
||||||
t /= 1000;
|
|
||||||
qq = "us";
|
|
||||||
if (t > 1000) {
|
|
||||||
t /= 1000;
|
|
||||||
qq = "ms";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return `${t.toPrecision(4)} ${qq}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
profile.report = function (start, msg = "[undefined report]") {
|
|
||||||
console.info(`${msg} in ${profile.best_t(profile.now() - start)}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
profile.addreport = function (cache, line, start) {
|
|
||||||
cache ??= profcache;
|
|
||||||
cache[line] ??= [];
|
|
||||||
cache[line].push(profile.now() - start);
|
|
||||||
return profile.now();
|
|
||||||
};
|
|
||||||
|
|
||||||
profile.printreport = function (cache, name) {
|
|
||||||
var report = name + "\n";
|
|
||||||
for (var i in cache)
|
|
||||||
report += `${i} ${profile.best_t(cache[i].reduce((a, b) => a + b) / cache[i].length)}\n`;
|
|
||||||
|
|
||||||
return report;
|
|
||||||
};
|
|
||||||
|
|
||||||
console.transcript = "";
|
console.transcript = "";
|
||||||
console.say = function (msg) {
|
console.say = function (msg) {
|
||||||
|
@ -218,17 +188,17 @@ console.doc = {
|
||||||
|
|
||||||
globalThis.global = globalThis;
|
globalThis.global = globalThis;
|
||||||
|
|
||||||
var profcache = {};
|
var use_prof = "USE";
|
||||||
|
|
||||||
|
profile.addreport = function(){};
|
||||||
|
|
||||||
function use(file, env = {}, script) {
|
function use(file, env = {}, script) {
|
||||||
file = Resources.find_script(file);
|
file = Resources.find_script(file);
|
||||||
var st = profile.now();
|
var st = profile.now();
|
||||||
|
|
||||||
profcache[file] ??= [];
|
|
||||||
|
|
||||||
if (use.cache[file]) {
|
if (use.cache[file]) {
|
||||||
var ret = use.cache[file].call(env);
|
var ret = use.cache[file].call(env);
|
||||||
profile.addreport(profcache, file, st);
|
profile.addreport(use_prof, file, st);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
script ??= Resources.replstrs(file);
|
script ??= Resources.replstrs(file);
|
||||||
|
@ -236,16 +206,21 @@ function use(file, env = {}, script) {
|
||||||
var fn = os.eval(file, script);
|
var fn = os.eval(file, script);
|
||||||
use.cache[file] = fn;
|
use.cache[file] = fn;
|
||||||
var ret = fn.call(env);
|
var ret = fn.call(env);
|
||||||
profile.addreport(profcache, file, st);
|
profile.addreport(use_prof, file, st);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
use.cache = {};
|
use.cache = {};
|
||||||
|
|
||||||
global.check_registers = function (obj) {
|
global.check_registers = function (obj) {
|
||||||
for (var reg in Register.registries)
|
for (var reg in Register.registries) {
|
||||||
if (typeof obj[reg] === 'function')
|
if (typeof obj[reg] === 'function') {
|
||||||
obj.timers.push(Register.registries[reg].register(obj[reg].bind(obj)));
|
var fn = obj[reg].bind(obj);
|
||||||
|
var name = obj.ur ? obj.ur.name : obj.toString();
|
||||||
|
obj.timers.push(Register.registries[reg].register(fn, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (var k in obj) {
|
for (var k in obj) {
|
||||||
if (!k.startswith("on_")) continue;
|
if (!k.startswith("on_")) continue;
|
||||||
var signal = k.fromfirst("on_");
|
var signal = k.fromfirst("on_");
|
||||||
|
@ -255,6 +230,7 @@ global.check_registers = function (obj) {
|
||||||
|
|
||||||
Object.assign(global, use("scripts/base"));
|
Object.assign(global, use("scripts/base"));
|
||||||
global.obscure("global");
|
global.obscure("global");
|
||||||
|
global.mixin("scripts/profile");
|
||||||
global.mixin("scripts/render");
|
global.mixin("scripts/render");
|
||||||
global.mixin("scripts/debug");
|
global.mixin("scripts/debug");
|
||||||
|
|
||||||
|
@ -452,6 +428,7 @@ var screencolor;
|
||||||
|
|
||||||
prosperon.render = function()
|
prosperon.render = function()
|
||||||
{
|
{
|
||||||
|
profile.frame("world");
|
||||||
render.set_camera(camera);
|
render.set_camera(camera);
|
||||||
render.sprites();
|
render.sprites();
|
||||||
prosperon.draw();
|
prosperon.draw();
|
||||||
|
@ -459,11 +436,17 @@ prosperon.render = function()
|
||||||
hudcam.transform.pos = [hudcam.size.x/2, hudcam.size.y/2, -100];
|
hudcam.transform.pos = [hudcam.size.x/2, hudcam.size.y/2, -100];
|
||||||
render.set_camera(hudcam);
|
render.set_camera(hudcam);
|
||||||
|
|
||||||
|
profile.endframe();
|
||||||
|
profile.frame("hud");
|
||||||
|
|
||||||
prosperon.hud();
|
prosperon.hud();
|
||||||
render.flush_text();
|
render.flush_text();
|
||||||
|
|
||||||
render.end_pass();
|
render.end_pass();
|
||||||
|
|
||||||
|
profile.endframe();
|
||||||
|
|
||||||
|
profile.frame("post process");
|
||||||
/* draw the image of the game world first */
|
/* draw the image of the game world first */
|
||||||
render.glue_pass();
|
render.glue_pass();
|
||||||
render.viewport(...camera.view());
|
render.viewport(...camera.view());
|
||||||
|
@ -471,6 +454,10 @@ prosperon.render = function()
|
||||||
render.use_mat({diffuse:screencolor});
|
render.use_mat({diffuse:screencolor});
|
||||||
render.draw(shape.quad);
|
render.draw(shape.quad);
|
||||||
|
|
||||||
|
profile.endframe();
|
||||||
|
|
||||||
|
profile.frame("app");
|
||||||
|
|
||||||
// Flush & render
|
// Flush & render
|
||||||
appcam.transform.pos = [window.size.x/2, window.size.y/2, -100];
|
appcam.transform.pos = [window.size.x/2, window.size.y/2, -100];
|
||||||
appcam.size = window.size.slice();
|
appcam.size = window.size.slice();
|
||||||
|
@ -488,49 +475,65 @@ prosperon.render = function()
|
||||||
render.flush_text();
|
render.flush_text();
|
||||||
mum.style = mum.base;
|
mum.style = mum.base;
|
||||||
|
|
||||||
|
profile.endframe();
|
||||||
|
|
||||||
|
profile.frame("imgui");
|
||||||
|
|
||||||
render.imgui_new(window.size.x, window.size.y, 0.01);
|
render.imgui_new(window.size.x, window.size.y, 0.01);
|
||||||
// if (gfx_gui) render.gfx_gui();
|
prosperon.imgui();
|
||||||
render.imgui_end();
|
render.imgui_end();
|
||||||
|
|
||||||
|
profile.endframe();
|
||||||
|
|
||||||
render.end_pass();
|
render.end_pass();
|
||||||
render.commit();
|
render.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function process() {
|
function process() {
|
||||||
var startframe = profile.now();
|
profile.frame("frame");
|
||||||
var dt = profile.secs(profile.now()) - frame_t;
|
var dt = profile.secs(profile.now()) - frame_t;
|
||||||
frame_t = profile.secs(profile.now());
|
frame_t = profile.secs(profile.now());
|
||||||
|
|
||||||
|
profile.frame("app update");
|
||||||
prosperon.appupdate(dt);
|
prosperon.appupdate(dt);
|
||||||
|
profile.endframe();
|
||||||
|
|
||||||
|
profile.frame("input");
|
||||||
input.procdown();
|
input.procdown();
|
||||||
|
profile.endframe();
|
||||||
|
|
||||||
if (sim.mode === "play" || sim.mode === "step") {
|
if (sim.mode === "play" || sim.mode === "step") {
|
||||||
|
profile.frame("update");
|
||||||
prosperon.update(dt * game.timescale);
|
prosperon.update(dt * game.timescale);
|
||||||
|
profile.endframe();
|
||||||
if (sim.mode === "step") sim.pause();
|
if (sim.mode === "step") sim.pause();
|
||||||
|
|
||||||
|
profile.frame("physics");
|
||||||
physlag += dt;
|
physlag += dt;
|
||||||
|
|
||||||
while (physlag > physics.delta) {
|
while (physlag > physics.delta) {
|
||||||
physlag -= physics.delta;
|
physlag -= physics.delta;
|
||||||
var st = profile.now();
|
|
||||||
prosperon.phys2d_step(physics.delta * game.timescale);
|
prosperon.phys2d_step(physics.delta * game.timescale);
|
||||||
prosperon.physupdate(physics.delta * game.timescale);
|
prosperon.physupdate(physics.delta * game.timescale);
|
||||||
profile.addreport(profcache, "physics step", st);
|
|
||||||
}
|
}
|
||||||
|
profile.endframe();
|
||||||
}
|
}
|
||||||
var st = profile.now();
|
|
||||||
|
profile.frame("window render");
|
||||||
prosperon.window_render(window.size);
|
prosperon.window_render(window.size);
|
||||||
profile.addreport(null, "window render", st);
|
profile.endframe();
|
||||||
|
profile.frame("render");
|
||||||
prosperon.render();
|
prosperon.render();
|
||||||
profile.addreport(profcache, "render frame", st);
|
profile.endframe();
|
||||||
frames.push(profile.secs(profile.now() - startframe));
|
|
||||||
if (frames.length > 20) frames.shift();
|
profile.endframe();
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.fps = function () {
|
globalThis.fps = function () {
|
||||||
var sum = 0;
|
return 0;
|
||||||
for (var i = 0; i < frames.length; i++) sum += frames[i];
|
// var sum = 0;
|
||||||
return frames.length / sum;
|
// for (var i = 0; i < frames.length; i++) sum += frames[i];
|
||||||
|
// return frames.length / sum;
|
||||||
};
|
};
|
||||||
|
|
||||||
game.timescale = 1;
|
game.timescale = 1;
|
||||||
|
@ -649,9 +652,16 @@ prosperon.touchrelease = function (touches) {};
|
||||||
prosperon.touchmove = function (touches) {};
|
prosperon.touchmove = function (touches) {};
|
||||||
prosperon.clipboardpaste = function (str) {};
|
prosperon.clipboardpaste = function (str) {};
|
||||||
prosperon.quit = function () {
|
prosperon.quit = function () {
|
||||||
say(profile.printreport(profcache, "USE REPORT"));
|
say("===START CACHE REPORTS===\n");
|
||||||
say(profile.printreport(entityreport, "ENTITY REPORT"));
|
for (var i in profile.report_cache) {
|
||||||
if (prosperon.quit_hook) prosperon.quit_hook();
|
say(profile.printreport(profile.report_cache[i],i));
|
||||||
|
}
|
||||||
|
|
||||||
|
say("===FRAME AVERAGES===\n");
|
||||||
|
say(profile.print_frame_avg());
|
||||||
|
say("\n");
|
||||||
|
|
||||||
|
profile.print_cpu_instr();
|
||||||
|
|
||||||
console.info("QUITTING");
|
console.info("QUITTING");
|
||||||
for (var i in debug.log.time)
|
for (var i in debug.log.time)
|
||||||
|
@ -718,17 +728,25 @@ var Register = {
|
||||||
var n = {};
|
var n = {};
|
||||||
var fns = [];
|
var fns = [];
|
||||||
|
|
||||||
n.register = function (fn, obj) {
|
n.register = function (fn, oname) {
|
||||||
if (typeof fn !== "function") return;
|
if (typeof fn !== "function") return;
|
||||||
if (typeof obj === "object") fn = fn.bind(obj);
|
|
||||||
fns.push(fn);
|
var dofn = function(...args) {
|
||||||
|
var st = profile.now();
|
||||||
|
fn(...args);
|
||||||
|
profile.addreport(name, oname, st);
|
||||||
|
}
|
||||||
|
|
||||||
|
fns.push(dofn);
|
||||||
return function () {
|
return function () {
|
||||||
fns.remove(fn);
|
fns.remove(dofn);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
prosperon[name] = function (...args) {
|
prosperon[name] = function (...args) {
|
||||||
fns.forEach((x) => x(...args));
|
fns.forEach(x => x(...args));
|
||||||
};
|
};
|
||||||
|
|
||||||
prosperon[name].fns = fns;
|
prosperon[name].fns = fns;
|
||||||
n.clear = function () {
|
n.clear = function () {
|
||||||
fns = [];
|
fns = [];
|
||||||
|
@ -750,6 +768,7 @@ Register.add_cb("draw_dbg", true);
|
||||||
Register.add_cb("gui_dbg", true);
|
Register.add_cb("gui_dbg", true);
|
||||||
Register.add_cb("hud_dbg", true);
|
Register.add_cb("hud_dbg", true);
|
||||||
Register.add_cb("draw", true);
|
Register.add_cb("draw", true);
|
||||||
|
Register.add_cb("imgui", true);
|
||||||
|
|
||||||
var Event = {
|
var Event = {
|
||||||
events: {},
|
events: {},
|
||||||
|
|
|
@ -230,7 +230,7 @@ var entity = {
|
||||||
for (var i in ent.objects)
|
for (var i in ent.objects)
|
||||||
ent.ur.fresh.objects[i] = ent.objects[i].instance_obj();
|
ent.ur.fresh.objects[i] = ent.objects[i].instance_obj();
|
||||||
|
|
||||||
profile.addreport(entityreport, ent.ur.name, st);
|
profile.addreport("ENTITY TIME", ent.ur.name, st);
|
||||||
|
|
||||||
return ent;
|
return ent;
|
||||||
},
|
},
|
||||||
|
@ -677,7 +677,10 @@ var getur = function(text, data)
|
||||||
name: "empty"
|
name: "empty"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var urstr = text + "+" + data;
|
var urstr = text;
|
||||||
|
if (data)
|
||||||
|
urstr += "+" + data;
|
||||||
|
|
||||||
if (!ur[urstr]) {
|
if (!ur[urstr]) {
|
||||||
ur[urstr] = {
|
ur[urstr] = {
|
||||||
name: urstr,
|
name: urstr,
|
||||||
|
|
178
scripts/profile.js
Normal file
178
scripts/profile.js
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
profile.cpu = function(fn, times = 1, q = "unnamed") {
|
||||||
|
var start = profile.now();
|
||||||
|
for (var i = 0; i < times; i++)
|
||||||
|
fn();
|
||||||
|
|
||||||
|
var elapsed = profile.now() - start;
|
||||||
|
var avgt = profile.best_t(elapsed/times);
|
||||||
|
var totalt = profile.best_t(elapsed);
|
||||||
|
|
||||||
|
say(`profile [${q}]: ${profile.best_t(avgt)} average [${profile.best_t(totalt)} for ${times} loops]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.ms = function(t) { return t/1000000; }
|
||||||
|
profile.secs = function(t) { return t/1000000000; }
|
||||||
|
|
||||||
|
var callgraph = {};
|
||||||
|
var st = profile.now();
|
||||||
|
|
||||||
|
function add_callgraph(fn, line, time) {
|
||||||
|
var cc = callgraph[line];
|
||||||
|
if (!cc) {
|
||||||
|
var cc = {};
|
||||||
|
callgraph[line] = cc;
|
||||||
|
cc.time = 0;
|
||||||
|
cc.hits = 0;
|
||||||
|
cc.fn = fn;
|
||||||
|
cc.line = line;
|
||||||
|
}
|
||||||
|
cc.time += time;
|
||||||
|
cc.hits++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hittar = 500;
|
||||||
|
var hitpct = 0.2;
|
||||||
|
var start_gather = profile.now();
|
||||||
|
profile.gather(hittar, 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 fns = stack.map(x => x[0]).filter(x=>x);
|
||||||
|
var lines = stack.map(x => x[1]).filter(x => x);
|
||||||
|
lines = lines.map(x => x.slice(1,x.length-1));
|
||||||
|
|
||||||
|
for (var i = 0; i < fns.length; i++)
|
||||||
|
add_callgraph(fns[i], lines[i], time);
|
||||||
|
|
||||||
|
st = profile.now();
|
||||||
|
|
||||||
|
profile.gather_rate(Math.variate(hittar,hitpct));
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.print_cpu_instr = function()
|
||||||
|
{
|
||||||
|
say("===CPU INSTRUMENTATION===\n");
|
||||||
|
var gather_time = profile.now()-start_gather;
|
||||||
|
var e = Object.values(callgraph);
|
||||||
|
e = e.sort((a,b) => {
|
||||||
|
if (a.time > b.time) return -1;
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
e.forEach(x => {
|
||||||
|
var ffs = x.line.split(':');
|
||||||
|
var time = profile.best_t(x.time);
|
||||||
|
var pct = x.time/gather_time*100;
|
||||||
|
say(`${x.line}::${x.fn}:: ${time} (${pct.toPrecision(3)}%) (${x.hits} hits) --> ${get_line(ffs[0], ffs[1])}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.best_t = function (t) {
|
||||||
|
var qq = 0;
|
||||||
|
while (t > 1000 && qq < t_units.length-1) {
|
||||||
|
t /= 1000;
|
||||||
|
qq++;
|
||||||
|
}
|
||||||
|
return `${t.toPrecision(4)} ${t_units[qq]}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
profile.report = function (start, msg = "[undefined report]") { console.info(`${msg} in ${profile.best_t(profile.now() - start)}`); };
|
||||||
|
|
||||||
|
var profile_frames = {};
|
||||||
|
var profile_frame_ts = [];
|
||||||
|
var profile_cframe = profile_frames;
|
||||||
|
var profile_frame = 0;
|
||||||
|
profile.frame = function(title)
|
||||||
|
{
|
||||||
|
profile_frame_ts.push(profile_cframe);
|
||||||
|
profile_cframe[title] ??= {};
|
||||||
|
profile_cframe = profile_cframe[title];
|
||||||
|
profile_cframe._times ??= [];
|
||||||
|
profile_cframe._times[profile_frame] = profile.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.endframe = function()
|
||||||
|
{
|
||||||
|
if (profile_cframe === profile_frames) return;
|
||||||
|
profile_cframe._times[profile_frame] = profile.now() - profile_cframe._times[profile_frame];
|
||||||
|
profile_cframe = profile_frame_ts.pop();
|
||||||
|
if (profile_cframe === profile_frames) profile_frame++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var print_frame = function(frame, indent, title)
|
||||||
|
{
|
||||||
|
var avg = frame._times.reduce((sum, e) => sum += e)/frame._times.length;
|
||||||
|
say(indent + `${title} ::::: ${profile.best_t(avg)}`);
|
||||||
|
|
||||||
|
for (var i in frame) {
|
||||||
|
if (i === '_times') continue;
|
||||||
|
print_frame(frame[i], indent + " ", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.print_frame_avg = function()
|
||||||
|
{
|
||||||
|
var indent = "";
|
||||||
|
for (var i in profile_frames)
|
||||||
|
print_frame(profile_frames[i], "", 'frame');
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.report_cache = {};
|
||||||
|
|
||||||
|
profile.addreport = function (group, line, start) {
|
||||||
|
if (typeof group !== 'string') group = 'UNGROUPED';
|
||||||
|
profile.report_cache[group] ??= {};
|
||||||
|
var cache = profile.report_cache[group];
|
||||||
|
cache[line] ??= [];
|
||||||
|
var t = profile.now();
|
||||||
|
cache[line].push(t - start);
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
|
||||||
|
profile.printreport = function (cache, name) {
|
||||||
|
var report = `==${name}==` + "\n";
|
||||||
|
|
||||||
|
var reports = [];
|
||||||
|
for (var i in cache) {
|
||||||
|
var time = cache[i].reduce((a,b)=>a+b);
|
||||||
|
reports.push({
|
||||||
|
time:time,
|
||||||
|
name:i,
|
||||||
|
hits:cache[i].length,
|
||||||
|
avg:time/cache[i].length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
reports = reports.sort((a,b) => {
|
||||||
|
if (a.avg<b.avg) return 1;
|
||||||
|
return -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var rep of reports)
|
||||||
|
report += `${rep.name} ${profile.best_t(rep.avg)} (${rep.hits} hits) (total ${profile.best_t(rep.time)})\n`;
|
||||||
|
|
||||||
|
return report;
|
||||||
|
};
|
|
@ -3,6 +3,7 @@
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "sokol/sokol_app.h"
|
#include "sokol/sokol_app.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "implot.h"
|
||||||
#define SOKOL_IMPL
|
#define SOKOL_IMPL
|
||||||
#include "sokol/util/sokol_imgui.h"
|
#include "sokol/util/sokol_imgui.h"
|
||||||
#include "sokol/util/sokol_gfx_imgui.h"
|
#include "sokol/util/sokol_gfx_imgui.h"
|
||||||
|
@ -12,11 +13,11 @@ static sgimgui_t sgimgui;
|
||||||
#include "jsffi.h"
|
#include "jsffi.h"
|
||||||
|
|
||||||
JSC_CCALL(imgui_begin,
|
JSC_CCALL(imgui_begin,
|
||||||
char *title = js2strdup(argv[0]);
|
char *title = js2strdup(argv[0]);
|
||||||
bool active = true;
|
bool active = true;
|
||||||
ImGui::Begin(title, &active, ImGuiWindowFlags_MenuBar);
|
ImGui::Begin(title, &active, ImGuiWindowFlags_MenuBar);
|
||||||
free(title);
|
free(title);
|
||||||
return boolean2js(active);
|
return boolean2js(active);
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(imgui_end, ImGui::End())
|
JSC_CCALL(imgui_end, ImGui::End())
|
||||||
|
@ -37,6 +38,22 @@ JSC_CCALL(imgui_menuitem,
|
||||||
free(hotkey);
|
free(hotkey);
|
||||||
)
|
)
|
||||||
|
|
||||||
|
JSC_SCALL(imgui_startplot,
|
||||||
|
ImPlot::SetNextAxisToFit(ImAxis_X1);
|
||||||
|
ImPlot::SetNextAxisToFit(ImAxis_Y1);
|
||||||
|
ImPlot::BeginPlot(str);
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(imgui_endplot, ImPlot::EndPlot() )
|
||||||
|
|
||||||
|
JSC_SCALL(imgui_lineplot,
|
||||||
|
double data[js_arrlen(argv[1])];
|
||||||
|
for (int i = 0; i < js_arrlen(argv[1]); i++)
|
||||||
|
data[i] = js2number(js_getpropidx(argv[1], i));
|
||||||
|
|
||||||
|
ImPlot::PlotLine(str, data, js_arrlen(argv[1]));
|
||||||
|
)
|
||||||
|
|
||||||
JSC_CCALL(imgui_beginmenubar, ImGui::BeginMenuBar())
|
JSC_CCALL(imgui_beginmenubar, ImGui::BeginMenuBar())
|
||||||
JSC_CCALL(imgui_endmenubar, ImGui::EndMenuBar())
|
JSC_CCALL(imgui_endmenubar, ImGui::EndMenuBar())
|
||||||
|
|
||||||
|
@ -55,6 +72,9 @@ static const JSCFunctionListEntry js_imgui_funcs[] = {
|
||||||
MIST_FUNC_DEF(imgui, beginmenubar, 0),
|
MIST_FUNC_DEF(imgui, beginmenubar, 0),
|
||||||
MIST_FUNC_DEF(imgui, endmenubar, 0),
|
MIST_FUNC_DEF(imgui, endmenubar, 0),
|
||||||
MIST_FUNC_DEF(imgui, textinput, 2),
|
MIST_FUNC_DEF(imgui, textinput, 2),
|
||||||
|
MIST_FUNC_DEF(imgui, startplot,1),
|
||||||
|
MIST_FUNC_DEF(imgui,endplot,0),
|
||||||
|
MIST_FUNC_DEF(imgui,lineplot,2)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int started = 0;
|
static int started = 0;
|
||||||
|
@ -67,6 +87,8 @@ JSValue gui_init(JSContext *js)
|
||||||
sgimgui_desc_t desc = {0};
|
sgimgui_desc_t desc = {0};
|
||||||
sgimgui_init(&sgimgui, &desc);
|
sgimgui_init(&sgimgui, &desc);
|
||||||
|
|
||||||
|
ImPlot::CreateContext();
|
||||||
|
|
||||||
JSValue imgui = JS_NewObject(js);
|
JSValue imgui = JS_NewObject(js);
|
||||||
JS_SetPropertyFunctionList(js, imgui, js_imgui_funcs, countof(js_imgui_funcs));
|
JS_SetPropertyFunctionList(js, imgui, js_imgui_funcs, countof(js_imgui_funcs));
|
||||||
started = 1;
|
started = 1;
|
||||||
|
|
5885
source/engine/thirdparty/imgui/implot.cpp
vendored
Normal file
5885
source/engine/thirdparty/imgui/implot.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
1297
source/engine/thirdparty/imgui/implot.h
vendored
Normal file
1297
source/engine/thirdparty/imgui/implot.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1669
source/engine/thirdparty/imgui/implot_internal.h
vendored
Normal file
1669
source/engine/thirdparty/imgui/implot_internal.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
2808
source/engine/thirdparty/imgui/implot_items.cpp
vendored
Normal file
2808
source/engine/thirdparty/imgui/implot_items.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue