Просмотр исходного кода

Merge pull request #10040 from overleaf/td-cm6-count-inputs-between-dom-updates

Record the maximum number of user input events between CM6 DOM updates

GitOrigin-RevId: 1a779a7d8e3675447cf58e2840afd0781bdc6ab9
Tim Down 4 лет назад
Родитель
Сommit
bfb8aaffdd
2 измененных файлов с 44 добавлено и 9 удалено
  1. 2 0
      services/web/frontend/js/ide.js
  2. 42 9
      services/web/frontend/js/infrastructure/cm6-performance.ts

+ 2 - 0
services/web/frontend/js/ide.js

@@ -276,6 +276,8 @@ If the project has been renamed please look in your project list for a new proje
               cm6PerfData.ninetyFifthPercentile
               cm6PerfData.ninetyFifthPercentile
             segmentation.cm6PerfDocLength = cm6PerfData.docLength
             segmentation.cm6PerfDocLength = cm6PerfData.docLength
             segmentation.cm6PerfNumberOfEntries = cm6PerfData.numberOfEntries
             segmentation.cm6PerfNumberOfEntries = cm6PerfData.numberOfEntries
+            segmentation.cm6PerfMaxUserEventsBetweenDomUpdates =
+              cm6PerfData.maxUserEventsBetweenDomUpdates
           }
           }
         }
         }
 
 

+ 42 - 9
services/web/frontend/js/infrastructure/cm6-performance.ts

@@ -1,4 +1,5 @@
 import { Transaction } from '@codemirror/state'
 import { Transaction } from '@codemirror/state'
+import { EditorView } from '@codemirror/view'
 
 
 const TIMER_START_NAME = 'CM6-BeforeUpdate'
 const TIMER_START_NAME = 'CM6-BeforeUpdate'
 const TIMER_END_NAME = 'CM6-AfterUpdate'
 const TIMER_END_NAME = 'CM6-AfterUpdate'
@@ -16,8 +17,20 @@ try {
   performanceMeasureOptionsSupport = true
   performanceMeasureOptionsSupport = true
 } catch (e) {}
 } catch (e) {}
 
 
-export function timedDispatch(dispatchFn: (tr: Transaction) => void) {
-  return (tr: Transaction) => {
+function isInputOrDelete(userEventType: string | undefined) {
+  return (
+    !!userEventType && ['input', 'delete'].includes(userEventType.split('.')[0])
+  )
+}
+
+export function timedDispatch() {
+  let userEventsSinceDomUpdateCount = 0
+
+  return (
+    view: EditorView,
+    tr: Transaction,
+    dispatchFn: (tr: Transaction) => void
+  ) => {
     if (!performanceMeasureOptionsSupport) {
     if (!performanceMeasureOptionsSupport) {
       dispatchFn(tr)
       dispatchFn(tr)
       return
       return
@@ -31,11 +44,22 @@ export function timedDispatch(dispatchFn: (tr: Transaction) => void) {
 
 
     const userEventType = tr.annotation(Transaction.userEvent)
     const userEventType = tr.annotation(Transaction.userEvent)
 
 
-    if (userEventType) {
+    if (isInputOrDelete(userEventType)) {
+      ++userEventsSinceDomUpdateCount
+
       performance.measure(TIMER_MEASURE_NAME, {
       performance.measure(TIMER_MEASURE_NAME, {
         start: TIMER_START_NAME,
         start: TIMER_START_NAME,
         end: TIMER_END_NAME,
         end: TIMER_END_NAME,
-        detail: { userEventType },
+        detail: { userEventType, userEventsSinceDomUpdateCount },
+      })
+
+      // The `key` property ensures that the measurement task is only run once
+      // per measure phase
+      view.requestMeasure({
+        key: 'inputEventCounter',
+        read() {
+          userEventsSinceDomUpdateCount = 0
+        },
       })
       })
     }
     }
 
 
@@ -68,6 +92,10 @@ function calculate95thPercentile(sortedDurations: number[]) {
   return sortedDurations[index]
   return sortedDurations[index]
 }
 }
 
 
+function calculateMax(numbers: number[]) {
+  return numbers.reduce((a, b) => Math.max(a, b), 0)
+}
+
 export function reportCM6Perf() {
 export function reportCM6Perf() {
   // Get entries triggered by keystrokes
   // Get entries triggered by keystrokes
   const cm6Entries = performance.getEntriesByName(
   const cm6Entries = performance.getEntriesByName(
@@ -75,17 +103,21 @@ export function reportCM6Perf() {
     'measure'
     'measure'
   ) as PerformanceMeasure[]
   ) as PerformanceMeasure[]
 
 
-  const inputDurations = cm6Entries
-    .filter(({ detail }) =>
-      ['input', 'delete'].includes(detail.userEventType.split('.')[0])
-    )
+  const inputEvents = cm6Entries.filter(({ detail }) =>
+    isInputOrDelete(detail.userEventType)
+  )
+
+  const inputDurations = inputEvents
     .map(({ duration }) => duration)
     .map(({ duration }) => duration)
     .sort((a, b) => a - b)
     .sort((a, b) => a - b)
 
 
-  const max = inputDurations.reduce((a, b) => Math.max(a, b), 0)
+  const max = calculateMax(inputDurations)
   const mean = calculateMean(inputDurations)
   const mean = calculateMean(inputDurations)
   const median = calculateMedian(inputDurations)
   const median = calculateMedian(inputDurations)
   const ninetyFifthPercentile = calculate95thPercentile(inputDurations)
   const ninetyFifthPercentile = calculate95thPercentile(inputDurations)
+  const maxUserEventsBetweenDomUpdates = calculateMax(
+    inputEvents.map(e => e.detail.userEventsSinceDomUpdateCount)
+  )
 
 
   performance.clearMeasures(TIMER_MEASURE_NAME)
   performance.clearMeasures(TIMER_MEASURE_NAME)
 
 
@@ -94,6 +126,7 @@ export function reportCM6Perf() {
     mean,
     mean,
     median,
     median,
     ninetyFifthPercentile,
     ninetyFifthPercentile,
+    maxUserEventsBetweenDomUpdates,
     docLength: latestDocLength,
     docLength: latestDocLength,
     numberOfEntries: inputDurations.length,
     numberOfEntries: inputDurations.length,
   }
   }