|
|
|
- analyze.css
body {
margin: 0;
padding: 0;
}
pre.line {
margin:0 0 0 0px;
min-height:1em;
font-size: 11pt;
}
pre.line.hilit {
background: yellow;
}
#content-profile {
height: 100%;
}
#content-trace,
#content-source {
display: none;
height: 400px;
}
#content {
font-family: monospace;
}
.trace {
margin-left:20px !important;
font-family: monospace;
font-size: 11pt;
}
.trace.open > a,
.trace.close > a {
text-decoration: none;
cursor: pointer;
}
.trace.open > a.icon:before {
content: "+ ";
}
.trace.close > a.icon:before {
content: "- ";
}
.trace.open > div.trace {
display: none;
}
.trace.close > div.trace {
display: default;
}
- analyze.js
$(function() {
var currFunc;
var summary = [];
function initProfile() {
var summary = {};
var records = [];
function calcSummary(data) {
var sum = summary[data.id];
if (data.id in summary) {
sum.count++;
sum.elapsed += data.elapsed;
sum.effective += data.effective;
} else {
sum = summary[data.id] = {
id: data.id,
fileName: functionMap.files[functionMap.functions[data.id].fileId],
name: functionMap.functions[data.id].name,
count: 1,
elapsed: data.elapsed,
effective: data.effective
};
}
for (var i = 0; i < data.children.length; i++) {
calcSummary(data.children[i]);
}
}
function calcEffective(data) {
data.effective = data.elapsed;
for (var i = 0; i < data.children.length; i++) {
var child = data.children[i];
data.effective -= child.elapsed;
calcEffective(child);
}
}
calcEffective(root);
calcSummary(root);
for (var key in summary) {
var rec = summary[key];
records.push({
recid: rec.id,
name: esc(rec.name),
count: rec.count,
elapsed: rec.elapsed,
effective: rec.effective
});
}
records.sort(function(a, b) {
return a.effective < b.effective ? 1 :
(a.effective > b.effective ? -1 : 0);
});
$('#content-profile').w2grid({
name: 'profile',
show: {
toolbar: false,
footer: true
},
columns: [
{ field: 'name', caption: 'name', size: '100%', sortable: true },
{ field: 'count', caption: 'count', size: '80px', sortable: true, render:'int' },
{ field: 'elapsed', caption: 'elapsed', size: '150px', sortable: true, render:'float:3' },
{ field: 'effective', caption: 'effective', size: '150px', sortable: true, render:'float:3' }
],
onClick: function(evt) {
if (evt.column === 0 && evt.recid != 0) {
currFunc = evt.recid;
w2ui.layout.panels[0].tabs.enable('tab-source');
w2ui.layout.panels[0].tabs.click('tab-source');
}
},
sortData: [
{ "field": "effective", "direction": "DESC" }
],
records: records
});
}
$('#layout').w2layout({
name : 'layout',
panels : [
{
type: 'main',
content:
'<div id="content-profile"></div>' +
'<div id="content-trace"></div>' +
'<div id="content-source"></div>',
tabs: {
active: 'tab-profile',
tabs: [
{ id: 'tab-profile', caption: 'profile' },
{ id: 'tab-trace', caption: 'trace' },
{ id: 'tab-source', caption: 'source', disabled: true }
],
onClick: function (id, data) {
switch(id) {
case 'tab-profile':
$('#content-profile').css('display', 'block');
$('#content-trace').css('display', 'none');
$('#content-source').css('display', 'none');
break;
case 'tab-trace':
var o = $(w2ui.layout.el('main'));
$('#content-profile').css('display', 'none');
$('#content-trace').css('display', 'block');
$('#content-source').css('display', 'none');
break;
case 'tab-source':
$('#content-profile').css('display', 'none');
$('#content-trace').css('display', 'none');
$('#content-source').css('display', 'block');
showFunction(currFunc);
break;
}
}
}
}
]
});
function initTrace() {
function createDom(data) {
var f = functionMap.functions[data.id];
var node = document.createElement('div');
node.id = 'trace-' + data.id;
node.className = 'trace close';
var icon = node.appendChild(document.createElement('a'));
icon.className = 'icon';
icon.onclick = toggle;
var file = functionMap.files[f.fileId];
var name = node.appendChild(document.createElement('a'));
name.appendChild(document.createTextNode(functionMap.functions[data.id].name + '(' + data.args.join(', ') + ')'));
if (file) {
name.title = file + ':' + f.row + ':' + f.col;
name.onclick = showSource;
}
for (var i = 0; i < data.children.length; i++) {
node.appendChild(createDom(data.children[i]));
}
return node;
}
function toggle(evt) {
var target = $(evt.target.parentNode);
if (target.hasClass('open')) {
target.removeClass('open');
target.addClass('close');
} else {
target.removeClass('close');
target.addClass('open');
}
}
$('#content-trace').append(createDom(root));
}
var root = JSON.parse(localStorage.getItem("jstools.profile"));
initProfile();
initTrace();
function onResize() {
var height = $(window).height();
$('#layout').css('height', height + 'px');
}
function esc(text) {
if (!text) return text;
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
function showFunction(id) {
function hilit(id) {
$('pre.line.hilit').removeClass('hilit');
var obj = $('#line-' + id).addClass('hilit');
var offsetParent = obj[0].offsetParent;
var offsetTop = obj[0].offsetTop;
offsetParent.scrollTop = offsetTop - offsetParent.offsetHeight / 2;
}
var f = functionMap.functions[id];
var fileName = 'sources/' + functionMap.files[f.fileId] + '.html';
if ($('#content-source').attr("title") != fileName) {
$.ajax({
type: "GET",
url: fileName,
dataType: "html",
success: function(html){
$("#content-source").html('');
$("#content-source").append(html);
$("#content-source").attr('title', fileName);
hilit(f.row);
}
});
} else {
hilit(f.row);
}
currFunc = id;
}
function showSource(evt) {
currFunc = evt.target.parentNode.id.replace(/^trace\-/, '');
w2ui.layout.panels[0].tabs.enable('tab-source');
w2ui.layout.panels[0].tabs.click('tab-source');
}
onResize();
$(window).resize(onResize);
});
- jstools.js
if (!("__jstools__" in window)) {
window.__jstools__ = (function() {
var running = true;
var controller;
var root = new node(0, null);
var curr = root;
var handlers = {
'enter': [],
'exit': []
}
var now = "performance" in window ?
function() { return performance.now(); } :
function() { return (new Date()).getTime(); };
function node(id, parent) {
this.id = id;
this.parent = parent;
this.args = [];
this.children = [];
this.elapsed = -1;
}
node.prototype.setArgs = function(args) {
this.args = [];
if (!args) {
return;
}
for (var i = 0; i < args.length; i++) {
var arg = args[i];
if (typeof arg == 'string') arg = "'" + arg + "'";
else if (typeof arg == 'object') arg = 'object';
this.args.push(arg);
}
};
node.prototype.addChild = function(child) {
this.children.push(child);
};
node.prototype.startTimer = function() {
this.stime = now();
};
node.prototype.stopTimer = function() {
this.elapsed = now() - this.stime;
delete this.stime;
};
node.prototype.clear = function() {
for (var i = 0; i < this.children.length; i++) {
this.children[i].clear();
}
this.children = [];
};
function start() {
running = true;
controller.style.background = "red";
}
function stop() {
running = false;
controller.style.background = "lightgreen";
report();
clear();
}
function clear() {
root.clear();
root = new node(0, null);
curr = root;
//localStorage.removeItem('jstools.profile');
}
function enter(num, name) {
if (!running) return;
var args = arguments.callee.caller.arguments;
var child = new node(num, curr);
child.setArgs(args);
child.startTimer();
curr.addChild(child);
curr = child;
for (var i = 0; i < handlers['enter'].length; i++) {
handlers['enter'][i](num, name);
}
}
function exit(retval) {
if (!running) return retval;
curr.stopTimer();
curr = curr.parent;
for (var i = 0; i < handlers['exit'].length; i++) {
handlers['exit'][i](retval);
}
return retval;
}
function report() {
localStorage.setItem('jstools.profile', JSON.stringify(tree()));
clear();
window.open(".jstools/analyze.html", "jstools");
}
function tree() {
function dig(node) {
var result = { id:node.id, elapsed:node.elapsed, args:node.args, children:[]};
for (var i = 0; i < node.children.length; i++) {
result.children.push(dig(node.children[i]));
}
return result;
}
return dig(root);
}
function createControl() {
var icon = controller = document.createElement("div");
icon.style.position = "fixed";
icon.style.width = "10px";
icon.style.height = "10px";
icon.style.top = "10px";
icon.style.right = "10px";
icon.style.background = "red";
icon.style.zIndex = 999999;
icon.onclick = function(evt) {
running ? stop() : start();
};
document.body.appendChild(icon);
}
function addHandler(name, fn) {
handlers[name].push(fn);
}
window.addEventListener('load', createControl, false);
return {
'enter': enter,
'exit': exit,
'addHandler': addHandler
}
})();
}
- profile.js
(function() {
var summary = {};
function esc(text) {
if (!text) return text;
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
function calc(data) {
var sum = summary[data.id];
if (data.id in summary) {
sum.count++;
sum.elapsed += data.elapsed;
} else {
sum = summary[data.id] = {
id: data.id,
fileName: functionMap.files[functionMap.functions[data.id].fileId],
name: functionMap.functions[data.id].name,
count: 1,
elapsed: data.elapsed,
effective: data.elapsed
};
}
for (var i = 0; i < data.children.length; i++) {
calc(data.children[i]);
}
for (var i = 0; i < data.children.length; i++) {
sum.effective -= data.children[i].elapsed;
}
}
function show() {
var array = [];
for (var key in summary) {
array.push(summary[key]);
}
array.sort(function(a, b) {
return a.elapsed > b.elapsed ? -1 : (a.elapsed < b.elapsed ? 1 : 0);
});
var html = '<table>';
for (var i = 0; i < array.length; i++) {
var v = array[i];
var h = '<tr><td><a target="source" href="sources/' +
v.fileName + '.html#line-' + functionMap.functions[v.id].row +
'">' + esc(v.name) + '</a></td><td>' + v.count + '</td><td>' +
v.elapsed + '</td><td>' + v.effective + '</td></tr>';
html += h;
}
html += '</table>';
document.getElementById('content').innerHTML = html;
}
function showSource(evt) {
var p = evt.target.title.split(/:/);
window.open("sources/" + p[0] + ".html#line-" + p[1], "source");
}
function hasClass(node, name) {
if (!node.className) {
return false;
} else {
return (' ' + node.className + ' ').includes(' ' + name + ' ');
}
}
function removeClass(node, name) {
if (hasClass(node, name)) {
var parts = node.className.trim().split(/ +/);
parts.splice(parts.indexOf(name), 1);
node.className = parts.join(' ');
}
}
function addClass(node, name) {
if (!hasClass(node, name)) {
node.className = node.className ?
node.className + ' ' + name :
name;
}
}
window.addEventListener('load', function() {
var root = JSON.parse(localStorage.getItem("jstools.profile"));
calc(root);
show();
});
})();
- trace.css
div#nav {
text-align: right;
}
#content {
font-family: monospace;
}
.trace {
margin-left:20px;
}
.trace.open > a,
.trace.close > a {
text-decoration: none;
cursor: pointer;
}
.trace.open > a.icon:before {
content: "+ ";
}
.trace.close > a.icon:before {
content: "- ";
}
.trace.open > div.trace {
display: none;
}
.trace.close > div.trace {
display: default;
}
- trace.js
(function() {
function esc(text) {
if (!text) return text;
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
function createDom(data) {
var f = functionMap.functions[data.id];
var node = document.createElement('div');
node.id = 'trace-' + data.id;
node.className = 'trace close';
var icon = node.appendChild(document.createElement('a'));
icon.className = 'icon';
icon.onclick = toggle;
var file = functionMap.files[f.fileId];
var name = node.appendChild(document.createElement('a'));
name.appendChild(document.createTextNode(functionMap.functions[data.id].name + '(' + data.args.join(', ') + ')'));
if (file) {
name.title = file + ':' + f.row + ':' + f.col;
name.onclick = showSource;
}
for (var i = 0; i < data.children.length; i++) {
node.appendChild(createDom(data.children[i]));
}
return node;
}
function toggle(evt) {
var target = evt.target.parentNode;
if (hasClass(target, 'open')) {
removeClass(target, 'open');
addClass(target, 'close');
} else {
removeClass(target, 'close');
addClass(target, 'open');
}
}
function showSource(evt) {
var p = evt.target.title.split(/:/);
window.open("sources/" + p[0] + ".html#line-" + p[1], "source");
}
function hasClass(node, name) {
if (!node.className) {
return false;
} else {
return (' ' + node.className + ' ').includes(' ' + name + ' ');
}
}
function removeClass(node, name) {
if (hasClass(node, name)) {
var parts = node.className.trim().split(/ +/);
parts.splice(parts.indexOf(name), 1);
node.className = parts.join(' ');
}
}
function addClass(node, name) {
if (!hasClass(node, name)) {
node.className = node.className ?
node.className + ' ' + name :
name;
}
}
window.addEventListener('load', function() {
var root = JSON.parse(localStorage.getItem("jstools.profile"));
document.getElementById('content').appendChild(createDom(root));
});
})();
|
|
|