Skip to content

fix: Add Apple M5 Pro/Max Super core (S-CPU) and new IOReport channel support#168

Merged
inureyes merged 4 commits into
mainfrom
fix/issue-167-m5-super-core-support
Apr 10, 2026
Merged

fix: Add Apple M5 Pro/Max Super core (S-CPU) and new IOReport channel support#168
inureyes merged 4 commits into
mainfrom
fix/issue-167-m5-super-core-support

Conversation

@inureyes

Copy link
Copy Markdown
Member

Summary

  • Add CoreType::Super variant and s_core_* fields to AppleSiliconCpuInfo for the M5 Pro/Max 3-tier CPU architecture (Super + Performance, no Efficiency cores)
  • Dynamically detect core type mapping by reading hw.perflevelN.name via sysctl instead of hardcoding perflevel0=P, perflevel1=E
  • Handle MCPU0* IOReport channels as Super cores and MCPU1* as Performance cluster, fixing the issue where only 6 of 18 cores were monitored on M5 Max
  • Update TUI to display "S-CPU"/"P-CPU" gauges for M5 chips and "P-CPU"/"E-CPU" for M1-M4, with corresponding per-core labels (S1, S2, ... P1, P2, ...)
  • Thread s_cluster metrics through NativeMetricsData, IOReportMetrics, and Prometheus API export
  • Full backward compatibility with M1/M2/M3/M4 chips preserved

Closes #167

Test plan

  • All 311 unit tests pass
  • cargo clippy clean (no warnings)
  • cargo fmt --check clean
  • Verify on M5 Max: all 18 cores (6S+12P) are monitored
  • Verify on M5 Max: TUI shows "S-CPU" and "P-CPU" gauge bars
  • Verify on M5 Max: per-core view shows S1-S6, P1-P12
  • Verify on M1-M4: existing P-CPU/E-CPU display is unchanged
  • Verify API mode exports all_smi_cpu_s_core_count and all_smi_cpu_s_core_utilization metrics on M5

…MCPU channel support

Add support for the Apple M5 Pro/Max 3-tier CPU architecture (Super + Performance,
no Efficiency cores). Previously only 6 of 18 cores were monitored on M5 Max because
the code only matched E*/ECPU and P*/PCPU IOReport channels, missing all MCPU channels.

Changes:
- Add CoreType::Super variant and s_core fields to AppleSiliconCpuInfo
- Read hw.perflevelN.name via sysctl to dynamically detect Super vs Performance mapping
- Handle MCPU0* channels as Super cores and MCPU1* as Performance cluster in IOReport
- Thread s_cluster metrics through NativeMetricsData and IOReportMetrics
- Display S-CPU/P-CPU gauges for M5, P-CPU/E-CPU for M1-M4 in TUI
- Export s_core metrics in Prometheus API format
- Full backward compatibility with M1/M2/M3/M4 chips preserved

Closes #167
@inureyes inureyes added type:bug Something isn't working priority:high High priority issue device:apple-silicon Apple Silicon related status:review Under review labels Apr 10, 2026
Add missing all_smi_cpu_s_cluster_frequency_mhz Prometheus metric for
M5 Pro/Max Super cores, and add dedicated s_idx counter in activity
panel per-core view to avoid sharing the Standard core counter.
@inureyes

Copy link
Copy Markdown
Member Author

Implementation Review Summary

Intent

Add Apple M5 Pro/Max Super core (S-CPU) support with IOReport MCPU channel handling, dynamic sysctl perflevel detection, and TUI/API integration.

Findings Addressed

  • S-cluster frequency metric (all_smi_cpu_s_cluster_frequency_mhz) was missing from Prometheus API export while P-cluster and E-cluster frequencies were exported (MEDIUM)
  • S-core index counter (s_idx) was missing in activity_panel.rs:draw_individual_cores — S-cores fell into the Standard core counter c_idx (LOW)

Remaining Items

  • None

Verification

  • All stated requirements implemented
  • No placeholder/mock code remaining
  • Integrated into project code flow
  • Project conventions followed
  • Existing modules reused where applicable
  • No unintended structural changes
  • Tests pass (309 lib + 369 bin + doctests, clippy clean, fmt clean)

Review Details

CoreType::Super enum — properly added to both device::types::CoreType (public API) and macos_native::metrics::CoreType (internal). Used correctly in all match arms across cpu_renderer.rs, activity_panel.rs, cpu.rs (metrics export), and metrics_parser.rs.

IOReport MCPU channel parsingioreport.rs:process_cpu_channel correctly maps MCPU0* to S-cluster and MCPU1* to P-cluster, while preserving ECPU/PCPU handling for M1-M4 backward compatibility.

sysctl perflevel detectioncpu_macos.rs:parse_apple_silicon_hardware_info_fast reads hw.perflevel0.name dynamically via get_perflevel_name(0) and branches on "Super" to distinguish M5 from M1-M4. Core counts correctly map perflevel0/1 to S/P (M5) or P/E (legacy).

TUI displaycpu_renderer.rs shows "S-CPU"/"P-CPU" gauges for M5 and "P-CPU"/"E-CPU" for M1-M4. Per-core labels are S1-Sn/P1-Pn. activity_panel.rs follows the same pattern for the collapsed cluster view.

Prometheus exports_core_count, s_core_utilization, s_cluster_frequency_mhz (added in review fix), and per-core core_type="S" metrics are all exported. Metrics parser handles cpu_s_core_count, cpu_s_core_utilization, and core_type="S" for remote monitoring.

Backward compatibility — All S-core fields default to 0/None when s_core_count == 0. M1-M4 code paths are unchanged. All test fixtures updated with new struct fields.

…size

The original code acquired cached_s_core_count mutex twice in the same
if-expression. Rust drops temporaries at statement end, not at &&, so
when the first condition evaluated to true the second .lock() would
deadlock. Consolidate into a single lock acquisition with matches!.
@inureyes

Copy link
Copy Markdown
Member Author

Security & Performance Review

Fixed

[MEDIUM] Mutex deadlock in get_e_core_l2_cache_size (src/device/cpu_macos.rs:712-718)

The original code acquired cached_s_core_count mutex twice in the same if-expression:

if *self.cached_s_core_count.lock().unwrap() != Some(0)
    && self.cached_s_core_count.lock().unwrap().is_some()

Rust drops temporaries at statement end, not at && boundaries. When the first condition evaluated to true (value is Some(n) where n > 0, or None), the second .lock() would attempt to acquire the same non-reentrant std::sync::Mutex while the first MutexGuard was still alive, causing a deadlock. On M5 Pro/Max where s_core_count is Some(6), this function would hang on every call.

Fixed by consolidating into a single lock acquisition: let s_count = self.cached_s_core_count.lock().unwrap(); if matches!(*s_count, Some(n) if n > 0).

Commit: ed56f3e


No issues found (reviewed and passed)

  • Command injection (sysctl calls): All Command::new("sysctl") invocations use hardcoded string arguments or format!("hw.perflevel{level}.name") where level is a u32 -- no user-controlled input reaches command arguments. Safe.

  • IOReport channel parsing: The MCPU0/MCPU1 prefix matching in process_cpu_channel is correctly ordered (most specific prefixes first). The starts_with("MCPU0") check correctly captures both the cluster summary channel MCPU0 and individual core channels MCPU00-MCPU05. No risk of misclassification between Super and Performance clusters.

  • Data validation: perflevel0_count and perflevel1_count use .parse().unwrap_or(0) with proper fallback. The validation at line 474 (if (s_core_count + p_core_count) == 0) correctly handles the M5 case where e_core_count is legitimately zero.

  • Allocations in hot paths: The IOReport processing in process_cpu_channel only pushes to pre-existing Vecs -- no new allocations per iteration. The from_sample method allocates s_cluster_freqs once per sample cycle (not per-frame), which is acceptable. The clone() calls on s_cluster_data in average_samples operate on small vecs (6-12 entries) and run at the sampling interval (every few seconds), not per-frame.

  • Prometheus metrics export: New all_smi_cpu_s_core_* metrics are conditionally emitted only when s_core_count > 0, avoiding metric churn on M1-M4 systems. The CoreType::Super => "S" mapping in per-core export is correct.

  • Backward compatibility: All new fields default to 0/None/empty, and all rendering paths branch on s_core_count > 0 before displaying Super core UI. M1-M4 behavior is preserved through the else branches.

Add three test cases to metrics_parser covering the new S-core fields
introduced for Apple M5 Pro/Max support:
- test_parse_m5_super_core_metrics: verifies s_core_count and
  s_core_utilization are parsed correctly from Prometheus metrics
- test_parse_m5_per_core_super_type: verifies CoreType::Super is
  assigned when core_type="S" in per-core utilization metrics
- test_m5_backward_compat_m1_m4_no_super_cores: verifies M1-M4 chips
  without S-core metrics default s_core_count and s_core_utilization
  to zero
@inureyes

Copy link
Copy Markdown
Member Author

PR Finalization Complete

Summary

  • Tests: Added 3 new unit tests in src/network/metrics_parser.rs covering the new M5 Super core (S-CPU) metrics:
    • test_parse_m5_super_core_metrics — verifies cpu_s_core_count and cpu_s_core_utilization Prometheus metrics are parsed into AppleSiliconCpuInfo.s_core_count / s_core_utilization correctly for an M5 Max (6S+10P layout)
    • test_parse_m5_per_core_super_type — verifies core_type="S" in per-core metrics maps to CoreType::Super
    • test_m5_backward_compat_m1_m4_no_super_cores — verifies M1–M4 chips without S-core metrics default s_core_count and s_core_utilization to zero (backward compatibility)
  • Documentation: No doc changes required; all new API metrics are self-describing via Prometheus # HELP lines
  • Lint/Format: cargo fmt --check and cargo clippy -- -D warnings both clean

Total test count: 311 → 312 (all passing).

@inureyes inureyes added status:done Completed and removed status:review Under review labels Apr 10, 2026
@inureyes inureyes merged commit f895627 into main Apr 10, 2026
2 checks passed
@inureyes inureyes deleted the fix/issue-167-m5-super-core-support branch April 10, 2026 06:27
@inureyes inureyes self-assigned this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

device:apple-silicon Apple Silicon related priority:high High priority issue status:done Completed type:bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: Add Apple M5 Pro/Max Super core (S-CPU) and new IOReport channel support

1 participant