Start of the benchmark recording framework.

This commit is contained in:
Brendan Dahl 2012-01-11 16:48:51 -08:00
parent cf00831a00
commit bd6d89e1a8
4 changed files with 91 additions and 22 deletions

View File

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

View File

@ -338,3 +338,55 @@ var Promise = (function PromiseClosure() {
return Promise; return Promise;
})(); })();
var Bench = (function BenchClosure() {
function rpad(str, pad, length) {
while (str.length < length)
str += pad;
return str;
}
function Bench() {
this.started = {};
this.times = [];
this.enabled = true;
}
Bench.prototype = {
time: function benchTime(name) {
if (!this.enabled)
return;
if (name in this.started)
throw 'Timer is already running for ' + name;
this.started[name] = Date.now();
},
timeEnd: function benchTimeEnd(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 benchToString() {
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 Bench;
})();

View File

@ -67,6 +67,12 @@ body {
span#info { span#info {
display: none; display: none;
position: fixed;
top: 32px;
right: 0px;
font-size: 10px;
white-space: pre;
font-family: courier;
} }
@-moz-document regexp("http:.*debug=1.*") { @-moz-document regexp("http:.*debug=1.*") {

View File

@ -222,6 +222,7 @@ var PDFView = {
return; return;
} }
pages[val - 1].updateStats();
currentPageNumber = val; currentPageNumber = val;
var event = document.createEvent('UIEvents'); var event = document.createEvent('UIEvents');
event.initUIEvent('pagechange', false, false, window, 0); event.initUIEvent('pagechange', false, false, window, 0);
@ -421,7 +422,7 @@ var PDFView = {
for (var i = 1; i <= pagesCount; i++) { for (var i = 1; i <= pagesCount; i++) {
var page = pdf.getPage(i); var page = pdf.getPage(i);
var pageView = new PageView(container, page, i, page.width, page.height, var pageView = new PageView(container, page, i, page.width, page.height,
page.stats, this.navigateTo.bind(this)); page.bench, this.navigateTo.bind(this));
var thumbnailView = new ThumbnailView(sidebar, page, i, var thumbnailView = new ThumbnailView(sidebar, page, i,
page.width / page.height); page.width / page.height);
bindOnAfterDraw(pageView, thumbnailView); bindOnAfterDraw(pageView, thumbnailView);
@ -581,7 +582,7 @@ var PDFView = {
}; };
var PageView = function pageView(container, content, id, pageWidth, pageHeight, var PageView = function pageView(container, content, id, pageWidth, pageHeight,
stats, navigateTo) { bench, navigateTo) {
this.id = id; this.id = id;
this.content = content; this.content = content;
@ -800,11 +801,11 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
ctx.restore(); ctx.restore();
ctx.translate(-this.x * scale, -this.y * scale); ctx.translate(-this.x * scale, -this.y * scale);
stats.begin = Date.now();
this.content.startRendering(ctx, this.content.startRendering(ctx,
(function pageViewDrawCallback(error) { (function pageViewDrawCallback(error) {
if (error) if (error)
PDFView.error('An error occurred while rendering the page.', error); PDFView.error('An error occurred while rendering the page.', error);
this.stats = content.bench;
this.updateStats(); this.updateStats();
if (this.onAfterDraw) if (this.onAfterDraw)
this.onAfterDraw(); this.onAfterDraw();
@ -819,10 +820,12 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
}; };
this.updateStats = function pageViewUpdateStats() { this.updateStats = function pageViewUpdateStats() {
var t1 = stats.compile, t2 = stats.fonts, t3 = stats.render; if (!PDFJS.enableBench || !this.stats || PDFView.page != this.id)
var str = 'Time to compile/fonts/render: ' + return;
(t1 - stats.begin) + '/' + (t2 - t1) + '/' + (t3 - t2) + ' ms'; var stats = this.stats;
document.getElementById('info').innerHTML = str; var statsHtml = 'Page ' + this.id + '\n';
statsHtml += stats.toString().replace(/\n/g, '<br>');
document.getElementById('info').innerHTML = statsHtml;
}; };
}; };
@ -1016,6 +1019,11 @@ window.addEventListener('load', function webViewerLoad(evt) {
if ('disableTextLayer' in params) if ('disableTextLayer' in params)
PDFJS.disableTextLayer = (params['disableTextLayer'] === 'true'); PDFJS.disableTextLayer = (params['disableTextLayer'] === 'true');
if ('enableBench' in params)
PDFJS.enableBench = (params['enableBench'] === 'true');
if (PDFJS.enableBench)
document.getElementById('info').style.display = 'block';
var sidebarScrollView = document.getElementById('sidebarScrollView'); var sidebarScrollView = document.getElementById('sidebarScrollView');
sidebarScrollView.addEventListener('scroll', updateThumbViewArea, true); sidebarScrollView.addEventListener('scroll', updateThumbViewArea, true);
}, true); }, true);