SPB Git

spb/zyquo-local Public MIT

Native macOS AI chat that runs LLMs 100% locally on Apple Silicon with MLX — no cloud, no API keys.

Swift 97.2% Shell 1.8% Makefile 1%
2.1 KB · 63 lines swift
Raw Blame History
1//2//  MemoryAdvisor.swift3//  Zyquo Local4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//89import Foundation10import MLX1112/// RAM estimation and fits/tight/won't-fit verdicts for THIS Mac.13/// Thresholds follow docs/MLX-RESEARCH.md §7: the macOS GPU-wired ceiling is14/// ~70–75 % of unified memory, so weights ≤60 % is comfortable, ≤75 % tight.15enum MemoryAdvisor {16    enum Verdict: String, Codable, Sendable {17        case fits18        case tight19        case tooLarge2021        var label: String {22            switch self {23            case .fits: "Fits"24            case .tight: "Tight"25            case .tooLarge: "Too large"26            }27        }28    }2930    /// Physical unified memory of this Mac in bytes.31    static var physicalMemoryBytes: UInt64 { HardwareGate.physicalMemory }3233    /// Estimated RAM needed to run a model: weights + KV cache + overhead.34    /// weights×1.2 covers activations/prefill working set; +1.5 GB covers a35    /// useful KV cache at moderate context.36    static func estimatedRuntimeBytes(weightsBytes: Int64) -> Int64 {37        Int64(Double(weightsBytes) * 1.2) + 1_500_000_00038    }3940    /// Verdict for a model of the given on-disk weights size.41    static func verdict(weightsBytes: Int64) -> Verdict {42        let ram = Double(physicalMemoryBytes)43        let weights = Double(weightsBytes)44        if weights <= ram * 0.60 { return .fits }45        if weights <= ram * 0.75 { return .tight }46        return .tooLarge47    }4849    /// Verdict for running two models side by side (Compare mode gate).50    static func verdict(combinedWeightsBytes: Int64) -> Verdict {51        verdict(weightsBytes: combinedWeightsBytes)52    }5354    /// Live MLX memory snapshot (bytes actively used by the loaded model).55    static var activeMemoryBytes: Int { MLX.Memory.activeMemory }56    static var peakMemoryBytes: Int { MLX.Memory.peakMemory }5758    static func resetPeakMemory() { MLX.GPU.resetPeakMemory() }5960    /// Returns cached MLX buffers to the OS — called after unloading a model.61    static func reclaimMemory() { MLX.Memory.clearCache() }62}63