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.
197 lines
6.1 KiB
197 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);
|
|
|