Compare commits

..

2 Commits

Author SHA1 Message Date
henrygd
9d87102e0c working intel gpu stats for one gpu 2025-09-22 16:13:04 -04:00
henrygd
6a406e5206 intel_gpu_top testing 2025-09-22 14:00:01 -04:00
3 changed files with 50 additions and 54 deletions

View File

@@ -252,7 +252,7 @@ func (gm *GPUManager) GetCurrentData() map[string]system.GPUData {
gpuAvg.Power = twoDecimals(gpu.Power / count) gpuAvg.Power = twoDecimals(gpu.Power / count)
// intel gpu stats doesn't provide usage, memory used, or memory total // intel gpu stats doesn't provide usage, memory used, or memory total
if gpu.Engines != nil { if gm.intelGpuStats {
maxEngineUsage := 0.0 maxEngineUsage := 0.0
for name, engine := range gpu.Engines { for name, engine := range gpu.Engines {
gpuAvg.Engines[name] = twoDecimals(engine / count) gpuAvg.Engines[name] = twoDecimals(engine / count)

View File

@@ -379,12 +379,12 @@ func TestGetCurrentData(t *testing.T) {
assert.InDelta(t, 60.0, result["1"].Power, 0.01) assert.InDelta(t, 60.0, result["1"].Power, 0.01)
// Verify that accumulators in the original map are reset // Verify that accumulators in the original map are reset
assert.EqualValues(t, float64(1), gm.GpuDataMap["0"].Count, "GPU 0 Count should be reset") assert.Equal(t, float64(0), gm.GpuDataMap["0"].Count, "GPU 0 Count should be reset")
assert.EqualValues(t, float64(50.0), gm.GpuDataMap["0"].Usage, "GPU 0 Usage should be reset") assert.Equal(t, float64(0), gm.GpuDataMap["0"].Usage, "GPU 0 Usage should be reset")
assert.Equal(t, float64(100.0), gm.GpuDataMap["0"].Power, "GPU 0 Power should be reset") assert.Equal(t, float64(0), gm.GpuDataMap["0"].Power, "GPU 0 Power should be reset")
assert.Equal(t, float64(1), gm.GpuDataMap["1"].Count, "GPU 1 Count should be reset") assert.Equal(t, float64(0), gm.GpuDataMap["1"].Count, "GPU 1 Count should be reset")
assert.Equal(t, float64(30), gm.GpuDataMap["1"].Usage, "GPU 1 Usage should be reset") assert.Equal(t, float64(0), gm.GpuDataMap["1"].Usage, "GPU 1 Usage should be reset")
assert.Equal(t, float64(60), gm.GpuDataMap["1"].Power, "GPU 1 Power should be reset") assert.Equal(t, float64(0), gm.GpuDataMap["1"].Power, "GPU 1 Power should be reset")
}) })
t.Run("handles zero count without panicking", func(t *testing.T) { t.Run("handles zero count without panicking", func(t *testing.T) {
@@ -409,7 +409,7 @@ func TestGetCurrentData(t *testing.T) {
assert.Equal(t, 0.0, result["0"].Power) assert.Equal(t, 0.0, result["0"].Power)
// Verify reset count // Verify reset count
assert.EqualValues(t, 1, gm.GpuDataMap["0"].Count) assert.Equal(t, float64(0), gm.GpuDataMap["0"].Count)
}) })
} }
@@ -779,15 +779,15 @@ func TestAccumulation(t *testing.T) {
} }
// Verify that accumulators in the original map are reset // Verify that accumulators in the original map are reset
for id, expected := range tt.expectedValues { for id := range tt.expectedValues {
gpu, exists := gm.GpuDataMap[id] gpu, exists := gm.GpuDataMap[id]
assert.True(t, exists, "GPU with ID %s should still exist after GetCurrentData", id) assert.True(t, exists, "GPU with ID %s should still exist after GetCurrentData", id)
if !exists { if !exists {
continue continue
} }
assert.EqualValues(t, 1, gpu.Count, "Count should be reset for GPU ID %s", id) assert.Equal(t, float64(0), gpu.Count, "Count should be reset for GPU ID %s", id)
assert.EqualValues(t, expected.avgUsage, gpu.Usage, "Usage should be reset for GPU ID %s", id) assert.Equal(t, float64(0), gpu.Usage, "Usage should be reset for GPU ID %s", id)
assert.EqualValues(t, expected.avgPower, gpu.Power, "Power should be reset for GPU ID %s", id) assert.Equal(t, float64(0), gpu.Power, "Power should be reset for GPU ID %s", id)
} }
}) })
} }

View File

@@ -760,6 +760,13 @@ export default memo(function SystemDetail({ name }: { name: string }) {
/> />
</ChartCard> </ChartCard>
)} )}
</div>
{/* Non-power GPU charts */}
{hasGpuData && (
<div className="grid xl:grid-cols-2 gap-4">
{/* GPU power draw chart */} {/* GPU power draw chart */}
{hasGpuPowerData && ( {hasGpuPowerData && (
<ChartCard <ChartCard
@@ -771,14 +778,8 @@ export default memo(function SystemDetail({ name }: { name: string }) {
<GpuPowerChart chartData={chartData} /> <GpuPowerChart chartData={chartData} />
</ChartCard> </ChartCard>
)} )}
</div>
{/* Non-power GPU charts */}
{hasGpuData && (
<div className="grid xl:grid-cols-2 gap-4">
{hasGpuEnginesData && ( {hasGpuEnginesData && (
<ChartCard <ChartCard
className="!col-span-1"
empty={dataEmpty} empty={dataEmpty}
grid={grid} grid={grid}
title={t`GPU Engines`} title={t`GPU Engines`}
@@ -813,35 +814,36 @@ export default memo(function SystemDetail({ name }: { name: string }) {
</ChartCard> </ChartCard>
{(gpu.mt ?? 0) > 0 && ( {(gpu.mt ?? 0) > 0 && (
<ChartCard <ChartCard
empty={dataEmpty} empty={dataEmpty}
grid={grid} grid={grid}
title={`${gpu.n} VRAM`} title={`${gpu.n} VRAM`}
description={t`Precise utilization at the recorded time`} description={t`Precise utilization at the recorded time`}
> >
<AreaChartDefault <AreaChartDefault
chartData={chartData} chartData={chartData}
dataPoints={[ dataPoints={[
{ {
label: t`Usage`, label: t`Usage`,
dataKey: ({ stats }) => stats?.g?.[id]?.mu ?? 0, dataKey: ({ stats }) => stats?.g?.[id]?.mu ?? 0,
color: 2, color: 2,
opacity: 0.25, opacity: 0.25,
}, },
]} ]}
max={gpu.mt} max={gpu.mt}
tickFormatter={(val) => { tickFormatter={(val) => {
const { value, unit } = formatBytes(val, false, Unit.Bytes, true) const { value, unit } = formatBytes(val, false, Unit.Bytes, true)
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}` return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
}} }}
contentFormatter={({ value }) => { contentFormatter={({ value }) => {
const { value: convertedValue, unit } = formatBytes(value, false, Unit.Bytes, true) const { value: convertedValue, unit } = formatBytes(value, false, Unit.Bytes, true)
return `${decimalString(convertedValue)} ${unit}` return `${decimalString(convertedValue)} ${unit}`
}} }}
/> />
</ChartCard> </ChartCard>
)} )}
</div> </div>
) )
})} })}
</div> </div>
@@ -919,18 +921,12 @@ function GpuEnginesChart({ chartData }: { chartData: ChartData }) {
dataPoints.push({ dataPoints.push({
label: engine, label: engine,
dataKey: ({ stats }: SystemStatsRecord) => stats?.g?.[0]?.e?.[engine] ?? 0, dataKey: ({ stats }: SystemStatsRecord) => stats?.g?.[0]?.e?.[engine] ?? 0,
color: `hsl(${140 + (((engines.indexOf(engine) * 360) / engines.length) % 360)}, 65%, 52%)`, color: `hsl(${140 + ((engines.indexOf(engine) * 360) / engines.length) % 360}, 65%, 52%)`,
opacity: 0.35, opacity: 0.35,
}) })
} }
return ( return (
<LineChartDefault <LineChartDefault legend={true} chartData={chartData} dataPoints={dataPoints} tickFormatter={(val) => `${toFixedFloat(val, 2)}%`} contentFormatter={({ value }) => `${decimalString(value)}%`} />
legend={true}
chartData={chartData}
dataPoints={dataPoints}
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
contentFormatter={({ value }) => `${decimalString(value)}%`}
/>
) )
} }