2023-02-05 09:32:33 +00:00
< html >
< head >
< link rel = "stylesheet" href = "../../css/spectre.min.css" >
2023-05-11 22:00:36 +00:00
2023-11-23 12:52:48 +00:00
< style >
2023-05-11 22:00:36 +00:00
.table_wrapper{
display: block;
overflow-x: auto;
margin-right: 0.8rem;
white-space: nowrap;
}
< / style >
2023-02-05 09:32:33 +00:00
< / head >
< body >
< div id = "content" > < / div >
< script src = "../../core/lib/interface.js" > < / script >
< script >
var domContent = document.getElementById("content");
function download(filename, callback) {
Util.showModal("Downloading power info...");
Util.readStorage(filename, data => {
Util.hideModal();
callback(data);
});
}
function show() {
Util.showModal("Loading...");
domContent.innerHTML = "";
var htmlOverview = `< table class = "table table-striped table-hover" >
2023-02-22 21:01:34 +00:00
< div > This needs "Logging" to be enabled in power manager settings. The deferred function calls table is only updated on the bangle on reloads.< / div >
2023-02-05 09:32:33 +00:00
< thead >
< tr >
< th > Type< / th >
< th > < / th >
< / tr >
< / thead >
< tbody >
< tr >
< td > Deferred function calls< / td >
< td >
< button class = "btn btn-primary" filename = "powermanager.def.json" task = "deftable" > Table< / button >
< button class = "btn btn-error" filename = "powermanager.def.json" task = "clear" style = "float: right;margin-right: 5px;" > Clear< / button >
< / td >
< / tr >
< tr >
2023-02-22 21:01:34 +00:00
< td > Hardware< / td >
2023-02-05 09:32:33 +00:00
< td >
2023-02-22 21:01:34 +00:00
< button class = "btn btn-primary" filename = "powermanager.hw.json" task = "hardwaretable" > Table< / button >
< button class = "btn btn-error" filename = "powermanager.hw.json" task = "clear" style = "float: right;margin-right: 5px;" > Clear< / button >
2023-02-05 09:32:33 +00:00
< / td >
< / tr >
< tr >
2023-02-22 21:01:34 +00:00
< td > Details (Trace)< / td >
2023-02-05 09:32:33 +00:00
< td >
< button class = "btn btn-primary" filename = "powermanager.log" task = "detailstable" > Table< / button >
< button class = "btn btn-error" filename = "powermanager.log" task = "detailsclear" style = "float: right;margin-right: 5px;" > Clear< / button >
< / td >
< / tr >
< / tbody >
< / table > `;
domContent.innerHTML = htmlOverview;
Util.hideModal();
var buttons = domContent.querySelectorAll("button");
for (var i=0;i< buttons.length ; i + + ) {
buttons[i].addEventListener("click",event => {
var button = event.currentTarget;
var filename = button.getAttribute("filename");
if (!filename) return;
var task = button.getAttribute("task");
if (task=="detailsclear") {
Util.showModal("Clearing...");
Util.eraseStorageFile(filename,()=>{
Util.hideModal();
show();
});
}
if (task=="clear") {
Util.showModal("Clearing...");
Util.eraseStorage(filename,()=>{
Util.hideModal();
show();
});
}
if (task=="deftable") {
viewDeferredTable(filename);
}
2023-02-22 21:01:34 +00:00
if (task=="hardwaretable") {
viewHardwareTable(filename);
2023-02-05 09:32:33 +00:00
}
if (task=="detailstable") {
viewDetailsTable(filename);
}
});
}
}
function viewDeferredTable(filename) {
Puck.eval(`require("Storage").list("powermanager.def.json").length > 0`, (f)=>{
if (f) {
Util.showModal("Reading summarized info...");
2023-11-23 12:52:48 +00:00
Util.readStorageJSON(
filename, parsed => {
2023-02-05 09:32:33 +00:00
Util.hideModal();
let sum = 0;
let rows = [];
for (var i in parsed.deferred) {
sum += parsed.deferred[i];
rows.push({func: i, time: parsed.deferred[i]});
}
rows.sort((a,b)=>{return b.time/sum - a.time/sum;});
let tableRows = "";
for (var i in rows) {
let c = rows[i];
tableRows += `< tr >
2023-04-19 07:58:21 +00:00
< td > ${timeFormat(c.time)}< / td >
2023-02-05 09:32:33 +00:00
< td > ${(c.time/sum*100).toFixed(2)}%< / td >
2023-02-22 21:01:34 +00:00
< td > < pre > ${c.func}< / pre > < / td > `
2023-02-05 09:32:33 +00:00
}
let duration = parsed.saved - parsed.start;
var htmlOverview = `< h1 > Deferred function calls< / h1 >
< button class = "btn btn-primary" id = "back" style = "float: right;margin-right: 5px;margin-left: 10px;" > Back< / button >
< div >
2023-04-19 07:58:21 +00:00
This are functions used in timeouts and intervals and their accumulated execution times. Recorded in a time span of < b > ${timeFormat(duration)}< / b > . Timeouts/intervals have run for < b > ${timeFormat(sum)} (${(sum/duration*100).toFixed(2)}%)< / b > . Percentages are calculated from summarized timeout/interval running time.
2023-11-23 12:52:48 +00:00
< / div >
2023-05-11 22:00:36 +00:00
< div class = "table_wrapper" >
< table class = "table table-striped table-hover" >
< thead >
< tr >
< th > Time< / th >
< th > Percentage< / th >
< th > Function< / th >
< / tr >
< / thead >
< tbody > \n`;
2023-02-05 09:32:33 +00:00
htmlOverview += tableRows;
2023-05-11 22:00:36 +00:00
htmlOverview += `< / tbody > < / table > < / div > `;
2023-02-05 09:32:33 +00:00
domContent.innerHTML = htmlOverview;
domContent.querySelector("#back").addEventListener("click",event => {
show();
});
//try finding possible sources for the given function, currently does not work because function.toString() not being identical to code in the *.js files.
/*Puck.eval(`require("Storage").list(/.*.js$/)`, (f)=>{
console.log("Found files:", f, rows[1].func);
for (let file of f){
let query = `require("Storage").read('${file}').includes('${rows[1].func}')`;
console.log("Query: " + query);
Puck.eval(query, (r)=>{
if (r) domContent.querySelector("#row_1").innerHTML = file;
console.log("Found", file, r)
});
}
});*/
});
} else {
var htmlOverview = `< h1 > Deferred function calls< / h1 >
< button class = "btn btn-primary" id = "back" style = "float: right;margin-right: 5px;" > Back< / button >
< div >
No data available.
< / div > `;
domContent.innerHTML = htmlOverview;
domContent.querySelector("#back").addEventListener("click",event => {
show();
});
}
});
}
2023-02-22 21:01:34 +00:00
function viewHardwareTable(filename) {
Puck.eval(`require("Storage").list("powermanager.hw.json").length > 0`, (f)=>{
2023-02-05 09:32:33 +00:00
if (f) {
2023-02-22 21:01:34 +00:00
Util.showModal("Reading hardware info...");
2023-11-23 12:52:48 +00:00
Util.readStorageJSON(
filename, parsed => {
2023-02-05 09:32:33 +00:00
Util.hideModal();
2023-02-22 21:01:34 +00:00
console.log("Hardware", parsed);
2023-02-05 09:32:33 +00:00
let duration = parsed.saved - parsed.start;
2023-11-23 12:52:48 +00:00
2023-02-05 09:32:33 +00:00
let rows = [];
for (var i in parsed.power) {
rows.push({func: i, time: parsed.power[i]});
}
rows.sort((a,b)=>{return b.time/duration - a.time/duration;});
let tableRows = "";
for (var i in rows) {
let c = rows[i];
tableRows += `< tr >
2023-04-19 07:58:21 +00:00
< td > ${timeFormat(c.time)}< / td >
2023-02-05 09:32:33 +00:00
< td > ${(c.time/duration*100).toFixed(2)}%< / td >
< td > ${c.func}< / td > `
}
2023-02-22 21:01:34 +00:00
var htmlOverview = `< h1 > Hardware power< / h1 >
2023-02-05 09:32:33 +00:00
< button class = "btn btn-primary" id = "back" style = "float: right;margin-right: 5px;margin-left: 10px;" > Back< / button >
< div >
2023-04-19 07:58:21 +00:00
Recorded in a time span of < b > ${timeFormat(duration)}< / b > . Percentages are calculated from recording time.
2023-02-05 09:32:33 +00:00
< / div >
< table class = "table table-striped table-hover" >
< thead >
< tr >
< th > Time< / th >
< th > Percentage< / th >
2023-02-22 21:01:34 +00:00
< th > Device< / th >
2023-02-05 09:32:33 +00:00
< / tr >
< / thead >
< tbody > \n`;
htmlOverview += tableRows;
htmlOverview += `< / tbody > < / table > `;
domContent.innerHTML = htmlOverview;
domContent.querySelector("#back").addEventListener("click",event => {
show();
});
});
} else {
2023-02-22 21:01:34 +00:00
var htmlOverview = `< h1 > Hardware power< / h1 >
2023-02-05 09:32:33 +00:00
< button class = "btn btn-primary" id = "back" style = "float: right;margin-right: 5px;" > Back< / button >
< div >
No data available.
< / div > `;
domContent.innerHTML = htmlOverview;
domContent.querySelector("#back").addEventListener("click",event => {
show();
});
}
});
}
function viewDetailsTable(filename) {
Util.showModal("Reading details info...");
Util.readStorageFile(
filename, data => {
Util.hideModal();
2023-11-23 12:52:48 +00:00
2023-02-05 09:32:33 +00:00
var htmlOverview = `< h1 > Detailed logging< / h1 >
< button class = "btn btn-primary" id = "back" style = "float: right;margin-right: 5px;" > Back< / button >
2023-05-11 22:00:36 +00:00
< div >
2023-05-11 22:32:47 +00:00
This is a trace log of all logged entries. Power is logged with type, state transition (old → new) and calling app if available. Functions are logged with execution duration and source if available.
2023-05-11 22:00:36 +00:00
< / div >
< div class = "table_wrapper" >
< table class = "table table-striped table-hover" >
< thead >
< tr >
< th > Time< / th >
< th > Type< / th >
< th > Info< / th >
< / tr >
< / thead >
< tbody > \n`;
2023-02-05 09:32:33 +00:00
let rows = data.trim().split("\n");
2023-05-11 22:00:36 +00:00
let firstTimestamp;
2023-02-05 09:32:33 +00:00
for (var row of rows) {
let cols = row.split(",");
2023-05-11 22:00:36 +00:00
let col = 0;
if (!firstTimestamp) firstTimestamp = cols[0];
if (cols[1] == "p"){
cols[1] = "Power";
htmlOverview += `< tr >
< td > ${timeFormat(cols[col++]-firstTimestamp)}< / td >
< td > ${cols[col++]}< / td >
< td > ${cols[col++]}< / br > ${cols[col++]} → ${cols[col++]}< / br > ${cols[col++]}< / td >
< / tr > `
} else {
htmlOverview += `< tr >
< td > ${timeFormat(cols[col++]-firstTimestamp)}< / td >
< td > ${cols[col++]=="t"?"Timeout":"Interval"}< / td >
< td > ${new Number(cols[col++]).toFixed(0)}ms< / br > < pre > ${cols[col++]}< / pre > < / td >
< / tr > `
}
2023-02-05 09:32:33 +00:00
}
2023-05-11 22:00:36 +00:00
htmlOverview += `< / tbody > < / table > < / div > `;
2023-02-05 09:32:33 +00:00
domContent.innerHTML = htmlOverview;
domContent.querySelector("#back").addEventListener("click",event => {
show();
});
});
}
function onInit() {
show();
}
2023-04-19 07:58:21 +00:00
function timeFormat(time) {
let secs = time / 1000;
if (secs < 60 )
return secs.toFixed(2) + "s";
let mins = secs / 60;
secs %= 60;
if (mins < 60 )
return mins.toFixed(0) + "m" + secs.toFixed(0) + "s";
let hrs = mins / 60;
mins %= 60;
if (hrs < 24 )
return hrs.toFixed(0) + "h" + mins.toFixed(0) + "m" + secs.toFixed(0) + "s";
let days = hrs / 24;
hrs %= 24;
return days.toFixed(0) + "d" + hrs.toFixed(0) + "h" + mins.toFixed(0) + "m" + secs.toFixed(0) + "s";
}
2023-02-05 09:32:33 +00:00
< / script >
< / body >
< / html >