瀏覽代碼

improve logger

dwelle 3 年之前
父節點
當前提交
1d65536360
共有 3 個文件被更改,包括 88 次插入25 次删除
  1. 86 20
      src/components/App.tsx
  2. 1 1
      src/global.d.ts
  3. 1 4
      src/renderer/renderScene.ts

+ 86 - 20
src/components/App.tsx

@@ -264,51 +264,99 @@ import {
 } from "../element/Hyperlink";
 import { shouldShowBoundingBox } from "../element/transformHandles";
 
-const TIMES_AGGR: Record<string, { t: number; times: number[] }> = {};
-const TIMES_AVG: Record<string, { times: number[] }> = {};
+let TIMES_AGGR: Record<string, { t: number; times: number[] }> = {};
+let TIMES_AVG: Record<
+  string,
+  { t: number; times: number[]; avg: number | null }
+> = {};
 
 window.DEBUG_LOG_TIMES = true;
 
-setInterval(() => {
+let lastDebugLogCall = 0;
+let DEBUG_LOG_INTERVAL_ID: null | number = null;
+
+const setupInterval = () => {
+  if (DEBUG_LOG_INTERVAL_ID === null) {
+    console.info("%c(starting perf recording)", "color: lime");
+    DEBUG_LOG_INTERVAL_ID = window.setInterval(debugLogger, 1000);
+  }
+  lastDebugLogCall = Date.now();
+};
+
+const lessPrecise = (num: number, precision = 5) =>
+  parseFloat(num.toPrecision(precision));
+
+const getAvgFrameTime = (times: number[]) =>
+  lessPrecise(times.reduce((a, b) => a + b) / times.length);
+
+const getFps = (frametime: number) => lessPrecise(1000 / frametime);
+
+const debugLogger = () => {
+  if (Date.now() - lastDebugLogCall > 600 && DEBUG_LOG_INTERVAL_ID !== null) {
+    window.clearInterval(DEBUG_LOG_INTERVAL_ID);
+    DEBUG_LOG_INTERVAL_ID = null;
+    for (const [name, { avg }] of Object.entries(TIMES_AVG)) {
+      if (avg != null) {
+        console.info(
+          `%c${name} run avg: ${avg}ms (${getFps(avg)} fps)`,
+          "color: blue",
+        );
+      }
+    }
+    console.info("%c(stopping perf recording)", "color: red");
+    TIMES_AGGR = {};
+    TIMES_AVG = {};
+    return;
+  }
   if (window.DEBUG_LOG_TIMES) {
     for (const [name, { t, times }] of Object.entries(TIMES_AGGR)) {
       if (times.length) {
         console.info(
           name,
-          times.reduce((a, b) => a + b),
-          times.sort((a, b) => a - b),
+          lessPrecise(times.reduce((a, b) => a + b) / times.length),
+          times.sort((a, b) => a - b).map((x) => lessPrecise(x)),
         );
         TIMES_AGGR[name] = { t, times: [] };
       }
     }
-    for (const [name, { times }] of Object.entries(TIMES_AVG)) {
+    for (const [name, { t, times, avg }] of Object.entries(TIMES_AVG)) {
       if (times.length) {
-        console.info(
-          name,
-          parseFloat(
-            (times.reduce((a, b) => a + b) / times.length).toPrecision(5),
-          ),
-          times.sort((a, b) => a - b),
-        );
-        TIMES_AVG[name] = { times: [] };
+        const avgFrameTime = getAvgFrameTime(times);
+        console.info(name, `${avgFrameTime}ms (${getFps(avgFrameTime)} fps)`);
+        TIMES_AVG[name] = {
+          t,
+          times: [],
+          avg:
+            avg != null ? getAvgFrameTime([avg, avgFrameTime]) : avgFrameTime,
+        };
       }
     }
   }
-}, 1000);
+};
 
 window.logTime = (name: string, time?: number) => {
+  setupInterval();
+  const now = performance.now();
   const { t, times } = (TIMES_AGGR[name] = TIMES_AGGR[name] || {
     t: 0,
     times: [],
   });
   if (t) {
-    times.push(time != null ? time : Date.now() - t);
+    times.push(time != null ? time : now - t);
   }
-  TIMES_AGGR[name].t = Date.now();
+  TIMES_AGGR[name].t = now;
 };
-window.logTimeAverage = (name: string, time: number) => {
-  const { times } = (TIMES_AVG[name] = TIMES_AVG[name] || { times: [] });
-  times.push(time);
+window.logTimeAverage = (name: string, time?: number) => {
+  setupInterval();
+  const now = performance.now();
+  const { t, times } = (TIMES_AVG[name] = TIMES_AVG[name] || {
+    t: 0,
+    times: [],
+  });
+  if (t) {
+    times.push(time != null ? time : now - t);
+  }
+  TIMES_AVG[name].t = now;
 };
 
 const deviceContextInitialValue = {
@@ -525,6 +573,24 @@ class App extends React.Component<AppProps, AppState> {
 
   private __renderUI = true;
 
+  private perfTest = (runs = 180, initial = true) => {
+    if (initial) {
+      console.time("perfTest");
+    } else if (!runs) {
+      console.timeEnd("perfTest");
+    }
+    if (runs) {
+      requestAnimationFrame((id) => {
+        for (const element of this.scene.getNonDeletedElements()) {
+          mutateElement(element, {
+            x: element.x + 1,
+          });
+        }
+        this.perfTest(runs - 1, false);
+      });
+    }
+  };
+
   public render() {
     const selectedElement = getSelectedElements(
       this.scene.getNonDeletedElements(),

+ 1 - 1
src/global.d.ts

@@ -17,7 +17,7 @@ interface Window {
   EXCALIDRAW_THROTTLE_RENDER: boolean | undefined;
   gtag: Function;
   logTime: (name: string, time?: number) => void;
-  logTimeAverage: (name: string, time: number) => void;
+  logTimeAverage: (name: string, time?: number) => void;
   DEBUG_LOG_TIMES: boolean;
 }
 

+ 1 - 4
src/renderer/renderScene.ts

@@ -310,8 +310,6 @@ const renderLinearElementPointHighlight = (
   context.restore();
 };
 
-let t = performance.now();
-
 export const _renderScene = ({
   elements,
   appState,
@@ -332,8 +330,7 @@ export const _renderScene = ({
     if (canvas === null) {
       return { atLeastOneVisibleElement: false };
     }
-    window.logTimeAverage("renderScene", performance.now() - t);
-    t = performance.now();
+    window.logTimeAverage("renderScene");
     const {
       renderScrollbars = true,
       renderSelection = true,