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.bench = new Bench();
+ this.bench.enabled = !!globalScope.PDFJS.enableBench;
this.xref = xref;
this.ref = ref;
return this.IRQueue;
}
+ this.bench.time('Build IR Queue');
+
var xref = this.xref;
var content = xref.fetchIfRef(this.content);
var resources = xref.fetchIfRef(this.resources);
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.bench.timeEnd('Build IR Queue');
+ return this.IRQueue;
},
ensureFonts: function pageEnsureFonts(fonts, callback) {
+ this.bench.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;
var fontObjs = FontLoader.bind(
fonts,
function pageEnsureFontsFontObjs(fontObjs) {
- this.stats.fonts = Date.now();
+ this.bench.timeEnd('Font Loading');
callback.call(this);
}.bind(this),
},
display: function pageDisplay(gfx, callback) {
+ var bench = this.bench;
+ bench.time('Rendering');
var xref = this.xref;
var resources = xref.fetchIfRef(this.resources);
var mediaBox = xref.fetchIfRef(this.mediaBox);
function next() {
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next);
if (startIdx == length) {
- self.stats.render = Date.now();
gfx.endDrawing();
+ bench.timeEnd('Rendering');
+ bench.timeEnd('Overall');
if (callback) callback();
}
}
return items;
},
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
// 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() {
var pageNum = data.pageNum;
var page = this.pageCache[pageNum];
var depFonts = data.depFonts;
-
+ page.bench.timeEnd('Page Request');
page.startRenderingFromIRQueue(data.IRQueue, depFonts);
}, this);
startRendering: function pdfDocStartRendering(page) {
// The worker might not be ready to receive the page request yet.
this.workerReadyPromise.then(function pdfDocStartRenderingThen() {
+ page.bench.time('Page Request');
this.messageHandler.send('page_request', page.pageNumber + 1);
}.bind(this));
},
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;
+})();
span#info {
display: none;
+ position: fixed;
+ top: 32px;
+ right: 0px;
+ font-size: 10px;
+ white-space: pre;
+ font-family: courier;
}
@-moz-document regexp("http:.*debug=1.*") {
return;
}
+ pages[val - 1].updateStats();
currentPageNumber = val;
var event = document.createEvent('UIEvents');
event.initUIEvent('pagechange', false, false, window, 0);
for (var i = 1; i <= pagesCount; i++) {
var page = pdf.getPage(i);
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,
page.width / page.height);
bindOnAfterDraw(pageView, thumbnailView);
};
var PageView = function pageView(container, content, id, pageWidth, pageHeight,
- stats, navigateTo) {
+ bench, navigateTo) {
this.id = id;
this.content = content;
ctx.restore();
ctx.translate(-this.x * scale, -this.y * scale);
- stats.begin = Date.now();
this.content.startRendering(ctx,
(function pageViewDrawCallback(error) {
if (error)
PDFView.error('An error occurred while rendering the page.', error);
+ this.stats = content.bench;
this.updateStats();
if (this.onAfterDraw)
this.onAfterDraw();
};
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').innerHTML = str;
+ if (!PDFJS.enableBench || !this.stats || PDFView.page != this.id)
+ return;
+ var stats = this.stats;
+ var statsHtml = 'Page ' + this.id + '\n';
+ statsHtml += stats.toString().replace(/\n/g, '<br>');
+ document.getElementById('info').innerHTML = statsHtml;
};
};
if ('disableTextLayer' in params)
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');
sidebarScrollView.addEventListener('scroll', updateThumbViewArea, true);
}, true);