fix: implement human-readable memory formatting and ensure hierarchical tree respects profiler filtering
This commit is contained in:
38
src/App.tsx
38
src/App.tsx
@@ -72,6 +72,19 @@ function cn(...inputs: (string | undefined | null | false)[]) {
|
|||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatBytes(bytes: number, decimals = 1) {
|
||||||
|
if (!bytes || bytes === 0) return '0 B';
|
||||||
|
const k = 1024;
|
||||||
|
const dm = decimals < 0 ? 0 : decimals;
|
||||||
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMB(mb: number, decimals = 1) {
|
||||||
|
return formatBytes(mb * 1024 * 1024, decimals);
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [view, setView] = useState<'dashboard' | 'report'>('dashboard');
|
const [view, setView] = useState<'dashboard' | 'report'>('dashboard');
|
||||||
const [stats, setStats] = useState<SystemStats | null>(null);
|
const [stats, setStats] = useState<SystemStats | null>(null);
|
||||||
@@ -420,11 +433,11 @@ function ReportView({ report, onBack }: { report: ProfilingReport, onBack: () =>
|
|||||||
<div className="text-subtext0 text-[11px] font-bold text-right self-center tabular-nums">{proc.peak_cpu.toFixed(1)}%</div>
|
<div className="text-subtext0 text-[11px] font-bold text-right self-center tabular-nums">{proc.peak_cpu.toFixed(1)}%</div>
|
||||||
|
|
||||||
<div className="text-mauve font-black text-sm text-right self-center tabular-nums">
|
<div className="text-mauve font-black text-sm text-right self-center tabular-nums">
|
||||||
{proc.inclusive_avg_memory_mb.toFixed(0)}MB
|
{formatMB(proc.inclusive_avg_memory_mb)}
|
||||||
{proc.children.length > 0 && <span className="block text-[9px] text-overlay1 font-normal">({proc.avg_memory_mb.toFixed(0)}MB self)</span>}
|
{proc.children.length > 0 && <span className="block text-[9px] text-overlay1 font-normal">({formatMB(proc.avg_memory_mb)} self)</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-subtext0 text-[11px] font-bold text-right self-center tabular-nums">{proc.peak_memory_mb.toFixed(0)}MB</div>
|
<div className="text-subtext0 text-[11px] font-bold text-right self-center tabular-nums">{formatMB(proc.peak_memory_mb, 0)}</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-1.5 pl-4 items-center">
|
<div className="flex flex-wrap gap-1.5 pl-4 items-center">
|
||||||
{proc.warnings.length > 0 ? proc.warnings.map((w, idx) => (
|
{proc.warnings.length > 0 ? proc.warnings.map((w, idx) => (
|
||||||
@@ -436,7 +449,10 @@ function ReportView({ report, onBack }: { report: ProfilingReport, onBack: () =>
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{hasChildren && isExpanded && renderTreeRows(proc.children, depth + 1)}
|
{hasChildren && isExpanded && renderTreeRows(
|
||||||
|
proc.children.filter(c => !hideProfiler || !c.is_syspulse),
|
||||||
|
depth + 1
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -521,6 +537,11 @@ function ReportView({ report, onBack }: { report: ProfilingReport, onBack: () =>
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{ background: 'var(--mantle)', border: '1px solid var(--surface1)', borderRadius: '12px', fontSize: '11px', fontWeight: 'bold' }}
|
contentStyle={{ background: 'var(--mantle)', border: '1px solid var(--surface1)', borderRadius: '12px', fontSize: '11px', fontWeight: 'bold' }}
|
||||||
itemStyle={{ color: 'var(--text)' }}
|
itemStyle={{ color: 'var(--text)' }}
|
||||||
|
formatter={(value: number, name: string) => {
|
||||||
|
if (name === 'MEM GB') return [formatBytes(value * 1024 * 1024 * 1024), 'RAM'];
|
||||||
|
if (name === 'CPU %') return [`${value.toFixed(1)}%`, 'CPU'];
|
||||||
|
return [value, name];
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Area type="monotone" dataKey="avg_cpu" name="CPU %" stroke="var(--blue)" fill="url(#cpuReportGradient)" strokeWidth={3} isAnimationActive={true} />
|
<Area type="monotone" dataKey="avg_cpu" name="CPU %" stroke="var(--blue)" fill="url(#cpuReportGradient)" strokeWidth={3} isAnimationActive={true} />
|
||||||
<Area type="monotone" dataKey="memory_gb" name="MEM GB" stroke="var(--mauve)" fill="none" strokeWidth={2} />
|
<Area type="monotone" dataKey="memory_gb" name="MEM GB" stroke="var(--mauve)" fill="none" strokeWidth={2} />
|
||||||
@@ -590,7 +611,7 @@ function ReportView({ report, onBack }: { report: ProfilingReport, onBack: () =>
|
|||||||
</div>
|
</div>
|
||||||
<div className="bg-surface0 p-6 rounded-2xl border border-surface1 shadow-lg">
|
<div className="bg-surface0 p-6 rounded-2xl border border-surface1 shadow-lg">
|
||||||
<div className="text-[10px] font-black text-overlay2 uppercase tracking-widest mb-2">Total Avg RAM</div>
|
<div className="text-[10px] font-black text-overlay2 uppercase tracking-widest mb-2">Total Avg RAM</div>
|
||||||
<div className="text-4xl font-black text-mauve tabular-nums">{selectedProcess.inclusive_avg_memory_mb.toFixed(0)}MB</div>
|
<div className="text-4xl font-black text-mauve tabular-nums">{formatMB(selectedProcess.inclusive_avg_memory_mb)}</div>
|
||||||
<p className="text-xs text-subtext1 mt-2">Combined RSS memory of the subtree.</p>
|
<p className="text-xs text-subtext1 mt-2">Combined RSS memory of the subtree.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -615,6 +636,11 @@ function ReportView({ report, onBack }: { report: ProfilingReport, onBack: () =>
|
|||||||
<YAxis stroke="var(--subtext0)" tick={{fontSize: 9}} />
|
<YAxis stroke="var(--subtext0)" tick={{fontSize: 9}} />
|
||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{ background: 'var(--crust)', border: '1px solid var(--surface1)', borderRadius: '12px' }}
|
contentStyle={{ background: 'var(--crust)', border: '1px solid var(--surface1)', borderRadius: '12px' }}
|
||||||
|
formatter={(value: number, name: string) => {
|
||||||
|
if (name === 'Self Mem (MB)') return [formatMB(value), 'RAM (Self)'];
|
||||||
|
if (name === 'Self CPU %') return [`${value.toFixed(1)}%`, 'CPU (Self)'];
|
||||||
|
return [value, name];
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Area type="monotone" dataKey="cpu_usage" name="Self CPU %" stroke="var(--blue)" fill="url(#procCpuGrad)" strokeWidth={3} />
|
<Area type="monotone" dataKey="cpu_usage" name="Self CPU %" stroke="var(--blue)" fill="url(#procCpuGrad)" strokeWidth={3} />
|
||||||
<Area type="monotone" dataKey="memory_mb" name="Self Mem (MB)" stroke="var(--mauve)" fill="url(#procMemGrad)" strokeWidth={2} />
|
<Area type="monotone" dataKey="memory_mb" name="Self Mem (MB)" stroke="var(--mauve)" fill="url(#procMemGrad)" strokeWidth={2} />
|
||||||
@@ -632,7 +658,7 @@ function ReportView({ report, onBack }: { report: ProfilingReport, onBack: () =>
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between text-sm">
|
<div className="flex justify-between text-sm">
|
||||||
<span className="text-subtext1">Peak Self RAM</span>
|
<span className="text-subtext1">Peak Self RAM</span>
|
||||||
<span className="font-black text-mauve">{selectedProcess.peak_memory_mb.toFixed(0)}MB</span>
|
<span className="font-black text-mauve">{formatMB(selectedProcess.peak_memory_mb)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between text-sm">
|
<div className="flex justify-between text-sm">
|
||||||
<span className="text-subtext1">Child Process Count</span>
|
<span className="text-subtext1">Child Process Count</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user