Files
MacMonitor/ARCHITECTURE.md
T

11 KiB
Raw Permalink Blame History

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

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:
    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:
    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), TC0CTC15C (Individual core DTS).
  • Chassis Thermals: TPCD (PCH Die), Th0HTh2H (Heatsinks), TM0PTM3P (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:
    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.