|
@@ -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,
|
|
|
- ),
|
|
|
- },
|
|
|
- };
|
|
|
-};
|