Skip to content

fix: normalize CPU % against container cpuLimit and add soft ceiling to BarChart#4464

Merged
amir20 merged 2 commits intomasterfrom
fix/cpu-normalization-soft-ceiling
Feb 23, 2026
Merged

fix: normalize CPU % against container cpuLimit and add soft ceiling to BarChart#4464
amir20 merged 2 commits intomasterfrom
fix/cpu-normalization-soft-ceiling

Conversation

@amir20
Copy link
Copy Markdown
Owner

@amir20 amir20 commented Feb 20, 2026

Summary

  • CPU normalization fix: When a container has a CPU limit (--cpus=N), the frontend was dividing raw CPU% by 1 instead of N. A --cpus=2 container using 1.5 cores now correctly shows 75% instead of being capped at 100%. Fixed in ContainerStatCell, HostCard, and MultiContainerStat.
  • BarChart soft ceiling: Added maxCeiling prop (default 10) so bar scaling uses max(dataMax * 1.2, maxCeiling) instead of just max(data). Idle containers stay visually flat instead of filling the full chart height. Spikes are visible relative to recent history.

Test plan

  • Run docker run -d --cpus=2 alpine sh -c "for i in 1 2 3 4; do while true; do :; done & done; wait" and verify Dozzle shows ~100% (not capped at 100% from raw 200%)
  • Run a container with no CPU limit and verify it still normalizes against host CPU count
  • Verify idle containers show small bars in the container table, not full-height
  • Verify a CPU spike shows meaningful visual variation in the bar chart
  • Run pnpm test and pnpm typecheck — both pass

🤖 Generated with Claude Code

@claude
Copy link
Copy Markdown

claude bot commented Feb 20, 2026

Review

CPU normalization fix - Correct. calculateCPUPercentUnix multiplies by onlineCPUs, so a container with --cpus=2 at full utilization reports 200% raw. The old return 1 divided by 1, overcapping at 100%. Dividing by cpuLimit (2.0) gives correct 100%. Fix is consistent across all three files.

BarChart soft ceiling - Improvement for relative scaling, but one behavioral note:

  • MetricCard in HostCard.vue passes totalCPU which is a sum across all containers (can exceed 100%). Old code capped at 100% height; new code scales relatively — actually better, but data passed as percent to MetricDataPoint semantically implies 0-100 and could exceed that on multi-container hosts. Not a blocker.
  • StatMonitor.vue passes raw y-values (not percentages). Old Math.min(dataPoint, 100)% would incorrectly cap non-percentage data. New relative scaling is strictly better here.
  • The maxCeiling = 10 creates a visual discontinuity around 8.3% (where dataMax * 1.2 overtakes the ceiling). Containers hovering near that threshold will see the scale shift. Minor visual edge case.

No bugs, no security concerns. The CPU normalization is the substantive fix here.

@amir20 amir20 force-pushed the fix/cpu-normalization-soft-ceiling branch from ecf748d to f236f59 Compare February 21, 2026 20:17
@claude
Copy link
Copy Markdown

claude bot commented Feb 23, 2026

CPU fix (return 1return container.cpuLimit): correct in all three locations.

Potential issue - BarChart maxValue spread:
Math.max(0, ...downsampledData.value) — safe given max 300 items after downsampling, no real risk.

Behavior change to flag:
chartData in ContainerStatCell still caps values at 100 via Math.min(stat.cpu / cores, 100). The new maxValue then scales those capped 0-100 values relative to max(dataMax * 1.2, 10). A container pegged at exactly 100% will render at ~83% bar height (100 / 120), not full height. This may be intentional (soft ceiling), but worth verifying it looks right visually.

Minor:

  • statMode added to v-memo dependency array — required, good catch
  • mdi:poll with scale-x-[-1] rotate-90 is hacky but works
  • .claude/settings.local.json should probably not be committed to the repo at all; consider adding it to .gitignore

No bugs or security issues. The CPU normalization fix is the main correctness improvement.

amir20 and others added 2 commits February 23, 2026 06:37
…to BarChart

CPU normalization was dividing by 1 when a container had a CPU limit set,
instead of dividing by the actual limit. A --cpus=2 container at 150% now
correctly shows 75% instead of being capped at 100%.

BarChart now uses a soft ceiling (max(dataMax * 1.2, 10)) so idle containers
stay visually flat instead of filling the full chart height.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@amir20 amir20 force-pushed the fix/cpu-normalization-soft-ceiling branch from 62c008b to ee4bad5 Compare February 23, 2026 14:37
@claude
Copy link
Copy Markdown

claude bot commented Feb 23, 2026

Follow-up Review

Implementation looks correct end-to-end after reading the full ContainerStatCell.vue:

  • averageValue correctly normalizes CPU via Math.min(movingAverage.cpu / cores, 100) — progress bar max="100" is consistent
  • barClass and progressClass use identical thresholds — good consistency
  • Memory path: container.movingAverage.memory is already a percentage, safe for max="100"

One minor note: chartData still caps at 100 via Math.min(stat.cpu / cores, 100), so BarChart's new relative scaling will render a container pegged at 100% as ~83% bar height (100 / 120). Intentional soft ceiling behavior — just confirm this looks right visually.

Overall: the CPU normalization fix is correct and the mode toggle is well-implemented. No blockers.

@amir20 amir20 merged commit 54469dc into master Feb 23, 2026
12 checks passed
@amir20 amir20 deleted the fix/cpu-normalization-soft-ceiling branch February 23, 2026 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant