Bläddra i källkod

feat(metrics): related to conference.init execution.

Adds logs and analytics events with time measurements for the different stages of conference.init execution.
factor2
Hristo Terezov 1 år sedan
förälder
incheckning
61a0247f30

+ 23
- 4
conference.js Visa fil

@@ -136,6 +136,7 @@ import {
136 136
     isUserInteractionRequiredForUnmute
137 137
 } from './react/features/base/tracks/functions';
138 138
 import { downloadJSON } from './react/features/base/util/downloadJSON';
139
+import { getJitsiMeetGlobalNSConnectionTimes } from './react/features/base/util/helpers';
139 140
 import { openLeaveReasonDialog } from './react/features/conference/actions.web';
140 141
 import { showDesktopPicker } from './react/features/desktop-picker/actions';
141 142
 import { appendSuffix } from './react/features/display-name/functions';
@@ -413,9 +414,10 @@ export default {
413 414
      * without any audio tracks.
414 415
      * @param {boolean} options.startWithVideoMuted - will start the conference
415 416
      * without any video tracks.
417
+     * @param {boolean} recordTimeMetrics - If true time metrics will be recorded.
416 418
      * @returns {Promise<JitsiLocalTrack[]>, Object}
417 419
      */
418
-    createInitialLocalTracks(options = {}) {
420
+    createInitialLocalTracks(options = {}, recordTimeMetrics = false) {
419 421
         const errors = {};
420 422
 
421 423
         // Always get a handle on the audio input device so that we have statistics (such as "No audio input" or
@@ -487,7 +489,7 @@ export default {
487 489
                 devices: initialDevices,
488 490
                 timeout,
489 491
                 firePermissionPromptIsShownEvent: true
490
-            })).then(({ tracks, errors: pErrors }) => {
492
+            }, recordTimeMetrics)).then(({ tracks, errors: pErrors }) => {
491 493
                 Object.assign(errors, pErrors);
492 494
 
493 495
                 return tracks;
@@ -571,8 +573,12 @@ export default {
571 573
             startWithAudioMuted: getStartWithAudioMuted(state) || isUserInteractionRequiredForUnmute(state),
572 574
             startWithVideoMuted: getStartWithVideoMuted(state) || isUserInteractionRequiredForUnmute(state)
573 575
         };
576
+        const connectionTimes = getJitsiMeetGlobalNSConnectionTimes();
577
+        const startTime = window.performance.now();
574 578
 
575
-        logger.debug(`Executed conference.init with roomName: ${roomName}`);
579
+        connectionTimes['conference.init.start'] = startTime;
580
+
581
+        logger.debug(`Executed conference.init with roomName: ${roomName} (performance.now=${startTime})`);
576 582
 
577 583
         this.roomName = roomName;
578 584
 
@@ -605,9 +611,19 @@ export default {
605 611
             return localTracks;
606 612
         };
607 613
         const { dispatch, getState } = APP.store;
608
-        const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
614
+        const createLocalTracksStart = window.performance.now();
615
+
616
+        connectionTimes['conference.init.createLocalTracks.start'] = createLocalTracksStart;
617
+
618
+        logger.debug(`(TIME) createInitialLocalTracks: ${createLocalTracksStart} `);
619
+
620
+        const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions, true);
609 621
 
610 622
         tryCreateLocalTracks.then(async tr => {
623
+            const createLocalTracksEnd = window.performance.now();
624
+
625
+            connectionTimes['conference.init.createLocalTracks.end'] = createLocalTracksEnd;
626
+            logger.debug(`(TIME) createInitialLocalTracks finished: ${createLocalTracksEnd} `);
611 627
             const tracks = handleInitialTracks(initialOptions, tr);
612 628
 
613 629
             this._initDeviceList(true);
@@ -621,6 +637,8 @@ export default {
621 637
                 // which will guarantee us that the local tracks are added to redux before we proceed.
622 638
                 initPrejoin(tracks, errors, dispatch);
623 639
 
640
+                connectionTimes['conference.init.end'] = window.performance.now();
641
+
624 642
                 // resolve the initialGUMPromise in case connect have finished so that we can proceed to join.
625 643
                 if (initialGUMPromise) {
626 644
                     logger.debug('Resolving the initialGUM promise! (prejoinVisible=true)');
@@ -639,6 +657,7 @@ export default {
639 657
                 APP.store.dispatch(displayErrorsForCreateInitialLocalTracks(errors));
640 658
                 setGUMPendingStateOnFailedTracks(tracks, APP.store.dispatch);
641 659
 
660
+                connectionTimes['conference.init.end'] = window.performance.now();
642 661
                 if (initialGUMPromise) {
643 662
                     logger.debug('Resolving the initialGUM promise!');
644 663
                     initialGUMPromise.resolve({

+ 6
- 0
react/features/base/devices/actions.web.ts Visa fil

@@ -75,6 +75,9 @@ export function configureInitialDevices() {
75 75
         const deviceLabels = getDevicesFromURL(getState());
76 76
         let updateSettingsPromise;
77 77
 
78
+        logger.debug(`(TIME) configureInitialDevices: deviceLabels=${
79
+            Boolean(deviceLabels)}, performance.now=${window.performance.now()}`);
80
+
78 81
         if (deviceLabels) {
79 82
             updateSettingsPromise = dispatch(getAvailableDevices()).then(() => {
80 83
                 const state = getState();
@@ -127,6 +130,9 @@ export function configureInitialDevices() {
127 130
             .then(() => {
128 131
                 const userSelectedAudioOutputDeviceId = getUserSelectedOutputDeviceId(getState());
129 132
 
133
+                logger.debug(`(TIME) configureInitialDevices -> setAudioOutputDeviceId: performance.now=${
134
+                    window.performance.now()}`);
135
+
130 136
                 return setAudioOutputDeviceId(userSelectedAudioOutputDeviceId, dispatch)
131 137
                     .catch(ex => logger.warn(`Failed to set audio output device.
132 138
                         Default audio output device will be used instead ${ex}`));

+ 3
- 2
react/features/base/tracks/actions.web.ts Visa fil

@@ -352,9 +352,10 @@ export function createAndAddInitialAVTracks(devices: Array<MediaType>) {
352 352
  * Creates the initial audio/video tracks.
353 353
  *
354 354
  * @param {ICreateInitialTracksOptions} options - Options for creating the audio/video tracks.
355
+ * @param {boolean} recordTimeMetrics - If true time metrics will be recorded.
355 356
  * @returns {Function}
356 357
  */
357
-export function createInitialAVTracks(options: ICreateInitialTracksOptions) {
358
+export function createInitialAVTracks(options: ICreateInitialTracksOptions, recordTimeMetrics = false) {
358 359
     return (dispatch: IStore['dispatch'], _getState: IStore['getState']) => {
359 360
         const {
360 361
             devices,
@@ -364,7 +365,7 @@ export function createInitialAVTracks(options: ICreateInitialTracksOptions) {
364 365
 
365 366
         dispatch(gumPending(devices, IGUMPendingState.PENDING_UNMUTE));
366 367
 
367
-        return createLocalTracksF(options).then(tracks => {
368
+        return createLocalTracksF(options, undefined, recordTimeMetrics).then(tracks => {
368 369
             return {
369 370
                 errors: {} as IInitialTracksErrors,
370 371
                 tracks

+ 7
- 1
react/features/base/tracks/functions.web.ts Visa fil

@@ -11,6 +11,7 @@ import {
11 11
     getUserSelectedCameraDeviceId,
12 12
     getUserSelectedMicDeviceId
13 13
 } from '../settings/functions.web';
14
+import { getJitsiMeetGlobalNSConnectionTimes } from '../util/helpers';
14 15
 
15 16
 import { getCameraFacingMode } from './functions.any';
16 17
 import loadEffects from './loadEffects';
@@ -36,9 +37,10 @@ export * from './functions.any';
36 37
  * corresponding event.
37 38
  * @param {IStore} store - The redux store in the context of which the function
38 39
  * is to execute and from which state such as {@code config} is to be retrieved.
40
+ * @param {boolean} recordTimeMetrics - If true time metrics will be recorded.
39 41
  * @returns {Promise<JitsiLocalTrack[]>}
40 42
  */
41
-export function createLocalTracksF(options: ITrackOptions = {}, store?: IStore) {
43
+export function createLocalTracksF(options: ITrackOptions = {}, store?: IStore, recordTimeMetrics = false) {
42 44
     let { cameraDeviceId, micDeviceId } = options;
43 45
     const {
44 46
         desktopSharingSourceDevice,
@@ -69,6 +71,10 @@ export function createLocalTracksF(options: ITrackOptions = {}, store?: IStore)
69 71
 
70 72
     return (
71 73
         loadEffects(store).then((effectsArray: Object[]) => {
74
+            if (recordTimeMetrics) {
75
+                getJitsiMeetGlobalNSConnectionTimes()['trackEffects.loaded'] = window.performance.now();
76
+            }
77
+
72 78
             // Filter any undefined values returned by Promise.resolve().
73 79
             const effects = effectsArray.filter(effect => Boolean(effect));
74 80
 

+ 8
- 1
react/features/base/tracks/loadEffects.web.ts Visa fil

@@ -11,6 +11,7 @@ import logger from './logger';
11 11
  * @returns {Promise} - A Promise which resolves when all effects are created.
12 12
  */
13 13
 export default function loadEffects(store: IStore): Promise<any> {
14
+    const start = window.performance.now();
14 15
     const state = store.getState();
15 16
     const virtualBackground = state['features/virtual-background'];
16 17
     const noiseSuppression = state['features/noise-suppression'];
@@ -30,5 +31,11 @@ export default function loadEffects(store: IStore): Promise<any> {
30 31
         ? Promise.resolve(new NoiseSuppressionEffect(nsOptions))
31 32
         : Promise.resolve();
32 33
 
33
-    return Promise.all([ backgroundPromise, noiseSuppressionPromise ]);
34
+    return Promise.all([ backgroundPromise, noiseSuppressionPromise ]).then(effectsArray => {
35
+        const end = window.performance.now();
36
+
37
+        logger.debug(`(TIME) loadEffects() start=${start}, end=${end}, time=${end - start}`);
38
+
39
+        return effectsArray;
40
+    });
34 41
 }

+ 15
- 0
react/features/base/util/helpers.ts Visa fil

@@ -100,6 +100,21 @@ export function getJitsiMeetGlobalNS() {
100 100
     return window.JitsiMeetJS.app;
101 101
 }
102 102
 
103
+/**
104
+ * Returns the object that stores the connection times.
105
+ *
106
+ * @returns {Object} - The object that stores the connection times.
107
+ */
108
+export function getJitsiMeetGlobalNSConnectionTimes() {
109
+    const globalNS = getJitsiMeetGlobalNS();
110
+
111
+    if (!globalNS.connectionTimes) {
112
+        globalNS.connectionTimes = {};
113
+    }
114
+
115
+    return globalNS.connectionTimes;
116
+}
117
+
103 118
 /**
104 119
  * Prints the error and reports it to the global error handler.
105 120
  *

+ 22
- 2
react/features/conference/actions.web.ts Visa fil

@@ -1,6 +1,7 @@
1 1
 import { IStore } from '../app/types';
2 2
 import { configureInitialDevices, getAvailableDevices } from '../base/devices/actions.web';
3 3
 import { openDialog } from '../base/dialog/actions';
4
+import { getJitsiMeetGlobalNSConnectionTimes } from '../base/util/helpers';
4 5
 import { getBackendSafeRoomName } from '../base/util/uri';
5 6
 
6 7
 import { DISMISS_CALENDAR_NOTIFICATION } from './actionTypes';
@@ -37,12 +38,29 @@ export function dismissCalendarNotification() {
37 38
 /**
38 39
  * Setups initial devices. Makes sure we populate availableDevices list before configuring.
39 40
  *
41
+ * @param {boolean} recordTimeMetrics - If true, an analytics time metrics will be sent.
40 42
  * @returns {Promise<any>}
41 43
  */
42
-export function setupInitialDevices() {
44
+export function setupInitialDevices(recordTimeMetrics = false) {
43 45
     return async (dispatch: IStore['dispatch']) => {
46
+        if (recordTimeMetrics) {
47
+            getJitsiMeetGlobalNSConnectionTimes()['setupInitialDevices.start'] = window.performance.now();
48
+        }
49
+
44 50
         await dispatch(getAvailableDevices());
51
+
52
+        if (recordTimeMetrics) {
53
+            getJitsiMeetGlobalNSConnectionTimes()['setupInitialDevices.getAD.finished'] = window.performance.now();
54
+        }
55
+
45 56
         await dispatch(configureInitialDevices());
57
+
58
+        const now = window.performance.now();
59
+
60
+        if (recordTimeMetrics) {
61
+            getJitsiMeetGlobalNSConnectionTimes()['setupInitialDevices.end'] = now;
62
+        }
63
+        logger.debug(`(TIME) setupInitialDevices finished: ${now}`);
46 64
     };
47 65
 }
48 66
 
@@ -55,11 +73,13 @@ export function setupInitialDevices() {
55 73
  */
56 74
 export function init(shouldDispatchConnect: boolean) {
57 75
     return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
76
+        logger.debug(`(TIME) init action dispatched: ${window.performance.now()}`);
77
+
58 78
         const room = getBackendSafeRoomName(getState()['features/base/conference'].room);
59 79
 
60 80
         // XXX For web based version we use conference initialization logic
61 81
         // from the old app (at the moment of writing).
62
-        return dispatch(setupInitialDevices()).then(
82
+        return dispatch(setupInitialDevices(true)).then(
63 83
             () => APP.conference.init({
64 84
                 roomName: room,
65 85
                 shouldDispatchConnect

+ 5
- 6
react/index.web.js Visa fil

@@ -4,7 +4,7 @@ import ReactDOM from 'react-dom';
4 4
 import { App } from './features/app/components/App.web';
5 5
 import { getLogger } from './features/base/logging/functions';
6 6
 import Platform from './features/base/react/Platform.web';
7
-import { getJitsiMeetGlobalNS } from './features/base/util/helpers';
7
+import { getJitsiMeetGlobalNS, getJitsiMeetGlobalNSConnectionTimes } from './features/base/util/helpers';
8 8
 import DialInSummaryApp from './features/invite/components/dial-in-summary/web/DialInSummaryApp';
9 9
 import PrejoinApp from './features/prejoin/components/web/PrejoinApp';
10 10
 import WhiteboardApp from './features/whiteboard/components/web/WhiteboardApp';
@@ -45,20 +45,19 @@ if (Platform.OS === 'ios') {
45 45
 }
46 46
 
47 47
 const globalNS = getJitsiMeetGlobalNS();
48
+const connectionTimes = getJitsiMeetGlobalNSConnectionTimes();
48 49
 
49 50
 // Used for automated performance tests.
50
-globalNS.connectionTimes = {
51
-    'index.loaded': window.indexLoadedTime
52
-};
51
+connectionTimes['index.loaded'] = window.indexLoadedTime;
53 52
 
54 53
 window.addEventListener('load', () => {
55
-    globalNS.connectionTimes['window.loaded'] = window.loadedEventTime;
54
+    connectionTimes['window.loaded'] = window.loadedEventTime;
56 55
 });
57 56
 
58 57
 document.addEventListener('DOMContentLoaded', () => {
59 58
     const now = window.performance.now();
60 59
 
61
-    globalNS.connectionTimes['document.ready'] = now;
60
+    connectionTimes['document.ready'] = now;
62 61
     logger.log('(TIME) document ready:\t', now);
63 62
 });
64 63
 

Laddar…
Avbryt
Spara