From bc4062b950c895638878ab80155575c04b028abd Mon Sep 17 00:00:00 2001 From: Chirag Chandrashekhar Date: Tue, 2 Dec 2025 14:40:20 +0530 Subject: [PATCH] Bugfix/inaccurate process metrics (#6257) --- .../Devtools/Performance/StyledWrapper.js | 231 ++++++++++++++++++ .../components/Devtools/Performance/index.js | 178 +++++++++++--- .../bruno-electron/src/app/system-monitor.js | 17 +- 3 files changed, 385 insertions(+), 41 deletions(-) diff --git a/packages/bruno-app/src/components/Devtools/Performance/StyledWrapper.js b/packages/bruno-app/src/components/Devtools/Performance/StyledWrapper.js index ea6c00caf..96060e14d 100644 --- a/packages/bruno-app/src/components/Devtools/Performance/StyledWrapper.js +++ b/packages/bruno-app/src/components/Devtools/Performance/StyledWrapper.js @@ -115,6 +115,237 @@ const StyledWrapper = styled.div` color: ${(props) => props.theme.console.buttonColor}; } } + + .performance-header { + display: flex; + align-items: center; + border-bottom: 1px solid ${(props) => props.theme.console.border}; + padding: 12px 16px; + background: ${(props) => props.theme.console.headerBg}; + } + + .performance-selector-wrapper { + display: flex; + align-items: center; + gap: 12px; + } + + .performance-selector-label { + font-size: 13px; + font-weight: 500; + color: ${(props) => props.theme.console.titleColor}; + user-select: none; + } + + .performance-selector { + position: relative; + display: inline-flex; + align-items: center; + } + + .performance-select { + appearance: none; + background: ${(props) => props.theme.console.bg}; + border: 1px solid ${(props) => props.theme.console.border}; + border-radius: 4px; + padding: 6px 32px 6px 12px; + font-size: 13px; + font-weight: 500; + color: ${(props) => props.theme.console.titleColor}; + cursor: pointer; + outline: none; + transition: all 0.2s ease; + min-width: 250px; + max-width: 400px; + + &:hover { + border-color: ${(props) => props.theme.colors.primary}; + } + + &:focus { + border-color: ${(props) => props.theme.colors.primary}; + box-shadow: 0 0 0 2px ${(props) => props.theme.colors.primary}33; + } + + option { + background: ${(props) => props.theme.console.bg}; + color: ${(props) => props.theme.console.titleColor}; + padding: 8px; + } + } + + .performance-select-icon { + position: absolute; + right: 10px; + pointer-events: none; + color: ${(props) => props.theme.console.buttonColor}; + } + + .processes-table-container { + display: flex; + flex-direction: column; + height: 100%; + min-height: 0; + + h2 { + margin: 0 0 16px 0; + font-size: 14px; + font-weight: 600; + color: ${(props) => props.theme.console.titleColor}; + flex-shrink: 0; + } + } + + .no-processes { + padding: 32px; + text-align: center; + color: ${(props) => props.theme.console.buttonColor}; + font-size: 13px; + } + + .processes-table-wrapper { + flex: 1; + min-height: 0; + overflow: auto; + } + + .processes-table { + width: 100%; + border-collapse: collapse; + background: ${(props) => props.theme.console.headerBg}; + border: 1px solid ${(props) => props.theme.console.border}; + border-radius: 4px; + overflow: hidden; + + thead { + background: ${(props) => props.theme.console.bg}; + border-bottom: 1px solid ${(props) => props.theme.console.border}; + + th { + padding: 10px 12px; + text-align: left; + font-size: 12px; + font-weight: 600; + color: ${(props) => props.theme.console.titleColor}; + text-transform: uppercase; + letter-spacing: 0.5px; + + &:first-child { + padding-left: 16px; + } + + &:last-child { + padding-right: 16px; + } + } + } + + tbody { + tr { + border-bottom: 1px solid ${(props) => props.theme.console.border}; + transition: background 0.15s ease; + + &:hover { + background: ${(props) => props.theme.console.bg}; + } + + &:last-child { + border-bottom: none; + } + } + + td { + padding: 10px 12px; + font-size: 13px; + color: ${(props) => props.theme.console.textColor}; + + &:first-child { + padding-left: 16px; + } + + &:last-child { + padding-right: 16px; + } + } + } + + .pid-cell { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 12px; + color: ${(props) => props.theme.console.buttonColor}; + } + + .type-cell { + .process-type-badge { + display: inline-block; + padding: 2px 8px; + border-radius: 3px; + font-size: 11px; + font-weight: 500; + text-transform: lowercase; + background: ${(props) => props.theme.console.border}; + color: ${(props) => props.theme.console.buttonColor}; + + &.Browser { + background: rgba(59, 130, 246, 0.2); + color: #3b82f6; + } + + &.Renderer { + background: rgba(16, 185, 129, 0.2); + color: #10b981; + } + + &.Utility { + background: rgba(139, 92, 246, 0.2); + color: #8b5cf6; + } + + &.Zygote { + background: rgba(245, 158, 11, 0.2); + color: #f59e0b; + } + + &.Sandbox { + background: rgba(239, 68, 68, 0.2); + color: #ef4444; + } + } + } + + .title-cell { + max-width: 300px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .cpu-cell { + font-weight: 500; + + .high-cpu { + color: #ef4444; + } + + .medium-cpu { + color: #f59e0b; + } + + .low-cpu { + color: ${(props) => props.theme.console.buttonColor}; + } + } + + .memory-cell { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 12px; + } + + .created-cell { + font-size: 12px; + color: ${(props) => props.theme.console.buttonColor}; + } + } `; export default StyledWrapper; diff --git a/packages/bruno-app/src/components/Devtools/Performance/index.js b/packages/bruno-app/src/components/Devtools/Performance/index.js index 91ec547a2..2ceabb764 100644 --- a/packages/bruno-app/src/components/Devtools/Performance/index.js +++ b/packages/bruno-app/src/components/Devtools/Performance/index.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState, useMemo } from 'react'; import { useSelector } from 'react-redux'; import StyledWrapper from './StyledWrapper'; import { @@ -6,11 +6,22 @@ import { IconDatabase, IconClock, IconServer, - IconChartLine + IconChevronDown } from '@tabler/icons'; +const getProcessOptions = (processes) => { + return [ + { value: 'cumulative', label: 'Cumulative (All Processes)' }, + ...(processes ?? []).map((process) => ({ + value: String(process.pid), + label: `PID ${process.pid}${process.title ? ` - ${process.title}` : ''}${process.type ? ` (${process.type})` : ''}` + })) + ]; +}; + const Performance = () => { const { systemResources } = useSelector((state) => state.performance); + const [selectedPid, setSelectedPid] = useState('cumulative'); useEffect(() => { const { ipcRenderer } = window; @@ -82,47 +93,140 @@ const Performance = () => { ); + // Get process options for dropdown + const processOptions = useMemo(() => getProcessOptions(systemResources.processes), [systemResources.processes]); + + // Get selected process data + const selectedProcess = useMemo(() => { + if (selectedPid === 'cumulative') { + return null; // Show cumulative view + } + const processes = systemResources.processes || []; + return processes.find((p) => String(p.pid) === selectedPid) || null; + }, [selectedPid, systemResources.processes]); + + // Reset to cumulative if selected PID no longer exists + useEffect(() => { + if (selectedPid !== 'cumulative' && !selectedProcess) { + setSelectedPid('cumulative'); + } + }, [selectedPid, selectedProcess]); + + const renderCumulativeView = () => ( +
+

System Resources

+
+ 80 ? 'danger' : systemResources.cpu > 60 ? 'warning' : 'success'} + /> + + (500 * 1024 * 1024) ? 'danger' : 'default'} + /> + + + + +
+
+ ); + + const renderProcessView = (process) => { + if (!process) return null; + + // Calculate uptime for individual process + const processUptime = process.creationTime + ? (new Date() - new Date(process.creationTime)) / 1000 + : 0; + + return ( +
+

System Resources

+
+ 80 ? 'danger' : process.cpu > 60 ? 'warning' : 'success'} + /> + + (500 * 1024 * 1024) ? 'danger' : 'default'} + /> + + + + +
+
+ ); + }; + return (
-
-
-

System Resources

-
- 80 ? 'danger' : systemResources.cpu > 60 ? 'warning' : 'success'} - /> - - 500 * 1024 * 1024 ? 'danger' : 'default'} - /> - - - - +
+
+ +
+ +
+
+ {selectedPid === 'cumulative' ? renderCumulativeView() : renderProcessView(selectedProcess)} +
); diff --git a/packages/bruno-electron/src/app/system-monitor.js b/packages/bruno-electron/src/app/system-monitor.js index c161638ce..a66e04078 100644 --- a/packages/bruno-electron/src/app/system-monitor.js +++ b/packages/bruno-electron/src/app/system-monitor.js @@ -65,17 +65,25 @@ class SystemMonitor { for (const metric of metrics) { totalCPU += metric.cpu.percentCPUUsage; - totalMemory += metric.memory.workingSetSize; + totalMemory += metric.memory.workingSetSize * 1024; } const uptime = (currentTime - this.startTime) / 1000; - + var processes = metrics.map((metric) => ({ + pid: metric.pid, + title: metric.title, + memory: metric.memory.workingSetSize * 1024, + cpu: metric.cpu.percentCPUUsage, + type: metric.type || 'unknown', + creationTime: metric.creationTime + })); const systemResources = { cpu: totalCPU, memory: totalMemory, pid: process.pid, uptime: uptime, - timestamp: currentTime.toISOString() + timestamp: currentTime.toISOString(), + processes: processes }; if (win && !win.isDestroyed()) { @@ -95,7 +103,8 @@ class SystemMonitor { memory: memory.rss, pid: process.pid, uptime: uptime, - timestamp: currentTime.toISOString() + timestamp: currentTime.toISOString(), + processes: [] }; if (win && !win.isDestroyed()) {