You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
6.1 KiB

(function (global) {
'use strict';
/**
* Ring-buffer performance sampler reading cc.profiler.stats.
* @constructor
*/
function PerfSampler() {
this.intervalMs = 200;
this.capacity = 300;
this.paused = false;
this.times = [];
this.series = {
fps: [],
frame: [],
draws: [],
tricount: [],
logic: [],
physics: [],
render: [],
present: [],
textureMemory: [],
bufferMemory: [],
jsHeap: [],
assetCount: [],
};
this.markers = [];
this._timer = 0;
this._cc = null;
this._onSample = null;
this._userMarkSeq = 0;
}
/** @param {*} cc */
PerfSampler.prototype.bindEngine = function (cc) {
this._cc = cc;
// 不在绑定时强制 showStats:引擎初始化未完成时会触发 profiler null 报错
};
/** @param {function():void} cb */
PerfSampler.prototype.onSample = function (cb) {
this._onSample = cb;
};
/** Start interval sampling. */
PerfSampler.prototype.start = function () {
var self = this;
this.stop();
this._timer = setInterval(function () { self.sample(); }, this.intervalMs);
};
/** Stop sampling timer. */
PerfSampler.prototype.stop = function () {
if (this._timer) {
clearInterval(this._timer);
this._timer = 0;
}
};
/**
* Set capacity for time window.
* @param {number} n
*/
PerfSampler.prototype.setCapacity = function (n) {
this.capacity = n;
this._trim();
};
/**
* Set sample interval ms.
* @param {number} ms
*/
PerfSampler.prototype.setIntervalMs = function (ms) {
this.intervalMs = ms;
if (this._timer) this.start();
};
/** Clear series and markers. */
PerfSampler.prototype.clear = function () {
this.times.length = 0;
for (var k in this.series) {
if (Object.prototype.hasOwnProperty.call(this.series, k)) this.series[k].length = 0;
}
this.markers.length = 0;
this._userMarkSeq = 0;
};
/**
* Push marker at now.
* @param {string} label
*/
PerfSampler.prototype.mark = function (label) {
this.markers.push({ t: performance.now(), label: String(label || 'mark') });
if (this.markers.length > 200) this.markers.splice(0, this.markers.length - 200);
if (this._onSample) this._onSample();
};
/** User mark from UI. */
PerfSampler.prototype.userMark = function (text) {
this._userMarkSeq += 1;
var label = text && String(text).trim() ? String(text).trim() : ('user:' + this._userMarkSeq);
this.mark(label);
};
/** Take one sample. */
PerfSampler.prototype.sample = function () {
if (this.paused) return;
var cc = this._cc;
var now = performance.now();
var stats = cc && cc.profiler ? cc.profiler.stats : null;
function read(key) {
if (!stats || !stats[key] || !stats[key].counter) return 0;
var v = stats[key].counter.value;
return typeof v === 'number' ? v : 0;
}
this.times.push(now);
this.series.fps.push(read('fps'));
this.series.frame.push(read('frame'));
this.series.draws.push(read('draws'));
this.series.tricount.push(read('tricount'));
this.series.logic.push(read('logic'));
this.series.physics.push(read('physics'));
this.series.render.push(read('render'));
this.series.present.push(read('present'));
this.series.textureMemory.push(read('textureMemory'));
this.series.bufferMemory.push(read('bufferMemory'));
var heap = 0;
if (performance.memory && performance.memory.usedJSHeapSize) {
heap = performance.memory.usedJSHeapSize / (1024 * 1024);
}
this.series.jsHeap.push(heap);
var assetCount = 0;
if (cc && cc.assetManager && cc.assetManager.assets) {
try {
cc.assetManager.assets.forEach(function () { assetCount += 1; });
} catch (e) {
assetCount = 0;
}
}
this.series.assetCount.push(assetCount);
this._trim();
if (this._onSample) this._onSample();
};
/** Latest scalar snapshot for strip/summary. */
PerfSampler.prototype.latest = function () {
function last(arr) { return arr.length ? arr[arr.length - 1] : 0; }
return {
fps: last(this.series.fps),
frame: last(this.series.frame),
draws: last(this.series.draws),
textureMemory: last(this.series.textureMemory),
bufferMemory: last(this.series.bufferMemory),
jsHeap: last(this.series.jsHeap),
assetCount: last(this.series.assetCount),
};
};
/** Export CSV string. */
PerfSampler.prototype.toCsv = function () {
var keys = Object.keys(this.series);
var lines = ['t,' + keys.join(',')];
for (var i = 0; i < this.times.length; i++) {
var row = [this.times[i]];
for (var k = 0; k < keys.length; k++) row.push(this.series[keys[k]][i]);
lines.push(row.join(','));
}
if (this.markers.length) {
lines.push('');
lines.push('marker_t,label');
for (var m = 0; m < this.markers.length; m++) {
lines.push(this.markers[m].t + ',' + JSON.stringify(this.markers[m].label));
}
}
return lines.join('\n');
};
PerfSampler.prototype._trim = function () {
while (this.times.length > this.capacity) {
this.times.shift();
for (var k in this.series) {
if (Object.prototype.hasOwnProperty.call(this.series, k)) this.series[k].shift();
}
}
if (this.times.length) {
var t0 = this.times[0];
while (this.markers.length && this.markers[0].t < t0 - 1000) this.markers.shift();
}
};
global.PWPerfSampler = PerfSampler;
})(window);