From b7b33eba4a7d2a0ffb3c71cef9ab93ef7af8081a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 13 Mar 2024 15:49:09 +0530 Subject: [PATCH] Switch to contextBridge - Part 1 --- desktop/src/main.ts | 2 - desktop/src/preload.ts | 17 +- desktop/src/utils/logging.ts | 13 -- desktop/src/utils/processStats.ts | 295 -------------------------- web/packages/shared/electron/types.ts | 1 - 5 files changed, 7 insertions(+), 321 deletions(-) delete mode 100644 desktop/src/utils/processStats.ts diff --git a/desktop/src/main.ts b/desktop/src/main.ts index a280a9b59..4de93046a 100644 --- a/desktop/src/main.ts +++ b/desktop/src/main.ts @@ -19,7 +19,6 @@ import { setupMainMenu, setupTrayItem, } from "./utils/main"; -import { setupMainProcessStatsLogger } from "./utils/processStats"; let mainWindow: BrowserWindow; @@ -104,7 +103,6 @@ if (!gotTheLock) { // Some APIs can only be used after this event occurs. app.on("ready", async () => { logSystemInfo(); - setupMainProcessStatsLogger(); mainWindow = await createWindow(); const tray = setupTrayItem(mainWindow); const watcher = initWatcher(mainWindow); diff --git a/desktop/src/preload.ts b/desktop/src/preload.ts index a602e76bb..359c04266 100644 --- a/desktop/src/preload.ts +++ b/desktop/src/preload.ts @@ -1,3 +1,4 @@ +import { contextBridge } from "electron"; import { deleteDiskCache, getCacheDirectory, @@ -59,17 +60,14 @@ import { updateWatchMappingSyncedFiles, } from "./api/watch"; import { setupLogging } from "./utils/logging"; -import { - logRendererProcessMemoryUsage, - setupRendererProcessStatsLogger, -} from "./utils/processStats"; setupLogging(); -setupRendererProcessStatsLogger(); -const windowObject: any = window; - -windowObject["ElectronAPIs"] = { +// These objects exposed here will become available to the JS code in our +// renderer (the web/ code) as `window.ElectronAPIs.*` +// +// https://www.electronjs.org/docs/latest/tutorial/tutorial-preload +contextBridge.exposeInMainWorld("ElectronAPIs", { exists, checkExistsAndCreateDir, saveStreamToDisk, @@ -108,7 +106,6 @@ windowObject["ElectronAPIs"] = { runFFmpegCmd, muteUpdateNotification, generateImageThumbnail, - logRendererProcessMemoryUsage, registerForegroundEventListener, openDirectory, moveFile, @@ -120,4 +117,4 @@ windowObject["ElectronAPIs"] = { getPlatform, getCacheDirectory, setCustomCacheDirectory, -}; +}); diff --git a/desktop/src/utils/logging.ts b/desktop/src/utils/logging.ts index 351a1aef8..e57382a65 100644 --- a/desktop/src/utils/logging.ts +++ b/desktop/src/utils/logging.ts @@ -9,16 +9,3 @@ export function setupLogging(isDev?: boolean) { log.transports.file.format = "[{y}-{m}-{d}T{h}:{i}:{s}{z}] [{level}]{scope} {text}"; } - -export function convertBytesToHumanReadable( - bytes: number, - precision = 2, -): string { - if (bytes === 0 || isNaN(bytes)) { - return "0 MB"; - } - - const i = Math.floor(Math.log(bytes) / Math.log(1024)); - const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; - return (bytes / Math.pow(1024, i)).toFixed(precision) + " " + sizes[i]; -} diff --git a/desktop/src/utils/processStats.ts b/desktop/src/utils/processStats.ts deleted file mode 100644 index b10238eea..000000000 --- a/desktop/src/utils/processStats.ts +++ /dev/null @@ -1,295 +0,0 @@ -import ElectronLog from "electron-log"; -import { webFrame } from "electron/renderer"; -import { convertBytesToHumanReadable } from "./logging"; - -const LOGGING_INTERVAL_IN_MICROSECONDS = 30 * 1000; // 30 seconds - -const SPIKE_DETECTION_INTERVAL_IN_MICROSECONDS = 1 * 1000; // 1 seconds - -const MAIN_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE = 50 * 1024; // 50 MB - -const HIGH_MAIN_MEMORY_USAGE_THRESHOLD_IN_KILOBYTES = 200 * 1024; // 200 MB - -const RENDERER_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE = 200 * 1024; // 200 MB - -const HIGH_RENDERER_MEMORY_USAGE_THRESHOLD_IN_KILOBYTES = 1024 * 1024; // 1 GB - -async function logMainProcessStats() { - const processMemoryInfo = await getNormalizedProcessMemoryInfo( - await process.getProcessMemoryInfo(), - ); - const cpuUsage = process.getCPUUsage(); - const heapStatistics = getNormalizedHeapStatistics( - process.getHeapStatistics(), - ); - - ElectronLog.log("main process stats", { - processMemoryInfo, - heapStatistics, - cpuUsage, - }); -} - -let previousMainProcessMemoryInfo: Electron.ProcessMemoryInfo = { - private: 0, - shared: 0, - residentSet: 0, -}; - -let mainProcessUsingHighMemory = false; - -async function logSpikeMainMemoryUsage() { - const processMemoryInfo = await process.getProcessMemoryInfo(); - const currentMemoryUsage = Math.max( - processMemoryInfo.residentSet ?? 0, - processMemoryInfo.private, - ); - const previousMemoryUsage = Math.max( - previousMainProcessMemoryInfo.residentSet ?? 0, - previousMainProcessMemoryInfo.private, - ); - const isSpiking = - currentMemoryUsage - previousMemoryUsage >= - MAIN_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE; - - const isHighMemoryUsage = - currentMemoryUsage >= HIGH_MAIN_MEMORY_USAGE_THRESHOLD_IN_KILOBYTES; - - const shouldReport = - (isHighMemoryUsage && !mainProcessUsingHighMemory) || - (!isHighMemoryUsage && mainProcessUsingHighMemory); - - if (isSpiking || shouldReport) { - const normalizedCurrentProcessMemoryInfo = - await getNormalizedProcessMemoryInfo(processMemoryInfo); - const normalizedPreviousProcessMemoryInfo = - await getNormalizedProcessMemoryInfo(previousMainProcessMemoryInfo); - const cpuUsage = process.getCPUUsage(); - const heapStatistics = getNormalizedHeapStatistics( - process.getHeapStatistics(), - ); - - ElectronLog.log("reporting main memory usage spike", { - currentProcessMemoryInfo: normalizedCurrentProcessMemoryInfo, - previousProcessMemoryInfo: normalizedPreviousProcessMemoryInfo, - heapStatistics, - cpuUsage, - }); - } - previousMainProcessMemoryInfo = processMemoryInfo; - if (shouldReport) { - mainProcessUsingHighMemory = !mainProcessUsingHighMemory; - } -} - -let previousRendererProcessMemoryInfo: Electron.ProcessMemoryInfo = { - private: 0, - shared: 0, - residentSet: 0, -}; - -let rendererUsingHighMemory = false; - -async function logSpikeRendererMemoryUsage() { - const processMemoryInfo = await process.getProcessMemoryInfo(); - const currentMemoryUsage = Math.max( - processMemoryInfo.residentSet ?? 0, - processMemoryInfo.private, - ); - - const previousMemoryUsage = Math.max( - previousRendererProcessMemoryInfo.private, - previousRendererProcessMemoryInfo.residentSet ?? 0, - ); - const isSpiking = - currentMemoryUsage - previousMemoryUsage >= - RENDERER_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE; - - const isHighMemoryUsage = - currentMemoryUsage >= HIGH_RENDERER_MEMORY_USAGE_THRESHOLD_IN_KILOBYTES; - - const shouldReport = - (isHighMemoryUsage && !rendererUsingHighMemory) || - (!isHighMemoryUsage && rendererUsingHighMemory); - - if (isSpiking || shouldReport) { - const normalizedCurrentProcessMemoryInfo = - await getNormalizedProcessMemoryInfo(processMemoryInfo); - const normalizedPreviousProcessMemoryInfo = - await getNormalizedProcessMemoryInfo( - previousRendererProcessMemoryInfo, - ); - const cpuUsage = process.getCPUUsage(); - const heapStatistics = getNormalizedHeapStatistics( - process.getHeapStatistics(), - ); - - ElectronLog.log("reporting renderer memory usage spike", { - currentProcessMemoryInfo: normalizedCurrentProcessMemoryInfo, - previousProcessMemoryInfo: normalizedPreviousProcessMemoryInfo, - heapStatistics, - cpuUsage, - }); - } - previousRendererProcessMemoryInfo = processMemoryInfo; - if (shouldReport) { - rendererUsingHighMemory = !rendererUsingHighMemory; - } -} - -async function logRendererProcessStats() { - const blinkMemoryInfo = getNormalizedBlinkMemoryInfo(); - const heapStatistics = getNormalizedHeapStatistics( - process.getHeapStatistics(), - ); - const webFrameResourceUsage = getNormalizedWebFrameResourceUsage(); - const processMemoryInfo = await getNormalizedProcessMemoryInfo( - await process.getProcessMemoryInfo(), - ); - ElectronLog.log("renderer process stats", { - blinkMemoryInfo, - heapStatistics, - processMemoryInfo, - webFrameResourceUsage, - }); -} - -export function setupMainProcessStatsLogger() { - setInterval( - logSpikeMainMemoryUsage, - SPIKE_DETECTION_INTERVAL_IN_MICROSECONDS, - ); - setInterval(logMainProcessStats, LOGGING_INTERVAL_IN_MICROSECONDS); -} - -export function setupRendererProcessStatsLogger() { - setInterval( - logSpikeRendererMemoryUsage, - SPIKE_DETECTION_INTERVAL_IN_MICROSECONDS, - ); - setInterval(logRendererProcessStats, LOGGING_INTERVAL_IN_MICROSECONDS); -} - -export async function logRendererProcessMemoryUsage(message: string) { - const processMemoryInfo = await process.getProcessMemoryInfo(); - const processMemory = Math.max( - processMemoryInfo.private, - processMemoryInfo.residentSet ?? 0, - ); - ElectronLog.log( - "renderer ProcessMemory", - message, - convertBytesToHumanReadable(processMemory * 1024), - ); -} - -const getNormalizedProcessMemoryInfo = async ( - processMemoryInfo: Electron.ProcessMemoryInfo, -) => { - return { - residentSet: convertBytesToHumanReadable( - processMemoryInfo.residentSet * 1024, - ), - private: convertBytesToHumanReadable(processMemoryInfo.private * 1024), - shared: convertBytesToHumanReadable(processMemoryInfo.shared * 1024), - }; -}; - -const getNormalizedBlinkMemoryInfo = () => { - const blinkMemoryInfo = process.getBlinkMemoryInfo(); - return { - allocated: convertBytesToHumanReadable( - blinkMemoryInfo.allocated * 1024, - ), - total: convertBytesToHumanReadable(blinkMemoryInfo.total * 1024), - }; -}; - -const getNormalizedHeapStatistics = ( - heapStatistics: Electron.HeapStatistics, -) => { - return { - totalHeapSize: convertBytesToHumanReadable( - heapStatistics.totalHeapSize * 1024, - ), - totalHeapSizeExecutable: convertBytesToHumanReadable( - heapStatistics.totalHeapSizeExecutable * 1024, - ), - totalPhysicalSize: convertBytesToHumanReadable( - heapStatistics.totalPhysicalSize * 1024, - ), - totalAvailableSize: convertBytesToHumanReadable( - heapStatistics.totalAvailableSize * 1024, - ), - usedHeapSize: convertBytesToHumanReadable( - heapStatistics.usedHeapSize * 1024, - ), - - heapSizeLimit: convertBytesToHumanReadable( - heapStatistics.heapSizeLimit * 1024, - ), - mallocedMemory: convertBytesToHumanReadable( - heapStatistics.mallocedMemory * 1024, - ), - peakMallocedMemory: convertBytesToHumanReadable( - heapStatistics.peakMallocedMemory * 1024, - ), - doesZapGarbage: heapStatistics.doesZapGarbage, - }; -}; - -const getNormalizedWebFrameResourceUsage = () => { - const webFrameResourceUsage = webFrame.getResourceUsage(); - return { - images: { - count: webFrameResourceUsage.images.count, - size: convertBytesToHumanReadable( - webFrameResourceUsage.images.size, - ), - liveSize: convertBytesToHumanReadable( - webFrameResourceUsage.images.liveSize, - ), - }, - scripts: { - count: webFrameResourceUsage.scripts.count, - size: convertBytesToHumanReadable( - webFrameResourceUsage.scripts.size, - ), - liveSize: convertBytesToHumanReadable( - webFrameResourceUsage.scripts.liveSize, - ), - }, - cssStyleSheets: { - count: webFrameResourceUsage.cssStyleSheets.count, - size: convertBytesToHumanReadable( - webFrameResourceUsage.cssStyleSheets.size, - ), - liveSize: convertBytesToHumanReadable( - webFrameResourceUsage.cssStyleSheets.liveSize, - ), - }, - xslStyleSheets: { - count: webFrameResourceUsage.xslStyleSheets.count, - size: convertBytesToHumanReadable( - webFrameResourceUsage.xslStyleSheets.size, - ), - liveSize: convertBytesToHumanReadable( - webFrameResourceUsage.xslStyleSheets.liveSize, - ), - }, - fonts: { - count: webFrameResourceUsage.fonts.count, - size: convertBytesToHumanReadable(webFrameResourceUsage.fonts.size), - liveSize: convertBytesToHumanReadable( - webFrameResourceUsage.fonts.liveSize, - ), - }, - other: { - count: webFrameResourceUsage.other.count, - size: convertBytesToHumanReadable(webFrameResourceUsage.other.size), - liveSize: convertBytesToHumanReadable( - webFrameResourceUsage.other.liveSize, - ), - }, - }; -}; diff --git a/web/packages/shared/electron/types.ts b/web/packages/shared/electron/types.ts index 34b8ee591..0273e7c65 100644 --- a/web/packages/shared/electron/types.ts +++ b/web/packages/shared/electron/types.ts @@ -93,7 +93,6 @@ export interface ElectronAPIsType { maxDimension: number, maxSize: number, ) => Promise; - logRendererProcessMemoryUsage: (message: string) => Promise; registerForegroundEventListener: (onForeground: () => void) => void; openDirectory: (dirPath: string) => Promise; moveFile: (oldPath: string, newPath: string) => Promise;