8a66b9086a
- Started from ac75faa (initial E4B-MarkBase integration)
- Kept Sources/ (all engine code) + Package.swift + .gitignore
- Removed all ad-hoc tests, documentation, scripts, Python files
- Added Tests/00_Unit/ (MathTest, TokenizerTest, SamplerTest)
- Added .gitea/workflows/ci.yaml (build + unit tests + lint)
- Added Scripts/check_resources.sh (memory-aware test runner)
- Added Tests/Manifest.json (resource requirements for all tests)
- Focus: 4-bit quantized models only
111 lines
3.6 KiB
Swift
111 lines
3.6 KiB
Swift
import Foundation
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Dynamic Concurrency Controller
|
|
// Automatically adjusts concurrency based on system resources
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
/// Memory statistics
|
|
public struct MemoryStats {
|
|
public let total: UInt64
|
|
public let available: UInt64
|
|
public let used: UInt64
|
|
public let percentage: Double
|
|
|
|
public init(total: UInt64, available: UInt64, used: UInt64) {
|
|
self.total = total
|
|
self.available = available
|
|
self.used = used
|
|
self.percentage = total > 0 ? Double(used) / Double(total) : 0
|
|
}
|
|
}
|
|
|
|
/// Dynamic concurrency controller
|
|
public actor DynamicConcurrencyController {
|
|
private var currentMax: Int
|
|
private let minConcurrency: Int
|
|
private let maxConcurrency: Int
|
|
private let modelMemoryEstimate: UInt64
|
|
|
|
/// Concurrency adjustment event
|
|
public struct ConcurrencyEvent {
|
|
public let timestamp: Date
|
|
public let oldMax: Int
|
|
public let newMax: Int
|
|
public let reason: String
|
|
}
|
|
|
|
/// Event handler
|
|
public var onConcurrencyChange: ((ConcurrencyEvent) -> Void)?
|
|
|
|
public init(
|
|
initialConcurrency: Int = 4,
|
|
minConcurrency: Int = 1,
|
|
maxConcurrency: Int = 16,
|
|
modelMemoryEstimate: UInt64 = 9 * 1024 * 1024 * 1024 // 9GB for 12B
|
|
) {
|
|
self.currentMax = initialConcurrency
|
|
self.minConcurrency = minConcurrency
|
|
self.maxConcurrency = maxConcurrency
|
|
self.modelMemoryEstimate = modelMemoryEstimate
|
|
}
|
|
|
|
/// Get current max concurrency
|
|
public func getCurrentMax() -> Int {
|
|
return currentMax
|
|
}
|
|
|
|
/// Adjust concurrency based on current memory
|
|
@discardableResult
|
|
public func adjust() -> ConcurrencyEvent? {
|
|
let oldMax = currentMax
|
|
|
|
// Simplified: use available memory estimation
|
|
// In production, you would use actual memory stats
|
|
let recommendedConcurrency = 4 // Default for now
|
|
|
|
let newMax = max(minConcurrency, min(maxConcurrency, recommendedConcurrency))
|
|
|
|
if newMax != oldMax {
|
|
let event = ConcurrencyEvent(
|
|
timestamp: Date(),
|
|
oldMax: oldMax,
|
|
newMax: newMax,
|
|
reason: "Automatic adjustment"
|
|
)
|
|
|
|
currentMax = newMax
|
|
onConcurrencyChange?(event)
|
|
return event
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/// Get recommended concurrency for a given model size
|
|
public static func recommendConcurrency(
|
|
modelMemoryBytes: UInt64,
|
|
totalMemory: UInt64,
|
|
reservedMemory: UInt64 = 2 * 1024 * 1024 * 1024 // 2GB reserved
|
|
) -> Int {
|
|
let availableMemory = totalMemory - reservedMemory
|
|
let concurrency = Int(availableMemory / modelMemoryBytes)
|
|
return max(1, concurrency)
|
|
}
|
|
}
|
|
|
|
/// Memory monitor using system information
|
|
public actor MemoryMonitor {
|
|
public init() {}
|
|
|
|
/// Get current memory statistics (simplified)
|
|
public func getStats() -> MemoryStats {
|
|
// Simplified implementation
|
|
return MemoryStats(
|
|
total: 48 * 1024 * 1024 * 1024, // 48GB
|
|
available: 32 * 1024 * 1024 * 1024, // 32GB
|
|
used: 16 * 1024 * 1024 * 1024 // 16GB
|
|
)
|
|
}
|
|
}
|