bleam 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +23 -4
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +23 -4
- package/dist/{ui-234Plg7Z.d.cts → ui-Bg11tvlc.d.ts} +7 -7
- package/dist/ui.d.ts +1 -1
- package/dist/window.d.ts +1 -1
- package/package.json +4 -1
- package/templates/image-generation/app/index.tsx +1 -1
- package/templates/native/.gitattributes +1 -0
- package/templates/native/App.tsx +26 -0
- package/templates/native/app.json +12 -0
- package/templates/native/index.ts +8 -0
- package/templates/native/ios/.xcode.env +11 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/Flux2Config.swift +288 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/MemoryConfig.swift +233 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/MemoryOptimizationConfig.swift +157 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/ModelRegistry.swift +425 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/QuantizationConfig.swift +138 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/TransformerRepoProfile.swift +59 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/VAEConfig.swift +134 -0
- package/templates/native/ios/Bleam/AI/Flux2/Flux2Core.swift +55 -0
- package/templates/native/ios/Bleam/AI/Flux2/Loading/WeightLoader.swift +1192 -0
- package/templates/native/ios/Bleam/AI/Flux2/Pipeline/FluxImageRunner.swift +1282 -0
- package/templates/native/ios/Bleam/AI/Flux2/Pipeline/LatentUtils.swift +191 -0
- package/templates/native/ios/Bleam/AI/Flux2/Scheduler/FlowMatchEulerScheduler.swift +279 -0
- package/templates/native/ios/Bleam/AI/Flux2/Text/KleinTextEncoder.swift +380 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Attention.swift +379 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Embeddings.swift +159 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2FeedForward.swift +154 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2FusedKernels.swift +198 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2KVCache.swift +36 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Modulation.swift +193 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2ParallelAttention.swift +389 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2RoPE.swift +304 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2SingleBlock.swift +290 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Transformer.swift +530 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2TransformerBlock.swift +362 -0
- package/templates/native/ios/Bleam/AI/Flux2/Utils/Flux2Debug.swift +101 -0
- package/templates/native/ios/Bleam/AI/Flux2/Utils/MLXCheckpoint.swift +118 -0
- package/templates/native/ios/Bleam/AI/Flux2/Utils/MemoryManager.swift +201 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/AutoencoderKL.swift +476 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/ResnetBlock.swift +316 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/VAEDecoder.swift +120 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/VAEEncoder.swift +136 -0
- package/templates/native/ios/Bleam/AppDelegate.swift +373 -0
- package/templates/native/ios/Bleam/Appearance.swift +62 -0
- package/templates/native/ios/Bleam/Bridging-Header.h +3 -0
- package/templates/native/ios/Bleam/Images.xcassets/AppIcon.appiconset/Contents.json +13 -0
- package/templates/native/ios/Bleam/Images.xcassets/Contents.json +6 -0
- package/templates/native/ios/Bleam/Info.plist +76 -0
- package/templates/native/ios/Bleam/PrivacyInfo.xcprivacy +48 -0
- package/templates/native/ios/Bleam/SceneDelegate.swift +58 -0
- package/templates/native/ios/Bleam/SplashScreen.storyboard +47 -0
- package/templates/native/ios/Bleam/Supporting/Expo.plist +6 -0
- package/templates/native/ios/Bleam/bleam.entitlements +10 -0
- package/templates/native/ios/Bleam.xcodeproj/project.pbxproj +1146 -0
- package/templates/native/ios/Bleam.xcodeproj/xcshareddata/xcschemes/Bleam.xcscheme +88 -0
- package/templates/native/ios/GenerationService/GenerationService.entitlements +10 -0
- package/templates/native/ios/GenerationService/ImageGenerationRunner.swift +591 -0
- package/templates/native/ios/GenerationService/Info.plist +31 -0
- package/templates/native/ios/GenerationService/main.swift +165 -0
- package/templates/native/ios/PlatformHelper/Info.plist +29 -0
- package/templates/native/ios/PlatformHelper/main.swift +335 -0
- package/templates/native/ios/Podfile +198 -0
- package/templates/native/ios/Podfile.lock +2284 -0
- package/templates/native/ios/Podfile.properties.json +5 -0
- package/templates/native/ios/Shared/Generation/GenerationServiceProtocol.swift +12 -0
- package/templates/native/ios/Shared/Generation/GenerationWorkerProtocol.swift +124 -0
- package/templates/native/metro.config.js +6 -0
- package/templates/native/modules/bleam-runtime/BleamRuntime.podspec +14 -0
- package/templates/native/modules/bleam-runtime/expo-module.config.json +8 -0
- package/templates/native/modules/bleam-runtime/ios/AIModule.swift +1258 -0
- package/templates/native/modules/bleam-runtime/ios/GenerationContracts.swift +135 -0
- package/templates/native/modules/bleam-runtime/ios/PlatformModule.swift +313 -0
- package/templates/native/modules/bleam-runtime/package.json +5 -0
- package/templates/native/package.json +39 -0
- package/templates/native/scripts/build/mlx-frameworks.ts +421 -0
- package/templates/native/scripts/start/index.ts +474 -0
- package/templates/native/scripts/start/known-failures.ts +20 -0
- package/templates/native/scripts/start/loader.ts +76 -0
- package/templates/native/scripts/start/native-state.ts +242 -0
- package/templates/native/scripts/start/package.json +4 -0
- package/templates/native/scripts/start/swift-packages.ts +414 -0
- package/templates/native/scripts/start/xcode-formatter.ts +106 -0
- package/templates/native/tsconfig.json +14 -0
- package/templates/native/yarn.lock +3749 -0
- package/dist/ui-BJmXhz9Q.d.ts +0 -92
- package/dist/ui-Dd7SXdbg.d.cts +0 -92
- package/dist/ui-Ds88eETu.d.ts +0 -92
- package/dist/ui-TaqnB5SP.d.ts +0 -92
- package/dist/ui-WQvnXL0W.d.ts +0 -92
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// MemoryConfig.swift - Centralized memory management configuration
|
|
2
|
+
// Copyright 2025 Vincent Gourbin
|
|
3
|
+
|
|
4
|
+
import Foundation
|
|
5
|
+
import MLX
|
|
6
|
+
|
|
7
|
+
/// Centralized memory configuration for GPU cache management
|
|
8
|
+
///
|
|
9
|
+
/// Provides dynamic memory management that adapts to:
|
|
10
|
+
/// - System RAM availability
|
|
11
|
+
/// - Image resolution being generated
|
|
12
|
+
/// - Model size (currently Klein 4B only in image-studio)
|
|
13
|
+
///
|
|
14
|
+
/// On high-RAM systems (64GB+), allows more cache for better performance.
|
|
15
|
+
/// On lower-RAM systems, uses conservative limits to prevent OOM.
|
|
16
|
+
public struct MemoryConfig {
|
|
17
|
+
|
|
18
|
+
// MARK: - Constants
|
|
19
|
+
|
|
20
|
+
private static let MB = 1024 * 1024
|
|
21
|
+
private static let GB = 1024 * 1024 * 1024
|
|
22
|
+
|
|
23
|
+
// MARK: - Cache Profiles
|
|
24
|
+
|
|
25
|
+
/// Memory profile presets - used as hints for dynamic calculation
|
|
26
|
+
public enum CacheProfile: String, CaseIterable, Sendable {
|
|
27
|
+
case conservative // Minimize memory usage (slower)
|
|
28
|
+
case balanced // Balance speed and memory
|
|
29
|
+
case performance // Maximize speed (more memory)
|
|
30
|
+
case auto // Dynamic based on available RAM
|
|
31
|
+
|
|
32
|
+
/// Human-readable description
|
|
33
|
+
public var description: String {
|
|
34
|
+
switch self {
|
|
35
|
+
case .conservative: return "Conservative - Minimize memory (may be slower)"
|
|
36
|
+
case .balanced: return "Balanced - Good tradeoff"
|
|
37
|
+
case .performance: return "Performance - Maximize speed (uses more memory)"
|
|
38
|
+
case .auto: return "Auto - Dynamic based on available RAM"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// MARK: - System Information
|
|
44
|
+
|
|
45
|
+
/// Get system RAM in GB
|
|
46
|
+
public static var systemRAMGB: Int {
|
|
47
|
+
Int(ProcessInfo.processInfo.physicalMemory / UInt64(GB))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Estimate available RAM in GB (rough heuristic)
|
|
51
|
+
/// Reserves ~8GB for system + other apps
|
|
52
|
+
public static var estimatedAvailableRAMGB: Int {
|
|
53
|
+
max(8, systemRAMGB - 8)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// Calculate what percentage of RAM we can safely use for GPU cache
|
|
57
|
+
/// Higher RAM systems can afford to use more cache
|
|
58
|
+
public static var safeCachePercentage: Double {
|
|
59
|
+
let ram = systemRAMGB
|
|
60
|
+
switch ram {
|
|
61
|
+
case ..<24: return 0.03 // 3% - Very conservative for 16-24GB
|
|
62
|
+
case 24..<48: return 0.05 // 5% - Conservative for 24-48GB
|
|
63
|
+
case 48..<96: return 0.08 // 8% - Moderate for 48-96GB
|
|
64
|
+
case 96..<192: return 0.12 // 12% - Performance for 96-192GB
|
|
65
|
+
default: return 0.15 // 15% - High performance for 192GB+
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// MARK: - Dynamic Cache Calculation
|
|
70
|
+
|
|
71
|
+
/// Calculate recommended cache limit based on system RAM
|
|
72
|
+
/// Returns bytes, or nil for unlimited
|
|
73
|
+
public static func recommendedCacheLimit() -> Int? {
|
|
74
|
+
let ram = systemRAMGB
|
|
75
|
+
|
|
76
|
+
// Very high RAM systems (128GB+) can use unlimited cache
|
|
77
|
+
if ram >= 128 {
|
|
78
|
+
return nil
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Calculate based on percentage of RAM
|
|
82
|
+
let cacheBytes = Int(Double(ram * GB) * safeCachePercentage)
|
|
83
|
+
|
|
84
|
+
// Clamp to reasonable bounds
|
|
85
|
+
let minCache = 256 * MB // At least 256 MB
|
|
86
|
+
let maxCache = 8 * GB // At most 8 GB
|
|
87
|
+
|
|
88
|
+
return min(max(cacheBytes, minCache), maxCache)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// Calculate cache limit for a specific resolution
|
|
92
|
+
/// Larger images need more cache for intermediate computations
|
|
93
|
+
public static func cacheLimitForResolution(width: Int, height: Int, model: Flux2Model) -> Int {
|
|
94
|
+
let pixels = width * height
|
|
95
|
+
let baseLimit = recommendedCacheLimit() ?? (4 * GB)
|
|
96
|
+
|
|
97
|
+
// Scale factor based on resolution
|
|
98
|
+
// 512x512 = 262144 pixels (base)
|
|
99
|
+
// 1024x1024 = 1048576 pixels (4x)
|
|
100
|
+
// 2048x2048 = 4194304 pixels (16x)
|
|
101
|
+
let basePixels = 512 * 512
|
|
102
|
+
let scaleFactor = max(1.0, sqrt(Double(pixels) / Double(basePixels)))
|
|
103
|
+
|
|
104
|
+
// Model size factor
|
|
105
|
+
let modelFactor: Double = 1.0
|
|
106
|
+
|
|
107
|
+
let adjustedLimit = Int(Double(baseLimit) * scaleFactor * modelFactor)
|
|
108
|
+
|
|
109
|
+
// Clamp to available RAM (leave at least 8GB for system)
|
|
110
|
+
let maxAllowed = (systemRAMGB - 8) * GB
|
|
111
|
+
return min(adjustedLimit, maxAllowed)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// MARK: - Profile-based Limits (for manual override)
|
|
115
|
+
|
|
116
|
+
/// Get cache limit for a specific profile
|
|
117
|
+
public static func cacheLimitForProfile(_ profile: CacheProfile) -> Int? {
|
|
118
|
+
switch profile {
|
|
119
|
+
case .auto:
|
|
120
|
+
return recommendedCacheLimit()
|
|
121
|
+
case .conservative:
|
|
122
|
+
return 512 * MB
|
|
123
|
+
case .balanced:
|
|
124
|
+
return min(2 * GB, (systemRAMGB / 32) * GB)
|
|
125
|
+
case .performance:
|
|
126
|
+
return min(4 * GB, (systemRAMGB / 16) * GB)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// MARK: - Cache Limit Application
|
|
131
|
+
|
|
132
|
+
/// Apply cache limit dynamically based on system RAM
|
|
133
|
+
public static func applyDynamicCacheLimit() {
|
|
134
|
+
if let limit = recommendedCacheLimit() {
|
|
135
|
+
Memory.cacheLimit = limit
|
|
136
|
+
Flux2Debug.log("GPU cache limit: \(limit / MB) MB (dynamic, \(systemRAMGB) GB RAM)")
|
|
137
|
+
} else {
|
|
138
|
+
Flux2Debug.log("GPU cache: unlimited (\(systemRAMGB) GB RAM)")
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// Apply cache limit for a specific profile
|
|
143
|
+
public static func applyCacheLimit(_ profile: CacheProfile) {
|
|
144
|
+
if let limit = cacheLimitForProfile(profile) {
|
|
145
|
+
Memory.cacheLimit = limit
|
|
146
|
+
Flux2Debug.log("GPU cache limit: \(limit / MB) MB (\(profile.rawValue) profile)")
|
|
147
|
+
} else {
|
|
148
|
+
Flux2Debug.log("GPU cache: unlimited (\(profile.rawValue) profile)")
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/// Apply cache limit with specific byte value
|
|
153
|
+
public static func applyCacheLimit(bytes: Int) {
|
|
154
|
+
Memory.cacheLimit = bytes
|
|
155
|
+
Flux2Debug.log("GPU cache limit: \(bytes / MB) MB")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/// Clear GPU cache
|
|
159
|
+
public static func clearCache() {
|
|
160
|
+
Memory.clearCache()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// MARK: - Phase-Specific Limits
|
|
164
|
+
|
|
165
|
+
/// Per-phase cache limits for granular control during generation
|
|
166
|
+
public struct PhaseLimits: Sendable {
|
|
167
|
+
public let textEncoding: Int // Text encoder phase
|
|
168
|
+
public let denoising: Int // Transformer denoising loop
|
|
169
|
+
public let vaeDecoding: Int // VAE decode phase
|
|
170
|
+
|
|
171
|
+
public init(textEncoding: Int, denoising: Int, vaeDecoding: Int) {
|
|
172
|
+
self.textEncoding = textEncoding
|
|
173
|
+
self.denoising = denoising
|
|
174
|
+
self.vaeDecoding = vaeDecoding
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/// Get dynamic phase limits based on model and system RAM
|
|
178
|
+
/// Automatically scales based on available memory
|
|
179
|
+
public static func forModel(_ model: Flux2Model, profile: CacheProfile) -> PhaseLimits {
|
|
180
|
+
// Use dynamic calculation for auto profile
|
|
181
|
+
if profile == .auto {
|
|
182
|
+
return dynamicLimitsForModel(model)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
switch profile {
|
|
186
|
+
case .auto:
|
|
187
|
+
return dynamicLimitsForModel(model)
|
|
188
|
+
case .conservative:
|
|
189
|
+
return PhaseLimits(textEncoding: 256 * MB, denoising: 512 * MB, vaeDecoding: 256 * MB)
|
|
190
|
+
case .balanced:
|
|
191
|
+
return PhaseLimits(textEncoding: 512 * MB, denoising: 1 * GB, vaeDecoding: 512 * MB)
|
|
192
|
+
case .performance:
|
|
193
|
+
return PhaseLimits(textEncoding: 1 * GB, denoising: 2 * GB, vaeDecoding: 1 * GB)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/// Calculate dynamic limits based on available RAM
|
|
198
|
+
private static func dynamicLimitsForModel(_ model: Flux2Model) -> PhaseLimits {
|
|
199
|
+
let baseLimit = recommendedCacheLimit() ?? (4 * GB)
|
|
200
|
+
|
|
201
|
+
_ = model
|
|
202
|
+
let (textRatio, denoiseRatio, vaeRatio): (Double, Double, Double) = (0.25, 0.6, 0.3)
|
|
203
|
+
|
|
204
|
+
return PhaseLimits(
|
|
205
|
+
textEncoding: Int(Double(baseLimit) * textRatio),
|
|
206
|
+
denoising: Int(Double(baseLimit) * denoiseRatio),
|
|
207
|
+
vaeDecoding: Int(Double(baseLimit) * vaeRatio)
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// MARK: - Memory Monitoring
|
|
213
|
+
|
|
214
|
+
/// Log current memory state
|
|
215
|
+
public static func logMemoryState(context: String = "") {
|
|
216
|
+
let prefix = context.isEmpty ? "" : "[\(context)] "
|
|
217
|
+
let recommended = recommendedCacheLimit()
|
|
218
|
+
let limitStr = recommended.map { "\($0 / MB) MB" } ?? "unlimited"
|
|
219
|
+
Flux2Debug.log("\(prefix)System: \(systemRAMGB) GB RAM, recommended cache: \(limitStr)")
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/// Get a summary of current memory configuration
|
|
223
|
+
public static var configurationSummary: String {
|
|
224
|
+
let recommended = recommendedCacheLimit()
|
|
225
|
+
let limitStr = recommended.map { "\($0 / MB) MB" } ?? "unlimited"
|
|
226
|
+
return """
|
|
227
|
+
Memory Configuration:
|
|
228
|
+
System RAM: \(systemRAMGB) GB
|
|
229
|
+
Safe cache %: \(Int(safeCachePercentage * 100))%
|
|
230
|
+
Recommended cache: \(limitStr)
|
|
231
|
+
"""
|
|
232
|
+
}
|
|
233
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// MemoryOptimizationConfig.swift - Memory optimization settings
|
|
2
|
+
// Copyright 2025 Vincent Gourbin
|
|
3
|
+
|
|
4
|
+
import Foundation
|
|
5
|
+
|
|
6
|
+
/// Configuration for memory optimization during transformer inference
|
|
7
|
+
///
|
|
8
|
+
/// These settings control how aggressively the transformer manages memory
|
|
9
|
+
/// by forcing evaluation of the computation graph at intervals.
|
|
10
|
+
///
|
|
11
|
+
/// # Background
|
|
12
|
+
/// MLX uses lazy evaluation and builds a computation graph. For large models,
|
|
13
|
+
/// this graph can grow very large and consume significant memory. Periodically
|
|
14
|
+
/// calling `eval()` materializes intermediate results and allows the graph to
|
|
15
|
+
/// be garbage collected.
|
|
16
|
+
///
|
|
17
|
+
/// # Trade-offs
|
|
18
|
+
/// - Lower `evalFrequency` = more memory savings, but slower inference
|
|
19
|
+
/// - Higher `evalFrequency` = faster inference, but more memory usage
|
|
20
|
+
/// - `clearCacheOnEval` = additional memory savings at cost of recomputation
|
|
21
|
+
///
|
|
22
|
+
/// # Reference
|
|
23
|
+
/// Based on optimizations from LTX-2-MLX: https://github.com/Acelogic/LTX-2-MLX
|
|
24
|
+
public struct MemoryOptimizationConfig: Sendable, Equatable {
|
|
25
|
+
|
|
26
|
+
/// How often to evaluate the computation graph during transformer forward pass.
|
|
27
|
+
///
|
|
28
|
+
/// - `0` = disabled (fastest, most memory)
|
|
29
|
+
/// - `4` = evaluate every 4 blocks (aggressive memory savings)
|
|
30
|
+
/// - `8` = evaluate every 8 blocks (moderate, recommended)
|
|
31
|
+
/// - `16` = evaluate every 16 blocks (light memory savings)
|
|
32
|
+
///
|
|
33
|
+
/// For Flux.2 Dev with 8 double + 48 single blocks:
|
|
34
|
+
/// - `evalFrequency: 8` will eval ~7 times during forward pass
|
|
35
|
+
/// - `evalFrequency: 4` will eval ~14 times during forward pass
|
|
36
|
+
public var evalFrequency: Int
|
|
37
|
+
|
|
38
|
+
/// Whether to clear GPU cache after each evaluation.
|
|
39
|
+
///
|
|
40
|
+
/// When enabled, calls `MLX.Memory.clearCache()` after each periodic eval.
|
|
41
|
+
/// This provides additional memory savings but may cause recomputation
|
|
42
|
+
/// of cached values.
|
|
43
|
+
///
|
|
44
|
+
/// Recommended: `false` for most cases, `true` only if running out of memory
|
|
45
|
+
public var clearCacheOnEval: Bool
|
|
46
|
+
|
|
47
|
+
/// Whether to evaluate after all double-stream blocks complete.
|
|
48
|
+
///
|
|
49
|
+
/// This ensures the transition between double-stream and single-stream
|
|
50
|
+
/// phases has a clean memory state.
|
|
51
|
+
public var evalBetweenPhases: Bool
|
|
52
|
+
|
|
53
|
+
public init(
|
|
54
|
+
evalFrequency: Int = 0,
|
|
55
|
+
clearCacheOnEval: Bool = false,
|
|
56
|
+
evalBetweenPhases: Bool = true
|
|
57
|
+
) {
|
|
58
|
+
self.evalFrequency = max(0, evalFrequency)
|
|
59
|
+
self.clearCacheOnEval = clearCacheOnEval
|
|
60
|
+
self.evalBetweenPhases = evalBetweenPhases
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// MARK: - Presets
|
|
64
|
+
|
|
65
|
+
/// Disabled - no periodic evaluation (fastest, most memory)
|
|
66
|
+
///
|
|
67
|
+
/// Use when you have plenty of RAM and want maximum speed.
|
|
68
|
+
public static let disabled = MemoryOptimizationConfig(
|
|
69
|
+
evalFrequency: 0,
|
|
70
|
+
clearCacheOnEval: false,
|
|
71
|
+
evalBetweenPhases: false
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
/// Light - evaluate every 16 blocks
|
|
75
|
+
///
|
|
76
|
+
/// Minimal impact on speed with some memory savings.
|
|
77
|
+
public static let light = MemoryOptimizationConfig(
|
|
78
|
+
evalFrequency: 16,
|
|
79
|
+
clearCacheOnEval: false,
|
|
80
|
+
evalBetweenPhases: true
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
/// Moderate - evaluate every 8 blocks (recommended default)
|
|
84
|
+
///
|
|
85
|
+
/// Good balance between speed and memory usage.
|
|
86
|
+
public static let moderate = MemoryOptimizationConfig(
|
|
87
|
+
evalFrequency: 8,
|
|
88
|
+
clearCacheOnEval: false,
|
|
89
|
+
evalBetweenPhases: true
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
/// Aggressive - evaluate every 4 blocks with cache clearing
|
|
93
|
+
///
|
|
94
|
+
/// Use when running low on memory. Slower but uses significantly less RAM.
|
|
95
|
+
public static let aggressive = MemoryOptimizationConfig(
|
|
96
|
+
evalFrequency: 4,
|
|
97
|
+
clearCacheOnEval: true,
|
|
98
|
+
evalBetweenPhases: true
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
/// Ultra low memory - evaluate every 2 blocks with cache clearing
|
|
102
|
+
///
|
|
103
|
+
/// Maximum memory savings at significant speed cost.
|
|
104
|
+
/// Use only if other presets cause out-of-memory errors.
|
|
105
|
+
public static let ultraLowMemory = MemoryOptimizationConfig(
|
|
106
|
+
evalFrequency: 2,
|
|
107
|
+
clearCacheOnEval: true,
|
|
108
|
+
evalBetweenPhases: true
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// MARK: - Description
|
|
113
|
+
|
|
114
|
+
extension MemoryOptimizationConfig: CustomStringConvertible {
|
|
115
|
+
public var description: String {
|
|
116
|
+
if evalFrequency == 0 && !evalBetweenPhases {
|
|
117
|
+
return "MemoryOptimization(disabled)"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
var parts: [String] = []
|
|
121
|
+
if evalFrequency > 0 {
|
|
122
|
+
parts.append("evalEvery: \(evalFrequency)")
|
|
123
|
+
}
|
|
124
|
+
if clearCacheOnEval {
|
|
125
|
+
parts.append("clearCache: true")
|
|
126
|
+
}
|
|
127
|
+
if evalBetweenPhases {
|
|
128
|
+
parts.append("evalBetweenPhases: true")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return "MemoryOptimization(\(parts.joined(separator: ", ")))"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// MARK: - Recommendation
|
|
136
|
+
|
|
137
|
+
extension MemoryOptimizationConfig {
|
|
138
|
+
|
|
139
|
+
/// Get recommended configuration based on available RAM
|
|
140
|
+
///
|
|
141
|
+
/// - Parameter ramGB: System RAM in gigabytes
|
|
142
|
+
/// - Returns: Recommended memory optimization preset
|
|
143
|
+
public static func recommended(forRAMGB ramGB: Int) -> MemoryOptimizationConfig {
|
|
144
|
+
switch ramGB {
|
|
145
|
+
case 0..<32:
|
|
146
|
+
return .ultraLowMemory
|
|
147
|
+
case 32..<64:
|
|
148
|
+
return .aggressive
|
|
149
|
+
case 64..<96:
|
|
150
|
+
return .moderate
|
|
151
|
+
case 96..<128:
|
|
152
|
+
return .light
|
|
153
|
+
default:
|
|
154
|
+
return .disabled
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|