Skip to content

Commit 0665b57

Browse files
committed
Fix Swift 6.4 build errors from state handler refactor
Two issues introduced by apple#132 on the current toolchain: 1. StateHandler+MTLBuffer.swift: insertAll(into: inout AsyncMutableViews) triggers lifetime-dependent-variable-escapes-scope. Fixed with _overrideLifetime(views, borrowing: self) after each insert — this tells the compiler the views' lifetime is tied to self (which owns the MTLBuffers backing the stored pointers), not to the loop-local AsyncMutableValue. 2. CoreAISequentialEngine.swift: Dead code referencing removed properties (keyCache, valueCache, currentKVCapacity, keyCacheDescriptor, valueCacheDescriptor). Deleted ensureKVCapacity(), copyCache(), and zeroFill() — all superseded by kvCache: SyncStateHandler.
1 parent 6329412 commit 0665b57

2 files changed

Lines changed: 2 additions & 78 deletions

File tree

swift/Sources/CoreAILanguageModels/Handlers/StateHandler+MTLBuffer.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ public struct FixedMTLBufferState {
4949
}
5050

5151
/// Insert all states into AsyncMutableViews for pipelined encoding.
52-
public func insertAll(into views: inout InferenceFunction.AsyncMutableViews) {
52+
func insertAll(into views: inout InferenceFunction.AsyncMutableViews) {
5353
for (name, buffer, scalarType, shape, strides) in bindings {
5454
var value = unsafe InferenceFunction.AsyncMutableValue(
5555
unsafeBuffer: buffer, byteOffset: 0,
5656
scalarType: scalarType, shape: shape, strides: strides)
5757
views.insert(&value, for: name)
58+
views = unsafe _overrideLifetime(views, borrowing: self)
5859
}
5960
}
6061

swift/Sources/CoreAILanguageModels/InferenceEngines/CoreAISequentialEngine.swift

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -475,84 +475,7 @@ public final class CoreAISequentialEngine: InferenceEngine, @unchecked Sendable
475475
cleanupSpan.end()
476476
}
477477

478-
// MARK: - KV Cache (dynamic growth)
479-
480-
private func ensureKVCapacity(forContextLength needed: Int) throws {
481-
guard needed > currentKVCapacity else { return }
482-
guard needed <= config.maxContextLength else {
483-
throw InferenceRuntimeError.invalidState(
484-
"Context length \(needed) exceeds maximum \(config.maxContextLength)")
485-
}
486-
487-
var newCapacity = currentKVCapacity
488-
while newCapacity < needed { newCapacity *= 2 }
489-
newCapacity = min(newCapacity, config.maxContextLength)
490-
491-
let resolvedKeyDesc = keyCacheDescriptor.resolvingDynamicDimensions(
492-
keyCacheDescriptor.shape.map { $0 < 0 ? newCapacity : $0 })
493-
let resolvedValueDesc = valueCacheDescriptor.resolvingDynamicDimensions(
494-
valueCacheDescriptor.shape.map { $0 < 0 ? newCapacity : $0 })
495-
496-
var newKeyCache = NDArray(descriptor: resolvedKeyDesc)
497-
var newValueCache = NDArray(descriptor: resolvedValueDesc)
498-
_ = newKeyCache.mutableRawView()
499-
_ = newValueCache.mutableRawView()
500-
501-
try Self.copyCache(from: keyCache, to: &newKeyCache)
502-
try Self.copyCache(from: valueCache, to: &newValueCache)
503-
504-
CLILogger.log("KV cache grew: \(currentKVCapacity)\(newCapacity)")
505-
keyCache = newKeyCache
506-
valueCache = newValueCache
507-
currentKVCapacity = newCapacity
508-
}
509-
510-
private static func copyCache(from source: NDArray, to destination: inout NDArray) throws {
511-
let srcShape = source.shape
512-
let dstShape = destination.shape
513-
guard let headDim = srcShape.last else {
514-
throw InferenceRuntimeError.invalidState("KV cache has empty shape — cannot copy")
515-
}
516-
let seqDim = KVCacheFactory.detectSequenceDim(shape: srcShape)
517-
518-
// Number of independent blocks before the sequence dimension (L * B * H or B * H)
519-
let numBlocks = srcShape[..<seqDim].reduce(1, *)
520-
let oldSeqLen = srcShape[seqDim]
521-
let copySize = oldSeqLen * headDim
522-
523-
// Strides in elements for the sequence block
524-
let srcBlockStride = srcShape[seqDim...].reduce(1, *) // S_old * D
525-
let dstBlockStride = dstShape[seqDim...].reduce(1, *) // S_new * D
526-
527-
source.view(as: LogitsScalarType.self).withUnsafePointer { srcPtr, _, _ in
528-
let dstView = destination.mutableView(as: LogitsScalarType.self)
529-
dstView.withUnsafeMutablePointer { dstPtr, _, _ in
530-
for block in 0..<numBlocks {
531-
let srcOff = block * srcBlockStride
532-
let dstOff = block * dstBlockStride
533-
dstPtr.advanced(by: dstOff).update(
534-
from: srcPtr.advanced(by: srcOff), count: copySize)
535-
}
536-
}
537-
}
538-
}
539-
540478
// MARK: - Helpers
541-
542-
private func zeroFill(_ array: inout NDArray) {
543-
let count = array.shape.reduce(1, *)
544-
let view = array.mutableView(as: LogitsScalarType.self)
545-
// Inlined constant write — under -Onone, fillNDArray's
546-
// `(Int) -> LogitsScalarType` closure is invoked per element (no inlining),
547-
// which made zeroing the KV cache (~14.7M elements for a 32K-context
548-
// Qwen3) take ~6 seconds per `reset()`. Direct loop keeps this in
549-
// the few-ms range even unoptimized; under -O it lowers to memset.
550-
view.withUnsafeMutablePointer { ptr, _, _ in
551-
for i in 0..<count {
552-
ptr[i] = 0
553-
}
554-
}
555-
}
556479
}
557480

558481
extension CoreAISequentialEngine {

0 commit comments

Comments
 (0)