Merge pull request #1067 from brendandahl/stats

Start of the benchmark recording framework.
This commit is contained in:
Artur Adib 2012-03-13 06:04:48 -07:00
commit 6833f64db3
6 changed files with 160 additions and 43 deletions

View File

@ -63,13 +63,8 @@ var Page = (function PageClosure() {
function Page(xref, pageNumber, pageDict, ref) {
this.pageNumber = pageNumber;
this.pageDict = pageDict;
this.stats = {
create: Date.now(),
compile: 0.0,
fonts: 0.0,
images: 0.0,
render: 0.0
};
this.stats = new StatTimer();
this.stats.enabled = !!globalScope.PDFJS.enableStats;
this.xref = xref;
this.ref = ref;
@ -200,6 +195,8 @@ var Page = (function PageClosure() {
return this.IRQueue;
}
this.stats.time('Build IR Queue');
var xref = this.xref;
var content = xref.fetchIfRef(this.content);
var resources = xref.fetchIfRef(this.resources);
@ -217,11 +214,14 @@ var Page = (function PageClosure() {
var pe = this.pe = new PartialEvaluator(
xref, handler, 'p' + this.pageNumber + '_');
var IRQueue = {};
return (this.IRQueue = pe.getIRQueue(content, resources, IRQueue,
dependency));
this.IRQueue = pe.getIRQueue(content, resources, IRQueue, dependency);
this.stats.timeEnd('Build IR Queue');
return this.IRQueue;
},
ensureFonts: function pageEnsureFonts(fonts, callback) {
this.stats.time('Font Loading');
// Convert the font names to the corresponding font obj.
for (var i = 0, ii = fonts.length; i < ii; i++) {
fonts[i] = this.objs.objs[fonts[i]].data;
@ -231,7 +231,7 @@ var Page = (function PageClosure() {
var fontObjs = FontLoader.bind(
fonts,
function pageEnsureFontsFontObjs(fontObjs) {
this.stats.fonts = Date.now();
this.stats.timeEnd('Font Loading');
callback.call(this);
}.bind(this),
@ -240,6 +240,8 @@ var Page = (function PageClosure() {
},
display: function pageDisplay(gfx, callback) {
var stats = this.stats;
stats.time('Rendering');
var xref = this.xref;
var resources = xref.fetchIfRef(this.resources);
var mediaBox = xref.fetchIfRef(this.mediaBox);
@ -266,8 +268,9 @@ var Page = (function PageClosure() {
function next() {
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next, stepper);
if (startIdx == length) {
self.stats.render = Date.now();
gfx.endDrawing();
stats.timeEnd('Rendering');
stats.timeEnd('Overall');
if (callback) callback();
}
}
@ -431,15 +434,14 @@ var Page = (function PageClosure() {
return items;
},
startRendering: function pageStartRendering(ctx, callback, textLayer) {
this.startRenderingTime = Date.now();
var stats = this.stats;
stats.time('Overall');
// If there is no displayReadyPromise yet, then the IRQueue was never
// requested before. Make the request and create the promise.
if (!this.displayReadyPromise) {
this.pdf.startRendering(this);
this.displayReadyPromise = new Promise();
}
// Once the IRQueue and fonts are loaded, perform the actual rendering.
this.displayReadyPromise.then(
function pageDisplayReadyPromise() {
@ -731,7 +733,7 @@ var PDFDoc = (function PDFDocClosure() {
var pageNum = data.pageNum;
var page = this.pageCache[pageNum];
var depFonts = data.depFonts;
page.stats.timeEnd('Page Request');
page.startRenderingFromIRQueue(data.IRQueue, depFonts);
}, this);
@ -840,6 +842,7 @@ var PDFDoc = (function PDFDocClosure() {
startRendering: function pdfDocStartRendering(page) {
// The worker might not be ready to receive the page request yet.
this.workerReadyPromise.then(function pdfDocStartRenderingThen() {
page.stats.time('Page Request');
this.messageHandler.send('page_request', page.pageNumber + 1);
}.bind(this));
},

View File

@ -416,3 +416,55 @@ var Promise = (function PromiseClosure() {
return Promise;
})();
var StatTimer = (function StatTimerClosure() {
function rpad(str, pad, length) {
while (str.length < length)
str += pad;
return str;
}
function StatTimer() {
this.started = {};
this.times = [];
this.enabled = true;
}
StatTimer.prototype = {
time: function statTimerTime(name) {
if (!this.enabled)
return;
if (name in this.started)
throw 'Timer is already running for ' + name;
this.started[name] = Date.now();
},
timeEnd: function statTimerTimeEnd(name) {
if (!this.enabled)
return;
if (!(name in this.started))
throw 'Timer has not been started for ' + name;
this.times.push({
'name': name,
'start': this.started[name],
'end': Date.now()
});
// Remove timer from started so it can be called again.
delete this.started[name];
},
toString: function statTimerToString() {
var times = this.times;
var out = '';
// Find the longest name for padding purposes.
var longest = 0;
for (var i = 0, ii = times.length; i < ii; ++i) {
var name = times[i]['name'];
if (name.length > longest)
longest = name.length;
}
for (var i = 0, ii = times.length; i < ii; ++i) {
var span = times[i];
var duration = span.end - span.start;
out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
}
return out;
}
};
return StatTimer;
})();

View File

@ -318,6 +318,58 @@ var Stepper = (function StepperClosure() {
return Stepper;
})();
var Stats = (function Stats() {
var stats = [];
function clear(node) {
while (node.hasChildNodes())
node.removeChild(node.lastChild);
}
function getStatIndex(pageNumber) {
for (var i = 0, ii = stats.length; i < ii; ++i)
if (stats[i].pageNumber === pageNumber)
return i;
return false;
}
return {
// Poperties/functions needed by PDFBug.
id: 'Stats',
name: 'Stats',
panel: null,
manager: null,
init: function init() {
this.panel.setAttribute('style', 'padding: 5px;');
PDFJS.enableStats = true;
},
enabled: false,
active: false,
// Stats specific functions.
add: function(pageNumber, stat) {
if (!stat)
return;
var statsIndex = getStatIndex(pageNumber);
if (statsIndex !== false) {
var b = stats[statsIndex];
this.panel.removeChild(b.div);
stats.splice(statsIndex, 1);
}
var wrapper = document.createElement('div');
wrapper.className = 'stats';
var title = document.createElement('div');
title.className = 'title';
title.textContent = 'Page: ' + pageNumber;
var statsDiv = document.createElement('div');
statsDiv.textContent = stat.toString();
wrapper.appendChild(title);
wrapper.appendChild(statsDiv);
stats.push({ pageNumber: pageNumber, div: wrapper });
stats.sort(function(a, b) { return a.pageNumber - b.pageNumber});
clear(this.panel);
for (var i = 0, ii = stats.length; i < ii; ++i)
this.panel.appendChild(stats[i].div);
}
};
})();
// Manages all the debugging tools.
var PDFBug = (function PDFBugClosure() {
var panelWidth = 300;
@ -327,8 +379,29 @@ var PDFBug = (function PDFBugClosure() {
return {
tools: [
FontInspector,
StepperManager
StepperManager,
Stats
],
enable: function(ids) {
var all = false, tools = this.tools;
if (ids.length === 1 && ids[0] === 'all')
all = true;
for (var i = 0; i < tools.length; ++i) {
var tool = tools[i];
if (all || ids.indexOf(tool.id) !== -1)
tool.enabled = true;
}
if (!all) {
// Sort the tools by the order they are enabled.
tools.sort(function(a, b) {
var indexA = ids.indexOf(a.id);
indexA = indexA < 0 ? tools.length : indexA;
var indexB = ids.indexOf(b.id);
indexB = indexB < 0 ? tools.length : indexB;
return indexA - indexB;
});
}
},
init: function init() {
/*
* Basic Layout:

View File

@ -65,16 +65,6 @@ body {
line-height: 16px;
}
span#info {
display: none;
}
@-moz-document regexp("http:.*debug=1.*") {
span#info {
display: inline-block;
}
}
/* === Sidebar === */
#sidebar {
position: fixed;
@ -442,3 +432,11 @@ canvas {
background: yellow;
opacity: 0.3;
}
#PDFBug .stats {
font-size: 10px;
white-space: pre;
font-family: courier;
}
#PDFBug .stats .title {
font-weight: bold;
}

View File

@ -102,7 +102,6 @@
<img src="images/bookmark.svg" alt="Bookmark" align="top" height="16"/>
</a>
<span id="info">--</span>
</div>
<div id="errorWrapper" hidden='true'>
<div id="errorMessageLeft">

View File

@ -234,6 +234,7 @@ var PDFView = {
return;
}
pages[val - 1].updateStats();
currentPageNumber = val;
var event = document.createEvent('UIEvents');
event.initUIEvent('pagechange', false, false, window, 0);
@ -870,7 +871,6 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
// Rendering area
var self = this;
stats.begin = Date.now();
this.content.startRendering(ctx, function pageViewDrawCallback(error) {
if (self.loadingIconDiv) {
div.removeChild(self.loadingIconDiv);
@ -880,6 +880,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
if (error)
PDFView.error('An error occurred while rendering the page.', error);
self.stats = content.stats;
self.updateStats();
if (self.onAfterDraw)
self.onAfterDraw();
@ -893,10 +894,10 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
};
this.updateStats = function pageViewUpdateStats() {
var t1 = stats.compile, t2 = stats.fonts, t3 = stats.render;
var str = 'Time to compile/fonts/render: ' +
(t1 - stats.begin) + '/' + (t2 - t1) + '/' + (t3 - t2) + ' ms';
document.getElementById('info').textContent = str;
if (PDFJS.pdfBug && Stats.enabled) {
var stats = this.stats;
Stats.add(this.id, stats);
}
};
};
@ -1184,17 +1185,8 @@ window.addEventListener('load', function webViewerLoad(evt) {
if ('pdfBug' in hashParams) {
PDFJS.pdfBug = true;
var pdfBug = hashParams['pdfBug'];
var all = false, enabled = [];
if (pdfBug === 'all')
all = true;
else
enabled = pdfBug.split(',');
var debugTools = PDFBug.tools;
for (var i = 0; i < debugTools.length; ++i) {
var tool = debugTools[i];
if (all || enabled.indexOf(tool.id) !== -1)
tool.enabled = true;
}
var enabled = pdfBug.split(',');
PDFBug.enable(enabled);
PDFBug.init();
}