Files
MacMonitor/ARCHITECTURE.md

210 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MacMonitor: System Architecture & Technical Specifications
This document details the architectural principles, data flow models, memory safety invariants, and subsystem implementation specifics for **MacMonitor**.
---
## 1. Architectural Principles & Constraints
### 1.1 Target Platform Invariants
- **Instruction Set Architecture:** Intel `x86_64`.
- **Target OS:** macOS 14.0 (Sonoma) or newer.
- **Language Stack:**
- **Presentation & ViewModels:** Modern Swift 5.9+ with SwiftUI, `@Observable`, and Swift Charts.
- **Telemetry & Kernel Layer:** Objective-C & C interfaces directly communicating with Mach, IOKit, BSD sysctl, CoreAudio, and DisplayServices.
- **Hybrid Bridge:** Bridging Header (`MacMonitor-Bridging-Header.h`) providing strict separation of concerns and zero overhead between C structures and Swift value types.
---
## 2. Unidirectional Data Flow & Concurrency Model
```mermaid
flowchart TD
subgraph KernelSpace ["Kernel / Driver Space"]
SMC_DEV["AppleSMC Driver"]
MACH_KERN["Mach Kernel Task/Host"]
BSD_SYS["BSD Sysctl & libproc"]
IOK_DRV["IOBlockStorage & IOAccelerator"]
end
subgraph TelemetryLayer ["Low-Level Telemetry Engine (Serial GCD Queue)"]
DISPATCH["dispatch_source_t Timer<br/>(com.i3omb.macmonitor.telemetry · QOS_CLASS_UTILITY)"]
PROV1["MMAppleSMCClient"]
PROV2["MMCPUUsageProvider"]
PROV3["MMMemoryProvider"]
PROV4["MMProcessCollector"]
BATCH["Snapshot Dictionary / DTO Aggregator"]
end
subgraph PresentationLayer ["UI & State Layer (@MainActor)"]
STORE["SystemTelemetryStore (@Observable)"]
ALERTS["AlertEngine (Rule Evaluator)"]
VIEWS["SwiftUI Dashboard / Popover / Charts (60 FPS)"]
end
SMC_DEV <-->|"IOConnectCallStructMethod"| PROV1
MACH_KERN -->|"host_processor_info / host_statistics64"| PROV2
BSD_SYS -->|"sysctl / proc_listpids"| PROV3
BSD_SYS --> PROV4
IOK_DRV -->|"IORegistryEntryCreateCFProperties"| BATCH
DISPATCH -->|"Trigger Tick (1s/2s)"| PROV1 & PROV2 & PROV3 & PROV4
PROV1 & PROV2 & PROV3 & PROV4 --> BATCH
BATCH -->|"Async Dispatch (Snapshot Copy)"| STORE
STORE -->|"Evaluate Rules"| ALERTS
STORE -->|"Declarative Bindings"| VIEWS
```
### 2.1 Threading & QoS Architecture
1. **Background Polling Queue:**
All hardware and kernel polling operations execute on a dedicated serial queue:
```objc
dispatch_queue_t queue = dispatch_queue_create("com.i3omb.macmonitor.telemetry", DISPATCH_QUEUE_SERIAL);
```
Configured with quality-of-service `QOS_CLASS_UTILITY` to prevent thermal or CPU contention with foreground user processes.
2. **Deterministic Sampling Timer:**
Driven by a Grand Central Dispatch timer source (`dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, ...)`). Timer coalescing leeway is set to 10% of the sample period to conserve battery on MacBooks while maintaining timing accuracy.
3. **Main Actor State Ingestion:**
Snapshots are unmarshaled into immutable, `Sendable` Swift structures and dispatched asynchronously to `@MainActor`:
```swift
Task { @MainActor in
self.store.digest(snapshot: batch)
}
```
4. **Mach Virtual Memory Management Invariant:**
Calls returning kernel-allocated memory arrays (such as `host_processor_info` or `processor_cpu_load_info`) must explicitly deallocate their previous memory pointers using `vm_deallocate(mach_task_self(), ...)` in the subsequent sampling pass to prevent progressive heap bloat.
---
## 3. Subsystem Implementation Specifications
### 3.1 Apple System Management Controller (AppleSMC)
- **Service Name:** `AppleSMC`
- **IOKit Connection:** Initiated using `IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("AppleSMC"))` and `IOServiceOpen(service, mach_task_self(), 0, &connect)`.
- **Selector:** `kSMCHandleYPCEvent` (Index 2) dispatched via `IOConnectCallStructMethod`.
#### SMC Data Types & Decoding Algorithms
| Data Type | FourCC | Byte Length | Encoding Scheme | Decoding Formula |
| :--- | :---: | :---: | :--- | :--- |
| `sp78` | `0x73703738` | 2 | Signed 8.8 Fixed-Point | `tempC = ((int16_t)(b[0] << 8 \| b[1])) / 256.0` |
| `fpe2` | `0x66706532` | 2 | Unsigned 14.2 Fixed-Point | `rpm = ((uint16_t)(b[0] << 8 \| b[1])) / 4.0` |
| `ui8` | `0x75693820` | 1 | Unsigned 8-bit Integer | `val = (uint8_t)b[0]` |
| `ui16` | `0x75693136` | 2 | Unsigned 16-bit Big-Endian | `val = (uint16_t)(b[0] << 8 \| b[1])` |
| `ui32` | `0x75693332` | 4 | Unsigned 32-bit Big-Endian | `val = (uint32_t)(b[0] << 24 \| ... \| b[3])` |
| `flt ` | `0x666c7420` | 4 | IEEE 754 32-bit Float | `memcpy(&val, b, 4)` |
#### Intel SMC Key Catalog
- **Fans:** `FNum` (Total count), `F0Ac`/`F1Ac` (Current RPM), `F0Mn`/`F1Mn` (Min RPM), `F0Mx`/`F1Mx` (Max RPM), `F0Tg`/`F1Tg` (Target RPM), `F0ID`/`F1ID` (Fan name).
- **CPU Thermals:** `TC0P` (Package proximity), `TC0D` (Die), `TCXC` (PECI), `TC0C``TC15C` (Individual core DTS).
- **Chassis Thermals:** `TPCD` (PCH Die), `Th0H``Th2H` (Heatsinks), `TM0P``TM3P` (Memory DIMMs), `TA0P`/`TA1P` (Chassis Ambient), `Tp0P` (Power Supply), `TTLD` (Thunderbolt).
- **Electrical & RAPL:** `PSTR`/`PDTR` (System Total Watts), `PCPR`/`PCTR` (CPU Package Watts via Intel RAPL), `PG0R` (GPU Watts), `VC0C` (Core Voltage), `IC0C` (Core Current).
---
### 3.2 Host CPU & Kernel Scheduling Telemetry
- **Per-Core Tick Counting:**
Executed via `host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, ...)`.
Deltas between ticks determine normalized CPU percentages:
$$\Delta \text{ticks} = \Delta \text{user} + \Delta \text{system} + \Delta \text{idle} + \Delta \text{nice}$$
$$\text{Core \%} = \frac{\Delta \text{user} + \Delta \text{system} + \Delta \text{nice}}{\Delta \text{ticks}} \times 100\%$$
- **Kernel Context Switches & Syscalls:**
Polled via BSD sysctl node statistics:
- `vm.stats.sys.v_swtch`
- `vm.stats.sys.v_syscall`
- `vm.stats.sys.v_intr`
- `vm_statistics64.faults` (Page faults)
Rates are computed against elapsed nanoseconds measured using `mach_absolute_time()` and `mach_timebase_info()`.
- **Unix Load Averages:**
Queried via standard BSD `getloadavg(double load[], 3)` and normalized against `[NSProcessInfo processInfo].activeProcessorCount`.
---
### 3.3 Virtual Memory & Pressure Subsystem
- **RAM Calculation Strategy:**
Direct query of `host_statistics64(mach_host_self(), HOST_VM_INFO64, ...)` multiplied by `vm_kernel_page_size`.
- **App Memory:** $(\text{internal\_count} - \text{purgeable\_count}) \times \text{page\_size}$
- **Wired Memory:** $\text{wire\_count} \times \text{page\_size}$
- **Compressed Memory:** $\text{compressor\_page\_count} \times \text{page\_size}$
- **Cached Files:** $(\text{external\_page\_count} + \text{purgeable\_count}) \times \text{page\_size}$
- **Free Memory:** $\text{free\_count} \times \text{page\_size}$
- **Swap Statistics:** `sysctlbyname("vm.swapusage", &swap, ...)` reporting `xsu_total`, `xsu_avail`, and `xsu_used`.
- **Memory Pressure Monitoring:**
Dedicated GCD dispatch source:
```objc
dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
DISPATCH_MEMORYPRESSURE_NORMAL |
DISPATCH_MEMORYPRESSURE_WARN |
DISPATCH_MEMORYPRESSURE_CRITICAL, queue);
```
---
### 3.4 Storage & Disk I/O Engine
- **Volume Capacity & APFS Snapshots:**
Queried via `NSFileManager.defaultManager.mountedVolumeURLsIncludingResourceValuesForKeys:`.
Utilizes `NSURLVolumeAvailableCapacityForImportantUsageKey` and `NSURLVolumeAvailableCapacityForOpportunisticUsageKey` to properly calculate usable storage space without showing local APFS snapshots as consumed capacity.
- **Real-Time Disk Throughput (IOPS & MB/s):**
Matches `IOBlockStorageDriver` in IOKit registry. Extracts `IOBlockStorageDriverStatistics`:
- `Bytes (Read)` and `Bytes (Write)`
- `Operations (Read)` and `Operations (Write)`
Deltas over elapsed time yield read/write throughput (MB/s) and IOPS.
---
### 3.5 High-Performance Process Explorer
- **Enumeration:** `proc_listpids(PROC_ALL_PIDS, 0, pids, byteSize)` to retrieve active PIDs.
- **Resource Attribution:**
- `proc_pidinfo(pid, PROC_PIDTASKINFO, ...)` yields `pti_total_user`, `pti_total_system`, `pti_resident_size`, and `pti_threadnum`.
- Differential CPU calculation tracks elapsed nanoseconds vs elapsed CPU time per process.
- **Static Metadata Caching:**
Executable paths (`proc_pidpath`) and application icons (`NSWorkspace.iconForFile:`) are cached in an internal hash map keyed by PID to eliminate file system traversal overhead during 1 Hz polling loops. Dead PIDs are pruned on each iteration.
- **Drill-Down Inspector:**
- Threads: `proc_pidinfo(..., PROC_PIDLISTTHREADS)` + `PROC_PIDTHREADINFO`.
- File Descriptors: `proc_pidinfo(..., PROC_PIDLISTFDS)` + `proc_pidfdinfo(..., PROC_PIDFDVNODEPATHINFO)`.
- Sockets: `proc_pidfdinfo(..., PROC_PIDFDSOCKETINFO)`.
---
### 3.6 GPU & Graphics Telemetry
- **IOKit Accelerator Service:** Matches `IOAccelerator` nodes in the IORegistry.
- **Performance Properties:** Inspects `PerformanceStatistics` dictionary:
- `Device Utilization %`
- `GPU Core Clock Hz`
- `vramUsedBytes` / `vramFreeBytes`
- `Temperature(C)`
- **Multi-GPU Architecture:** Handles both Intel integrated graphics (Intel Iris/UHD) and discrete AMD Radeon Pro GPUs on 15"/16" MacBook Pros. Correctly accommodates AMD GPU power-down states when automatic graphics switching is idle.
---
### 3.7 Network Bandwidth & Protocol Control Blocks
- **64-Bit Network Traffic Counters:**
Avoids 32-bit integer rollover on high-throughput connections by querying BSD routing tables via `sysctl` with `NET_RT_IFLIST2` and decoding `struct if_data64` (`ifi_ibytes`, `ifi_obytes`, `ifi_ipackets`, `ifi_opackets`).
- **Socket Table Inspection:**
Scans active TCP/UDP Protocol Control Blocks via `net.inet.tcp.pcblist_n` and `net.inet.udp.pcblist_n`, parsing `xinpcb_n` to extract local/foreign addresses and connection states.
---
### 3.8 Display & Screen Brightness
- **Dynamic Framework Linking:**
To safely access screen brightness across built-in MacBook screens and Apple external displays, private `DisplayServices.framework` symbols (`DisplayServicesGetBrightness`, `DisplayServicesSetBrightness`) are loaded dynamically via `dlopen`/`dlsym`.
- **Display Configurations:**
CoreGraphics APIs (`CGGetActiveDisplayList`, `CGDisplayCopyDisplayMode`) provide active screen resolution, refresh rate (Hz), and built-in panel identification.
---
### 3.9 Time-Series Visualization (Swift Charts Engine)
- **Ring Buffer Design:**
Fixed-capacity circular ring buffers (`RingBuffer<T>`) maintain rolling samples (60s, 5m, 15m, 1h).
Appending is $O(1)$ with zero runtime dynamic memory reallocations.
- **Swift Charts Integration:**
Renders using Apple's declarative `Chart`, `LineMark`, and gradient `AreaMark` components, backed by Metal rasterization.
---
### 3.10 Intelligence & Alert Rules Engine
- **Architecture:** Synchronous post-sampling evaluation engine (`AlertEngine`).
- **Notification Throttle & Cooldown:**
Each alert identifier maintains a cooldown timestamp. Notifications for persistent abnormal conditions (e.g. CPU temperature > 95°C) are capped at a maximum of 1 alert per 1015 minutes until normalized, preventing notification floods.
- **Delivery Channel:** Native `UNUserNotificationCenter` with critical priority sounds for fan stalls and hardware emergencies.