Merge pull request #9245 from Snuffleupagus/issue-5215

[api-major] Only create a `StatTimer` for pages when `enableStats == true` (issue 5215)
This commit is contained in:
Tim van der Meij 2017-12-07 21:59:32 +01:00 committed by GitHub
commit 694c4171d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 116 additions and 85 deletions

View File

@ -15,15 +15,14 @@
/* globals requirejs, __non_webpack_require__ */
import {
assert, createPromiseCapability, getVerbosityLevel, info,
InvalidPDFException, isArrayBuffer, isSameOrigin, loadJpegStream,
MessageHandler, MissingPDFException, NativeImageDecoding, PageViewport,
PasswordException, StatTimer, stringToBytes, UnexpectedResponseException,
UnknownErrorException, Util, warn
assert, createPromiseCapability, getVerbosityLevel, info, InvalidPDFException,
isArrayBuffer, isSameOrigin, loadJpegStream, MessageHandler,
MissingPDFException, NativeImageDecoding, PageViewport, PasswordException,
stringToBytes, UnexpectedResponseException, UnknownErrorException, Util, warn
} from '../shared/util';
import {
DOMCanvasFactory, DOMCMapReaderFactory, getDefaultSetting,
RenderingCancelledException
DOMCanvasFactory, DOMCMapReaderFactory, DummyStatTimer, getDefaultSetting,
RenderingCancelledException, StatTimer
} from './dom_utils';
import { FontFaceObject, FontLoader } from './font_loader';
import { CanvasGraphics } from './canvas';
@ -735,8 +734,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
this.pageIndex = pageIndex;
this.pageInfo = pageInfo;
this.transport = transport;
this.stats = new StatTimer();
this.stats.enabled = getDefaultSetting('enableStats');
this._stats = (getDefaultSetting('enableStats') ?
new StatTimer() : DummyStatTimer);
this.commonObjs = transport.commonObjs;
this.objs = new PDFObjects();
this.cleanupAfterRender = false;
@ -812,7 +811,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* is resolved when the page finishes rendering.
*/
render: function PDFPageProxy_render(params) {
var stats = this.stats;
let stats = this._stats;
stats.time('Overall');
// If there was a pending destroy cancel it so no cleanup happens during
@ -843,7 +842,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
lastChunk: false,
};
this.stats.time('Page Request');
stats.time('Page Request');
this.transport.messageHandler.send('RenderPageRequest', {
pageIndex: this.pageNumber - 1,
intent: renderingIntent,
@ -1021,17 +1020,19 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
/**
* Cleans up resources allocated by the page.
* @param {boolean} resetStats - (optional) Reset page stats, if enabled.
* The default value is `false`.
*/
cleanup: function PDFPageProxy_cleanup() {
cleanup(resetStats = false) {
this.pendingCleanup = true;
this._tryCleanup();
this._tryCleanup(resetStats);
},
/**
* For internal use only. Attempts to clean up if rendering is in a state
* where that's possible.
* @ignore
*/
_tryCleanup: function PDFPageProxy_tryCleanup() {
_tryCleanup(resetStats = false) {
if (!this.pendingCleanup ||
Object.keys(this.intentStates).some(function(intent) {
var intentState = this.intentStates[intent];
@ -1046,6 +1047,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
}, this);
this.objs.clear();
this.annotationsPromise = null;
if (resetStats) {
this._stats.reset();
}
this.pendingCleanup = false;
},
/**
@ -1087,6 +1091,13 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
this._tryCleanup();
}
},
/**
* @return {Object} Returns page stats, if enabled.
*/
get stats() {
return (this._stats instanceof StatTimer ? this._stats : null);
},
};
return PDFPageProxy;
})();
@ -1705,7 +1716,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
}
var page = this.pageCache[data.pageIndex];
page.stats.timeEnd('Page Request');
page._stats.timeEnd('Page Request');
page._startRenderPage(data.transparency, data.intent);
}, this);

View File

@ -461,6 +461,86 @@ function isExternalLinkTargetSet() {
}
}
class StatTimer {
constructor(enable = true) {
this.enabled = !!enable;
this.reset();
}
reset() {
this.started = Object.create(null);
this.times = [];
}
time(name) {
if (!this.enabled) {
return;
}
if (name in this.started) {
warn('Timer is already running for ' + name);
}
this.started[name] = Date.now();
}
timeEnd(name) {
if (!this.enabled) {
return;
}
if (!(name in this.started)) {
warn('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() {
let times = this.times;
// Find the longest name for padding purposes.
let out = '', longest = 0;
for (let i = 0, ii = times.length; i < ii; ++i) {
let name = times[i]['name'];
if (name.length > longest) {
longest = name.length;
}
}
for (let i = 0, ii = times.length; i < ii; ++i) {
let span = times[i];
let duration = span.end - span.start;
out += `${span['name'].padEnd(longest)} ${duration}ms\n`;
}
return out;
}
}
/**
* Helps avoid having to initialize {StatTimer} instances, e.g. one for every
* page, in cases where the collected stats are not actually being used.
* This (dummy) class can thus, since all its methods are `static`, be directly
* shared between multiple call-sites without the need to be initialized first.
*
* NOTE: This must implement the same interface as {StatTimer}.
*/
class DummyStatTimer {
constructor() {
throw new Error('Cannot initialize DummyStatTimer.');
}
static reset() {}
static time(name) {}
static timeEnd(name) {}
static toString() {
return '';
}
}
export {
CustomStyle,
RenderingCancelledException,
@ -474,4 +554,6 @@ export {
DOMCMapReaderFactory,
DOMSVGFactory,
SimpleXMLParser,
StatTimer,
DummyStatTimer,
};

View File

@ -73,4 +73,3 @@ exports.RenderingCancelledException =
pdfjsDisplayDOMUtils.RenderingCancelledException;
exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl;
exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes;
exports.StatTimer = pdfjsSharedUtil.StatTimer;

View File

@ -1118,66 +1118,6 @@ function createPromiseCapability() {
return capability;
}
var StatTimer = (function StatTimerClosure() {
function rpad(str, pad, length) {
while (str.length < length) {
str += pad;
}
return str;
}
function StatTimer() {
this.started = Object.create(null);
this.times = [];
this.enabled = true;
}
StatTimer.prototype = {
time: function StatTimer_time(name) {
if (!this.enabled) {
return;
}
if (name in this.started) {
warn('Timer is already running for ' + name);
}
this.started[name] = Date.now();
},
timeEnd: function StatTimer_timeEnd(name) {
if (!this.enabled) {
return;
}
if (!(name in this.started)) {
warn('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 StatTimer_toString() {
var i, ii;
var times = this.times;
var out = '';
// Find the longest name for padding purposes.
var longest = 0;
for (i = 0, ii = times.length; i < ii; ++i) {
var name = times[i]['name'];
if (name.length > longest) {
longest = name.length;
}
}
for (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;
})();
var createBlob = function createBlob(data, contentType) {
if (typeof Blob !== 'undefined') {
return new Blob([data], { type: contentType, });
@ -1668,7 +1608,6 @@ export {
PageViewport,
PasswordException,
PasswordResponses,
StatTimer,
StreamType,
TextRenderingMode,
UnexpectedResponseException,

View File

@ -19,8 +19,6 @@
var WAITING_TIME = 100; // ms
var PDF_TO_CSS_UNITS = 96.0 / 72.0;
var StatTimer = pdfjsDistBuildPdf.StatTimer;
/**
* @class
*/
@ -536,9 +534,10 @@ var Driver = (function DriverClosure() { // eslint-disable-line no-unused-vars
if (annotationLayerCanvas) {
ctx.drawImage(annotationLayerCanvas, 0, 0);
}
page.cleanup();
task.stats = page.stats;
page.stats = new StatTimer();
if (page.stats) { // Get the page stats *before* running cleanup.
task.stats = page.stats;
}
page.cleanup(/* resetStats = */ true);
self._snapshot(task, error);
});
initPromise.then(function () {

View File

@ -1668,7 +1668,8 @@ function webViewerPageRendered(evt) {
thumbnailView.setImage(pageView);
}
if (PDFJS.pdfBug && Stats.enabled && pageView.stats) {
if (PDFJS.pdfBug && typeof Stats !== 'undefined' && Stats.enabled &&
pageView.stats) {
Stats.add(pageNumber, pageView.stats);
}
@ -1957,9 +1958,9 @@ function webViewerPageChanging(evt) {
}
// we need to update stats
if (PDFJS.pdfBug && Stats.enabled) {
if (PDFJS.pdfBug && typeof Stats !== 'undefined' && Stats.enabled) {
let pageView = PDFViewerApplication.pdfViewer.getPageView(page - 1);
if (pageView.stats) {
if (pageView && pageView.stats) {
Stats.add(page, pageView.stats);
}
}