Add performance data collection mechanism

This commit is contained in:
Germain Souquet 2021-05-14 11:04:58 +01:00
parent d6a25d493a
commit 6804a26e74
2 changed files with 59 additions and 20 deletions

View file

@ -486,14 +486,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
startPageChangeTimer() { startPageChangeTimer() {
PerformanceMonitor.start(PerformanceEntryNames.SWITCH_ROOM); PerformanceMonitor.start(PerformanceEntryNames.PAGE_CHANGE);
} }
stopPageChangeTimer() { stopPageChangeTimer() {
PerformanceMonitor.stop(PerformanceEntryNames.SWITCH_ROOM); PerformanceMonitor.stop(PerformanceEntryNames.PAGE_CHANGE);
const entries = PerformanceMonitor.getEntries({ const entries = PerformanceMonitor.getEntries({
name: PerformanceEntryNames.SWITCH_ROOM, name: PerformanceEntryNames.PAGE_CHANGE,
}); });
const measurement = entries.pop(); const measurement = entries.pop();
@ -1612,13 +1612,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
action: 'start_registration', action: 'start_registration',
params: params, params: params,
}); });
Performance.start(PerformanceEntryNames.REGISTER); PerformanceMonitor.start(PerformanceEntryNames.REGISTER);
} else if (screen === 'login') { } else if (screen === 'login') {
dis.dispatch({ dis.dispatch({
action: 'start_login', action: 'start_login',
params: params, params: params,
}); });
Performance.start(PerformanceEntryNames.LOGIN); PerformanceMonitor.start(PerformanceEntryNames.LOGIN);
} else if (screen === 'forgot_password') { } else if (screen === 'forgot_password') {
dis.dispatch({ dis.dispatch({
action: 'start_password_recovery', action: 'start_password_recovery',
@ -1858,7 +1858,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// returns a promise which resolves to the new MatrixClient // returns a promise which resolves to the new MatrixClient
onRegistered(credentials: IMatrixClientCreds) { onRegistered(credentials: IMatrixClientCreds) {
Performance.stop(PerformanceEntryNames.REGISTER); PerformanceMonitor.stop(PerformanceEntryNames.REGISTER);
return Lifecycle.setLoggedIn(credentials); return Lifecycle.setLoggedIn(credentials);
} }
@ -1948,7 +1948,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// Create and start the client // Create and start the client
await Lifecycle.setLoggedIn(credentials); await Lifecycle.setLoggedIn(credentials);
await this.postLoginSetup(); await this.postLoginSetup();
Performance.stop(PerformanceEntryNames.LOGIN); PerformanceMonitor.stop(PerformanceEntryNames.LOGIN);
}; };
// complete security / e2e setup has finished // complete security / e2e setup has finished

View file

@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { string } from "prop-types";
import { PerformanceEntryNames } from "./entry-names"; import { PerformanceEntryNames } from "./entry-names";
const START_PREFIX = "start:"; const START_PREFIX = "start:";
@ -29,6 +28,16 @@ interface GetEntriesOptions {
type?: string, type?: string,
} }
type PerformanceCallbackFunction = (entry: PerformanceEntry) => void;
interface PerformanceDataListener {
entryTypes?: string[],
callback: PerformanceCallbackFunction
}
let listeners: PerformanceDataListener[] = [];
const entries: PerformanceEntry[] = [];
export default class PerformanceMonitor { export default class PerformanceMonitor {
/** /**
* Starts a performance recording * Starts a performance recording
@ -42,7 +51,7 @@ export default class PerformanceMonitor {
} }
const key = buildKey(name, id); const key = buildKey(name, id);
if (!performance.getEntriesByName(key).length) { if (performance.getEntriesByName(key).length > 0) {
console.warn(`Recording already started for: ${name}`); console.warn(`Recording already started for: ${name}`);
return; return;
} }
@ -57,12 +66,12 @@ export default class PerformanceMonitor {
* @param id Specify an identifier appended to the measurement name * @param id Specify an identifier appended to the measurement name
* @returns {void} * @returns {void}
*/ */
static stop(name: string, id?: string): void { static stop(name: string, id?: string): PerformanceEntry {
if (!supportsPerformanceApi()) { if (!supportsPerformanceApi()) {
return; return;
} }
const key = buildKey(name, id); const key = buildKey(name, id);
if (!performance.getEntriesByName(START_PREFIX + key).length) { if (performance.getEntriesByName(START_PREFIX + key).length === 0) {
console.warn(`No recording started for: ${name}`); console.warn(`No recording started for: ${name}`);
return; return;
} }
@ -75,6 +84,17 @@ export default class PerformanceMonitor {
); );
this.clear(name, id); this.clear(name, id);
const measurement = performance.getEntriesByName(key).pop();
// Keeping a reference to all PerformanceEntry created
// by this abstraction for historical events collection
// when adding a data callback
entries.push(measurement);
listeners.forEach(listener => emitPerformanceData(listener, measurement));
return measurement;
} }
static clear(name: string, id?: string): void { static clear(name: string, id?: string): void {
@ -87,18 +107,37 @@ export default class PerformanceMonitor {
} }
static getEntries({ name, type }: GetEntriesOptions = {}): PerformanceEntry[] { static getEntries({ name, type }: GetEntriesOptions = {}): PerformanceEntry[] {
if (!supportsPerformanceApi()) { return entries.filter(entry => {
return; const satisfiesName = !name || entry.name === name;
const satisfiedType = !type || entry.entryType === type;
return satisfiesName && satisfiedType;
});
} }
if (!name && !type) { static addPerformanceDataCallback(listener: PerformanceDataListener, buffer = false) {
return performance.getEntries(); listeners.push(listener);
} else if (!name) {
return performance.getEntriesByType(type); if (buffer) {
} else { entries.forEach(entry => emitPerformanceData(listener, entry));
return performance.getEntriesByName(name, type);
} }
} }
static removePerformanceDataCallback(callback?: PerformanceCallbackFunction) {
if (!callback) {
listeners = [];
} else {
listeners.splice(
listeners.findIndex(listener => listener.callback === callback),
1,
);
}
}
}
function emitPerformanceData(listener, entry): void {
if (!listener.entryTypes || listener.entryTypes.includes(entry.entryType)) {
listener.callback(entry)
}
} }
/** /**