Skip to content

Instantly share code, notes, and snippets.

@joshbeckman
Last active January 22, 2018 04:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshbeckman/4bb4db766354384a65accbb4f12e4b7f to your computer and use it in GitHub Desktop.
Save joshbeckman/4bb4db766354384a65accbb4f12e4b7f to your computer and use it in GitHub Desktop.
import log from './log.js';
import __ from './console.sparkline.js';
const debug = log('[perf]');
export const hasPerf = typeof self !== 'undefined' && self.performance;
export const hasPerfNow = hasPerf && self.performance.now;
export const hasPerfMark = hasPerf && self.performance.mark;
let marks = {};
let measures = {};
function mean(values) {
return values.reduce((acc, val) => {
return acc + val;
}, 0) / values.length;
}
export const perf = {
now: () => {
if (!hasPerfNow)
return Date.now();
return self.performance.now();
},
mark: (name = 'untitled') => {
if (hasPerfMark) {
return self.performance.mark(name);
}
return marks[name] = perf.now();
},
measure: (name = 'untitled', start = 'untitled_start', end = 'untitled_end') => {
if (hasPerfMark) {
return self.performance.measure(name, start, end);
}
measures[name] = measures[name] || [];
measures[name].push({
duration: marks[end] - marks[start],
start: marks[start],
end: marks[end],
});
},
clearMarks: (name) => {
if (hasPerfMark)
return self.performance.clearMarks(name);
if (name) {
delete marks[name];
return;
}
marks = {};
},
clearMeasures: (name) => {
if (hasPerfMark)
return self.performance.clearMeasures(name);
if (name) {
delete measures[name];
return;
}
measures = {};
},
getEntriesByName: (name = 'untitled') => {
if (hasPerfMark) {
return self.performance.getEntriesByName(name);
}
return measures[name] || [];
},
getEntryByName: (name = 'untitled') => {
const entries = perf.getEntriesByName(name);
return entries[entries.length - 1];
},
start: (name = 'untitled') => {
return perf.mark(name + '_start');
},
end: (name = 'untitled') => {
const e = perf.mark(name + '_end');
perf.measure(name, name + '_start', name + '_end');
return e;
},
duration: (name = 'untitled') => {
return (perf.getEntryByName(name) || {}).duration;
},
mean: (name = 'untitled') => {
return mean(perf.getEntriesByName(name).map(d => d.duration));
},
sdev: (name = 'untitled') => {
const entries = perf.getEntriesByName(name).map(d => d.duration);
const avg = mean(entries);
const squareDiffs = entries.map((value) => {
const diff = value - avg;
return diff * diff;
});
return Math.sqrt(mean(squareDiffs));
},
percentile: (name = 'untitled', percent = 0) => {
const values = perf.getEntriesByName(name).map(d => d.duration).sort();
const len = values.length;
const index = Math.min(len - 1, Math.max(0, Math.floor(len * percent)));
return values[index];
},
log: (name = 'untitled', level = 'info') => {
debug[level](`${name} took ${perf.duration(name).toFixed(2)}ms`, {
mean: perf.mean(name),
sdev: perf.sdev(name),
samples: perf.getEntriesByName(name).length,
});
console.sparkline('[perf] ' + name, perf.getEntriesByName(name).map(d => d.duration));
},
onFPS: (cb, interval = 1000) => {
var prevTime = perf.now(),
time = prevTime;
let frames = 0;
let fps = 0;
let scalar = 1000 / interval;
(function iterate () {
frames++;
time = perf.now();
if (time >= (prevTime + interval)) {
fps = (frames * interval) / (time - prevTime) * scalar;
frames = 0;
prevTime = time;
if (cb) cb(fps, time);
}
(self.requestAnimationFrame || self.setTimeout)(iterate, 0);
})();
}
};
export default perf;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment