From dff44fa20edbaf7ee2d2e3095151ae8135c40d67 Mon Sep 17 00:00:00 2001 From: Michal Harakal Date: Wed, 26 Aug 2026 09:50:07 +0200 Subject: [PATCH] refactor(storage): delete the placement machinery that decided nothing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The @Place/@Weights annotations were read by nothing — the KDoc claim that "the MemoryPlanner reads these annotations" was false. The tensor.storage.MemoryPlanner itself had one consumer: an ExecutionContext property that built a fresh instance on every read and was itself never read. StorageSpec was deprecated with no callers. Placement.Residency's single non-test read sat on that deprecated path. All of these answered the placement question at the wrong site, and SKEEP-003 already scheduled them for deletion. Lifetime stays with ScopeKind, weight staging with WeightForm.WeightResidency; the replacement decision-maker (AllocationResolver) lands separately. Placement itself stays — the KV cache stores carry it — as do @KvCache/@KvCacheBypass, which moved to KvCacheAnnotations.kt. Closes #1142. Co-Authored-By: Claude Fable 5 --- .../api/jvm/skainet-backend-cpu.api | 1 - .../api/jvm/skainet-compile-dag.api | 2 - .../StorageAwareSafeTensorsLoaderTest.kt | 2 - .../api/jvm/skainet-lang-core.api | 96 +---------- .../sk/ainet/context/ExecutionContext.kt | 4 - .../ops/turboquant/TurboQuantPresets.kt | 7 +- ...ntAnnotations.kt => KvCacheAnnotations.kt} | 46 ------ .../ainet/lang/tensor/storage/KvCacheStore.kt | 2 +- .../lang/tensor/storage/MemoryPlanner.kt | 95 ----------- .../sk/ainet/lang/tensor/storage/Placement.kt | 21 +-- .../ainet/lang/tensor/storage/StorageSpec.kt | 108 ------------- .../ainet/lang/memory/AllocationSpecTest.kt | 21 ++- .../tensor/storage/AcceptanceCriteriaTest.kt | 20 --- .../tensor/storage/LogicalDTypeBridgeTest.kt | 6 - .../lang/tensor/storage/MemoryPlannerTest.kt | 150 ------------------ .../storage/TensorStorageContractTest.kt | 3 - 16 files changed, 25 insertions(+), 559 deletions(-) rename skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/{PlacementAnnotations.kt => KvCacheAnnotations.kt} (59%) delete mode 100644 skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/MemoryPlanner.kt delete mode 100644 skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/StorageSpec.kt delete mode 100644 skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/MemoryPlannerTest.kt diff --git a/skainet-backends/skainet-backend-cpu/api/jvm/skainet-backend-cpu.api b/skainet-backends/skainet-backend-cpu/api/jvm/skainet-backend-cpu.api index b6594f7a7..c89718f3a 100644 --- a/skainet-backends/skainet-backend-cpu/api/jvm/skainet-backend-cpu.api +++ b/skainet-backends/skainet-backend-cpu/api/jvm/skainet-backend-cpu.api @@ -17,7 +17,6 @@ public final class sk/ainet/context/DirectCpuExecutionContext : sk/ainet/context public fun getHooks ()Lsk/ainet/lang/nn/hooks/ForwardHooks; public fun getInTraining ()Z public fun getMemoryInfo ()Lsk/ainet/context/MemoryInfo; - public fun getMemoryPlanner ()Lsk/ainet/lang/tensor/storage/MemoryPlanner; public fun getMemoryScope ()Lsk/ainet/lang/memory/Scope; public fun getMemoryTracker ()Lsk/ainet/lang/tensor/storage/MemoryTracker; public fun getObservers ()Lsk/ainet/context/ExecutionObserverRegistry; diff --git a/skainet-compile/skainet-compile-dag/api/jvm/skainet-compile-dag.api b/skainet-compile/skainet-compile-dag/api/jvm/skainet-compile-dag.api index b314e1db8..e8666ad5a 100644 --- a/skainet-compile/skainet-compile-dag/api/jvm/skainet-compile-dag.api +++ b/skainet-compile/skainet-compile-dag/api/jvm/skainet-compile-dag.api @@ -172,7 +172,6 @@ public final class sk/ainet/lang/graph/DefaultGraphExecutionContext : sk/ainet/l public fun getHooks ()Lsk/ainet/lang/nn/hooks/ForwardHooks; public fun getInTraining ()Z public fun getMemoryInfo ()Lsk/ainet/context/MemoryInfo; - public fun getMemoryPlanner ()Lsk/ainet/lang/tensor/storage/MemoryPlanner; public fun getMemoryScope ()Lsk/ainet/lang/memory/Scope; public fun getMemoryTracker ()Lsk/ainet/lang/tensor/storage/MemoryTracker; public fun getObservers ()Lsk/ainet/context/ExecutionObserverRegistry; @@ -449,7 +448,6 @@ public final class sk/ainet/lang/graph/exec/GraphExecutionContext$DefaultImpls { public static fun full (Lsk/ainet/lang/graph/exec/GraphExecutionContext;Lsk/ainet/lang/tensor/Shape;Lkotlin/reflect/KClass;Ljava/lang/Number;)Lsk/ainet/lang/tensor/Tensor; public static fun getHooks (Lsk/ainet/lang/graph/exec/GraphExecutionContext;)Lsk/ainet/lang/nn/hooks/ForwardHooks; public static fun getInTraining (Lsk/ainet/lang/graph/exec/GraphExecutionContext;)Z - public static fun getMemoryPlanner (Lsk/ainet/lang/graph/exec/GraphExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryPlanner; public static fun getMemoryScope (Lsk/ainet/lang/graph/exec/GraphExecutionContext;)Lsk/ainet/lang/memory/Scope; public static fun getMemoryTracker (Lsk/ainet/lang/graph/exec/GraphExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryTracker; public static fun getScratch (Lsk/ainet/lang/graph/exec/GraphExecutionContext;)Lsk/ainet/lang/tensor/scratch/ScratchPool; diff --git a/skainet-io/skainet-io-safetensors/src/commonTest/kotlin/sk/ainet/io/safetensors/StorageAwareSafeTensorsLoaderTest.kt b/skainet-io/skainet-io-safetensors/src/commonTest/kotlin/sk/ainet/io/safetensors/StorageAwareSafeTensorsLoaderTest.kt index 86a795d1c..6e66fd7ac 100644 --- a/skainet-io/skainet-io-safetensors/src/commonTest/kotlin/sk/ainet/io/safetensors/StorageAwareSafeTensorsLoaderTest.kt +++ b/skainet-io/skainet-io-safetensors/src/commonTest/kotlin/sk/ainet/io/safetensors/StorageAwareSafeTensorsLoaderTest.kt @@ -6,7 +6,6 @@ import sk.ainet.io.RandomAccessSource import sk.ainet.lang.tensor.storage.LogicalDType import sk.ainet.lang.tensor.storage.MemoryDomain import sk.ainet.lang.tensor.storage.Ownership -import sk.ainet.lang.tensor.storage.Residency import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -127,7 +126,6 @@ class StorageAwareSafeTensorsLoaderTest { assertTrue(storage.isFileBacked) assertEquals(Ownership.FILE_BACKED, storage.ownership) assertEquals(MemoryDomain.MMAP_FILE, storage.placement.domain) - assertEquals(Residency.PERSISTENT, storage.placement.residency) assertFalse(storage.isMutable) } diff --git a/skainet-lang/skainet-lang-core/api/jvm/skainet-lang-core.api b/skainet-lang/skainet-lang-core/api/jvm/skainet-lang-core.api index 5f0aea700..2257c6923 100644 --- a/skainet-lang/skainet-lang-core/api/jvm/skainet-lang-core.api +++ b/skainet-lang/skainet-lang-core/api/jvm/skainet-lang-core.api @@ -204,7 +204,6 @@ public final class sk/ainet/context/DefaultDataExecutionContext : sk/ainet/conte public fun getHooks ()Lsk/ainet/lang/nn/hooks/ForwardHooks; public fun getInTraining ()Z public fun getMemoryInfo ()Lsk/ainet/context/MemoryInfo; - public fun getMemoryPlanner ()Lsk/ainet/lang/tensor/storage/MemoryPlanner; public fun getMemoryScope ()Lsk/ainet/lang/memory/Scope; public fun getMemoryTracker ()Lsk/ainet/lang/tensor/storage/MemoryTracker; public fun getObservers ()Lsk/ainet/context/ExecutionObserverRegistry; @@ -234,7 +233,6 @@ public abstract interface class sk/ainet/context/ExecutionContext { public fun getHooks ()Lsk/ainet/lang/nn/hooks/ForwardHooks; public fun getInTraining ()Z public abstract fun getMemoryInfo ()Lsk/ainet/context/MemoryInfo; - public fun getMemoryPlanner ()Lsk/ainet/lang/tensor/storage/MemoryPlanner; public fun getMemoryScope ()Lsk/ainet/lang/memory/Scope; public fun getMemoryTracker ()Lsk/ainet/lang/tensor/storage/MemoryTracker; public abstract fun getObservers ()Lsk/ainet/context/ExecutionObserverRegistry; @@ -262,7 +260,6 @@ public final class sk/ainet/context/ExecutionContext$DefaultImpls { public static fun full (Lsk/ainet/context/ExecutionContext;Lsk/ainet/lang/tensor/Shape;Lkotlin/reflect/KClass;Ljava/lang/Number;)Lsk/ainet/lang/tensor/Tensor; public static fun getHooks (Lsk/ainet/context/ExecutionContext;)Lsk/ainet/lang/nn/hooks/ForwardHooks; public static fun getInTraining (Lsk/ainet/context/ExecutionContext;)Z - public static fun getMemoryPlanner (Lsk/ainet/context/ExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryPlanner; public static fun getMemoryScope (Lsk/ainet/context/ExecutionContext;)Lsk/ainet/lang/memory/Scope; public static fun getMemoryTracker (Lsk/ainet/context/ExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryTracker; public static fun getScratch (Lsk/ainet/context/ExecutionContext;)Lsk/ainet/lang/tensor/scratch/ScratchPool; @@ -364,7 +361,6 @@ public final class sk/ainet/context/PhaseOverridingExecutionContext : sk/ainet/c public fun getHooks ()Lsk/ainet/lang/nn/hooks/ForwardHooks; public fun getInTraining ()Z public fun getMemoryInfo ()Lsk/ainet/context/MemoryInfo; - public fun getMemoryPlanner ()Lsk/ainet/lang/tensor/storage/MemoryPlanner; public fun getMemoryScope ()Lsk/ainet/lang/memory/Scope; public fun getMemoryTracker ()Lsk/ainet/lang/tensor/storage/MemoryTracker; public fun getObservers ()Lsk/ainet/context/ExecutionObserverRegistry; @@ -414,7 +410,6 @@ public final class sk/ainet/context/TrainingExecutionContext$DefaultImpls { public static fun full (Lsk/ainet/context/TrainingExecutionContext;Lsk/ainet/lang/tensor/Shape;Lkotlin/reflect/KClass;Ljava/lang/Number;)Lsk/ainet/lang/tensor/Tensor; public static fun getHooks (Lsk/ainet/context/TrainingExecutionContext;)Lsk/ainet/lang/nn/hooks/ForwardHooks; public static fun getInTraining (Lsk/ainet/context/TrainingExecutionContext;)Z - public static fun getMemoryPlanner (Lsk/ainet/context/TrainingExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryPlanner; public static fun getMemoryScope (Lsk/ainet/context/TrainingExecutionContext;)Lsk/ainet/lang/memory/Scope; public static fun getMemoryTracker (Lsk/ainet/context/TrainingExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryTracker; public static fun getScratch (Lsk/ainet/context/TrainingExecutionContext;)Lsk/ainet/lang/tensor/scratch/ScratchPool; @@ -2375,7 +2370,6 @@ public final class sk/ainet/lang/nn/DefaultNeuralNetworkExecutionContext : sk/ai public fun getHooks ()Lsk/ainet/lang/nn/hooks/ForwardHooks; public fun getInTraining ()Z public fun getMemoryInfo ()Lsk/ainet/context/MemoryInfo; - public fun getMemoryPlanner ()Lsk/ainet/lang/tensor/storage/MemoryPlanner; public fun getMemoryScope ()Lsk/ainet/lang/memory/Scope; public fun getMemoryTracker ()Lsk/ainet/lang/tensor/storage/MemoryTracker; public fun getObservers ()Lsk/ainet/context/ExecutionObserverRegistry; @@ -2712,7 +2706,6 @@ public final class sk/ainet/lang/nn/NeuralNetworkExecutionContext$DefaultImpls { public static fun full (Lsk/ainet/lang/nn/NeuralNetworkExecutionContext;Lsk/ainet/lang/tensor/Shape;Lkotlin/reflect/KClass;Ljava/lang/Number;)Lsk/ainet/lang/tensor/Tensor; public static fun getHooks (Lsk/ainet/lang/nn/NeuralNetworkExecutionContext;)Lsk/ainet/lang/nn/hooks/ForwardHooks; public static fun getInTraining (Lsk/ainet/lang/nn/NeuralNetworkExecutionContext;)Z - public static fun getMemoryPlanner (Lsk/ainet/lang/nn/NeuralNetworkExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryPlanner; public static fun getMemoryScope (Lsk/ainet/lang/nn/NeuralNetworkExecutionContext;)Lsk/ainet/lang/memory/Scope; public static fun getMemoryTracker (Lsk/ainet/lang/nn/NeuralNetworkExecutionContext;)Lsk/ainet/lang/tensor/storage/MemoryTracker; public static fun getScratch (Lsk/ainet/lang/nn/NeuralNetworkExecutionContext;)Lsk/ainet/lang/tensor/scratch/ScratchPool; @@ -7150,15 +7143,6 @@ public final class sk/ainet/lang/tensor/storage/MemoryDomain : java/lang/Enum { public static fun values ()[Lsk/ainet/lang/tensor/storage/MemoryDomain; } -public final class sk/ainet/lang/tensor/storage/MemoryPlanner { - public fun ()V - public fun (Ljava/util/Set;)V - public synthetic fun (Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun resolve (Lsk/ainet/lang/tensor/storage/Placement;)Lsk/ainet/lang/tensor/storage/ResolvedPlacement; - public final fun suggestActivationPlacement ()Lsk/ainet/lang/tensor/storage/Placement; - public final fun suggestWeightPlacement (Z)Lsk/ainet/lang/tensor/storage/Placement; -} - public final class sk/ainet/lang/tensor/storage/MemoryTracker { public fun ()V public final fun clear ()V @@ -7210,30 +7194,22 @@ public final class sk/ainet/lang/tensor/storage/PackedBlockStorage$DefaultImpls public static synthetic fun toTensorStorage$default (Lsk/ainet/lang/tensor/storage/PackedBlockStorage;Lsk/ainet/lang/types/DType;Lsk/ainet/lang/tensor/storage/Placement;ILjava/lang/Object;)Lsk/ainet/lang/tensor/storage/TensorStorage; } -public abstract interface annotation class sk/ainet/lang/tensor/storage/Place : java/lang/annotation/Annotation { - public abstract fun device ()Lsk/ainet/lang/tensor/storage/DeviceKind; - public abstract fun memory ()Lsk/ainet/lang/tensor/storage/MemoryDomain; - public abstract fun requirement ()Lsk/ainet/lang/tensor/storage/Requirement; -} - public final class sk/ainet/lang/tensor/storage/Placement { public static final field Companion Lsk/ainet/lang/tensor/storage/Placement$Companion; public fun ()V - public fun (Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Residency;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;)V - public synthetic fun (Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Residency;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;)V + public synthetic fun (Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lsk/ainet/lang/tensor/storage/DeviceKind; public final fun component2 ()Lsk/ainet/lang/tensor/storage/MemoryDomain; - public final fun component3 ()Lsk/ainet/lang/tensor/storage/Residency; - public final fun component4 ()Lsk/ainet/lang/tensor/storage/Requirement; - public final fun component5 ()Lsk/ainet/lang/tensor/storage/DeviceKind; - public final fun copy (Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Residency;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;)Lsk/ainet/lang/tensor/storage/Placement; - public static synthetic fun copy$default (Lsk/ainet/lang/tensor/storage/Placement;Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Residency;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;ILjava/lang/Object;)Lsk/ainet/lang/tensor/storage/Placement; + public final fun component3 ()Lsk/ainet/lang/tensor/storage/Requirement; + public final fun component4 ()Lsk/ainet/lang/tensor/storage/DeviceKind; + public final fun copy (Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;)Lsk/ainet/lang/tensor/storage/Placement; + public static synthetic fun copy$default (Lsk/ainet/lang/tensor/storage/Placement;Lsk/ainet/lang/tensor/storage/DeviceKind;Lsk/ainet/lang/tensor/storage/MemoryDomain;Lsk/ainet/lang/tensor/storage/Requirement;Lsk/ainet/lang/tensor/storage/DeviceKind;ILjava/lang/Object;)Lsk/ainet/lang/tensor/storage/Placement; public fun equals (Ljava/lang/Object;)Z public final fun getDevice ()Lsk/ainet/lang/tensor/storage/DeviceKind; public final fun getDomain ()Lsk/ainet/lang/tensor/storage/MemoryDomain; public final fun getFallback ()Lsk/ainet/lang/tensor/storage/DeviceKind; public final fun getRequirement ()Lsk/ainet/lang/tensor/storage/Requirement; - public final fun getResidency ()Lsk/ainet/lang/tensor/storage/Residency; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -7244,10 +7220,6 @@ public final class sk/ainet/lang/tensor/storage/Placement$Companion { public final fun getMMAP_WEIGHTS ()Lsk/ainet/lang/tensor/storage/Placement; } -public final class sk/ainet/lang/tensor/storage/PlacementUnavailableException : java/lang/RuntimeException { - public fun (Ljava/lang/String;)V -} - public final class sk/ainet/lang/tensor/storage/Requirement : java/lang/Enum { public static final field PREFERRED Lsk/ainet/lang/tensor/storage/Requirement; public static final field REQUIRED Lsk/ainet/lang/tensor/storage/Requirement; @@ -7256,27 +7228,6 @@ public final class sk/ainet/lang/tensor/storage/Requirement : java/lang/Enum { public static fun values ()[Lsk/ainet/lang/tensor/storage/Requirement; } -public final class sk/ainet/lang/tensor/storage/Residency : java/lang/Enum { - public static final field PERSISTENT Lsk/ainet/lang/tensor/storage/Residency; - public static final field TRANSIENT Lsk/ainet/lang/tensor/storage/Residency; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public static fun valueOf (Ljava/lang/String;)Lsk/ainet/lang/tensor/storage/Residency; - public static fun values ()[Lsk/ainet/lang/tensor/storage/Residency; -} - -public final class sk/ainet/lang/tensor/storage/ResolvedPlacement { - public fun (Lsk/ainet/lang/tensor/storage/Placement;Z)V - public final fun component1 ()Lsk/ainet/lang/tensor/storage/Placement; - public final fun component2 ()Z - public final fun copy (Lsk/ainet/lang/tensor/storage/Placement;Z)Lsk/ainet/lang/tensor/storage/ResolvedPlacement; - public static synthetic fun copy$default (Lsk/ainet/lang/tensor/storage/ResolvedPlacement;Lsk/ainet/lang/tensor/storage/Placement;ZILjava/lang/Object;)Lsk/ainet/lang/tensor/storage/ResolvedPlacement; - public fun equals (Ljava/lang/Object;)Z - public final fun getActual ()Lsk/ainet/lang/tensor/storage/Placement; - public final fun getUsedFallback ()Z - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - public final class sk/ainet/lang/tensor/storage/StorageMemoryReport { public fun (Lsk/ainet/lang/tensor/Shape;Lsk/ainet/lang/tensor/storage/LogicalDType;Lsk/ainet/lang/tensor/storage/TensorEncoding;Lsk/ainet/lang/tensor/storage/Ownership;Lsk/ainet/lang/tensor/storage/Placement;JJZZZ)V public final fun component1 ()Lsk/ainet/lang/tensor/Shape; @@ -7308,37 +7259,6 @@ public final class sk/ainet/lang/tensor/storage/StorageMemoryReport { public fun toString ()Ljava/lang/String; } -public final class sk/ainet/lang/tensor/storage/StorageSpec { - public static final field Companion Lsk/ainet/lang/tensor/storage/StorageSpec$Companion; - public fun (Lsk/ainet/lang/tensor/storage/LogicalDType;Lsk/ainet/lang/tensor/storage/TensorEncoding;Lsk/ainet/lang/tensor/storage/Ownership;Lsk/ainet/lang/tensor/storage/Placement;)V - public synthetic fun (Lsk/ainet/lang/tensor/storage/LogicalDType;Lsk/ainet/lang/tensor/storage/TensorEncoding;Lsk/ainet/lang/tensor/storage/Ownership;Lsk/ainet/lang/tensor/storage/Placement;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Lsk/ainet/lang/tensor/storage/LogicalDType; - public final fun component2 ()Lsk/ainet/lang/tensor/storage/TensorEncoding; - public final fun component3 ()Lsk/ainet/lang/tensor/storage/Ownership; - public final fun component4 ()Lsk/ainet/lang/tensor/storage/Placement; - public final fun copy (Lsk/ainet/lang/tensor/storage/LogicalDType;Lsk/ainet/lang/tensor/storage/TensorEncoding;Lsk/ainet/lang/tensor/storage/Ownership;Lsk/ainet/lang/tensor/storage/Placement;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public static synthetic fun copy$default (Lsk/ainet/lang/tensor/storage/StorageSpec;Lsk/ainet/lang/tensor/storage/LogicalDType;Lsk/ainet/lang/tensor/storage/TensorEncoding;Lsk/ainet/lang/tensor/storage/Ownership;Lsk/ainet/lang/tensor/storage/Placement;ILjava/lang/Object;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public fun equals (Ljava/lang/Object;)Z - public final fun getDtype ()Lsk/ainet/lang/types/DType; - public final fun getEncoding ()Lsk/ainet/lang/tensor/storage/TensorEncoding; - public final fun getLogicalType ()Lsk/ainet/lang/tensor/storage/LogicalDType; - public final fun getOwnership ()Lsk/ainet/lang/tensor/storage/Ownership; - public final fun getPlacement ()Lsk/ainet/lang/tensor/storage/Placement; - public fun hashCode ()I - public final fun toAllocationSpec (J)Lsk/ainet/lang/memory/AllocationSpec; - public fun toString ()Ljava/lang/String; -} - -public final class sk/ainet/lang/tensor/storage/StorageSpec$Companion { - public final fun borrowed (Lsk/ainet/lang/types/DType;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public final fun fromDType (Lsk/ainet/lang/types/DType;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public final fun mmapWeights (Lsk/ainet/lang/types/DType;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public final fun q4k (Lsk/ainet/lang/tensor/storage/Placement;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public static synthetic fun q4k$default (Lsk/ainet/lang/tensor/storage/StorageSpec$Companion;Lsk/ainet/lang/tensor/storage/Placement;ILjava/lang/Object;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public final fun q80 (Lsk/ainet/lang/tensor/storage/Placement;)Lsk/ainet/lang/tensor/storage/StorageSpec; - public static synthetic fun q80$default (Lsk/ainet/lang/tensor/storage/StorageSpec$Companion;Lsk/ainet/lang/tensor/storage/Placement;ILjava/lang/Object;)Lsk/ainet/lang/tensor/storage/StorageSpec; -} - public abstract interface class sk/ainet/lang/tensor/storage/TensorEncoding { public abstract fun getName ()Ljava/lang/String; public abstract fun physicalBytes (J)Ljava/lang/Long; @@ -7638,10 +7558,6 @@ public final class sk/ainet/lang/tensor/storage/TurboQuantKvCacheStore : sk/aine public fun valueWindow (III)Lsk/ainet/lang/memory/WindowedKV; } -public abstract interface annotation class sk/ainet/lang/tensor/storage/Weights : java/lang/annotation/Annotation { - public abstract fun memory ()Lsk/ainet/lang/tensor/storage/MemoryDomain; -} - public final class sk/ainet/lang/trace/CompositeSink : sk/ainet/lang/trace/OpSink { public fun (Ljava/util/List;)V public fun onOpExecuted (Lsk/ainet/lang/trace/OpTrace;)V diff --git a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/context/ExecutionContext.kt b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/context/ExecutionContext.kt index 5ba678385..313f8172c 100644 --- a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/context/ExecutionContext.kt +++ b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/context/ExecutionContext.kt @@ -8,7 +8,6 @@ import sk.ainet.lang.tensor.operators.OpsBoundTensor import sk.ainet.lang.tensor.ops.TensorOps import sk.ainet.lang.tensor.scratch.NoopScratchPool import sk.ainet.lang.tensor.scratch.ScratchPool -import sk.ainet.lang.tensor.storage.MemoryPlanner import sk.ainet.lang.tensor.storage.MemoryTracker import sk.ainet.lang.types.DType import kotlin.reflect.KClass @@ -187,9 +186,6 @@ public interface ExecutionContext { public val memoryInfo: MemoryInfo public val executionStats: ExecutionStats - /** Memory planner for resolving placement intents. Default: CPU-only. */ - public val memoryPlanner: MemoryPlanner get() = MemoryPlanner() - /** Memory tracker for observability and copy tracing. Default: no-op (not tracking). */ public val memoryTracker: MemoryTracker? get() = null } diff --git a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/ops/turboquant/TurboQuantPresets.kt b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/ops/turboquant/TurboQuantPresets.kt index 7be97d2fa..07ec82d9f 100644 --- a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/ops/turboquant/TurboQuantPresets.kt +++ b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/ops/turboquant/TurboQuantPresets.kt @@ -2,7 +2,6 @@ package sk.ainet.lang.tensor.ops.turboquant import sk.ainet.lang.tensor.storage.KvCacheConfig import sk.ainet.lang.tensor.storage.Placement -import sk.ainet.lang.tensor.storage.Residency import sk.ainet.lang.tensor.storage.TensorEncoding /** @@ -39,7 +38,7 @@ public object TurboQuantPresets { maxSeqLen = maxSeqLen, keyEncoding = TensorEncoding.Q8_0, valueEncoding = TensorEncoding.TurboQuantPolar(bitsPerElement = 4), - placement = Placement.CPU_HEAP.copy(residency = Residency.PERSISTENT) + placement = Placement.CPU_HEAP ), keyQuantConfig = null, // Q8_0 uses standard quantization, not TurboQuant valueQuantConfig = TurboQuantConfig.polarOnly(bits = 4) @@ -65,7 +64,7 @@ public object TurboQuantPresets { maxSeqLen = maxSeqLen, keyEncoding = TensorEncoding.TurboQuantPolar(bitsPerElement = 4), valueEncoding = TensorEncoding.TurboQuantPolar(bitsPerElement = 4), - placement = Placement.CPU_HEAP.copy(residency = Residency.PERSISTENT) + placement = Placement.CPU_HEAP ), keyQuantConfig = TurboQuantConfig.polarOnly(bits = 4), valueQuantConfig = TurboQuantConfig.polarOnly(bits = 4) @@ -92,7 +91,7 @@ public object TurboQuantPresets { maxSeqLen = maxSeqLen, keyEncoding = TensorEncoding.TurboQuantPolar(bitsPerElement = 3), valueEncoding = TensorEncoding.TurboQuantPolar(bitsPerElement = 3), - placement = Placement.CPU_HEAP.copy(residency = Residency.PERSISTENT) + placement = Placement.CPU_HEAP ), keyQuantConfig = TurboQuantConfig.polarOnly(bits = 3), valueQuantConfig = TurboQuantConfig.polarOnly(bits = 3) diff --git a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/PlacementAnnotations.kt b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/KvCacheAnnotations.kt similarity index 59% rename from skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/PlacementAnnotations.kt rename to skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/KvCacheAnnotations.kt index 5ac0880ec..9c51835db 100644 --- a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/PlacementAnnotations.kt +++ b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/KvCacheAnnotations.kt @@ -1,51 +1,5 @@ package sk.ainet.lang.tensor.storage -/** - * Declares placement intent for a tensor parameter or property. - * - * The [MemoryPlanner] reads these annotations (via reflection or codegen) - * to decide where tensors should be allocated. This expresses *intent*, - * not a hard guarantee — the planner may fall back if the target is - * unavailable and [requirement] is [Requirement.PREFERRED]. - * - * Example: - * ```kotlin - * @Place(device = DeviceKind.GPU, memory = MemoryDomain.DEVICE_LOCAL) - * val projectionWeight: Tensor - * ``` - */ -@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD) -@Retention(AnnotationRetention.RUNTIME) -public annotation class Place( - val device: DeviceKind = DeviceKind.AUTO, - val memory: MemoryDomain = MemoryDomain.HOST_HEAP, - val requirement: Requirement = Requirement.PREFERRED -) - -/** - * Marks a tensor as an immutable weight that should be file-backed - * (memory-mapped) when possible. - * - * Equivalent to `@Place(device = CPU, memory = MMAP_FILE)` with - * [Residency.PERSISTENT]. The planner treats these tensors as - * read-only and long-lived, preferring OS-paged file access over - * heap allocation. - * - * Example: - * ```kotlin - * @Weights - * val embeddings: Tensor - * - * @Weights(memory = MemoryDomain.HOST_HEAP) // force heap for small weights - * val biasVector: Tensor - * ``` - */ -@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD) -@Retention(AnnotationRetention.RUNTIME) -public annotation class Weights( - val memory: MemoryDomain = MemoryDomain.MMAP_FILE -) - /** * Configures TurboQuant KV-cache compression for an attention layer. * diff --git a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/KvCacheStore.kt b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/KvCacheStore.kt index 748066784..52496f494 100644 --- a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/KvCacheStore.kt +++ b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/KvCacheStore.kt @@ -300,7 +300,7 @@ public data class KvCacheConfig( val maxSeqLen: Int, val keyEncoding: TensorEncoding = TensorEncoding.Dense(4), val valueEncoding: TensorEncoding = TensorEncoding.Dense(4), - val placement: Placement = Placement.CPU_HEAP.copy(residency = Residency.PERSISTENT), + val placement: Placement = Placement.CPU_HEAP, /** * The dtype the key ring stores; with [keyEncoding] it forms the store's `keyFormat` (#1077). * `FP32` is what the dense store has always held; `BF16`/`FP16` halve the ring. diff --git a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/MemoryPlanner.kt b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/MemoryPlanner.kt deleted file mode 100644 index 281043230..000000000 --- a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/MemoryPlanner.kt +++ /dev/null @@ -1,95 +0,0 @@ -package sk.ainet.lang.tensor.storage - -/** - * Resolves [Placement] intent into concrete buffer allocation decisions. - * - * The planner inspects available backends and decides: - * - Where a tensor should actually live (device + memory domain) - * - Whether a fallback is needed (e.g. GPU not available → CPU) - * - Whether immutable weights should be file-backed vs heap-copied - * - * Currently only the CPU backend is wired in, so the planner always - * resolves to CPU/HOST_HEAP or CPU/MMAP_FILE. GPU/NPU resolution - * will be added when those backends ship. - */ -public class MemoryPlanner( - private val availableDevices: Set = setOf(DeviceKind.CPU) -) { - - /** - * Resolve a placement intent to an actual placement that can be satisfied. - * - * @param requested The user/loader-requested placement - * @return A [ResolvedPlacement] with the actual target and whether fallback was used - */ - public fun resolve(requested: Placement): ResolvedPlacement { - val targetDevice = if (requested.device == DeviceKind.AUTO) { - bestAvailableDevice() - } else { - requested.device - } - - return if (targetDevice in availableDevices) { - ResolvedPlacement( - actual = requested.copy(device = targetDevice), - usedFallback = false - ) - } else if (requested.requirement == Requirement.REQUIRED) { - throw PlacementUnavailableException( - "Required device $targetDevice is not available. Available: $availableDevices" - ) - } else { - // Fallback to the placement's specified fallback device - val fallbackDevice = if (requested.fallback in availableDevices) { - requested.fallback - } else { - DeviceKind.CPU - } - ResolvedPlacement( - actual = Placement( - device = fallbackDevice, - domain = fallbackDomain(requested.domain, fallbackDevice), - residency = requested.residency, - requirement = requested.requirement, - fallback = requested.fallback - ), - usedFallback = true - ) - } - } - - /** - * Suggest the best placement for a weight tensor. - * File-backed if persistent, heap if transient. - */ - public fun suggestWeightPlacement(isFileBacked: Boolean): Placement { - return if (isFileBacked) Placement.MMAP_WEIGHTS else Placement.CPU_HEAP.copy(residency = Residency.PERSISTENT) - } - - /** - * Suggest placement for a mutable activation/intermediate tensor. - */ - public fun suggestActivationPlacement(): Placement = Placement.CPU_HEAP - - private fun bestAvailableDevice(): DeviceKind = when { - DeviceKind.GPU in availableDevices -> DeviceKind.GPU - DeviceKind.NPU in availableDevices -> DeviceKind.NPU - else -> DeviceKind.CPU - } - - private fun fallbackDomain(requested: MemoryDomain, device: DeviceKind): MemoryDomain { - // If falling back to CPU, translate device-specific domains to host domains - return when { - device == DeviceKind.CPU && requested == MemoryDomain.DEVICE_LOCAL -> MemoryDomain.HOST_HEAP - device == DeviceKind.CPU && requested == MemoryDomain.UNIFIED -> MemoryDomain.HOST_HEAP - else -> requested - } - } -} - -public data class ResolvedPlacement( - val actual: Placement, - val usedFallback: Boolean -) - -public class PlacementUnavailableException(message: String) : RuntimeException(message) diff --git a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/Placement.kt b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/Placement.kt index 99100ecaf..10ed81c62 100644 --- a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/Placement.kt +++ b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/Placement.kt @@ -4,15 +4,16 @@ package sk.ainet.lang.tensor.storage * High-level placement descriptor: where a tensor lives and how the runtime * should manage it. * - * Placement is *intent* — it tells the planner what to aim for but does not - * encode backend scratch-memory details. The planner resolves placement to - * a concrete [BufferHandle] and falls back if the preferred target is - * unavailable. + * Placement is *intent* — it tells the runtime what to aim for but does not + * encode backend scratch-memory details. + * + * Lifetime is deliberately not part of placement: how long bytes live is a + * scope decision (`sk.ainet.lang.memory.ScopeKind`), and how a weight is + * staged at load is a resolver decision (`WeightForm.WeightResidency`). */ public data class Placement( val device: DeviceKind = DeviceKind.CPU, val domain: MemoryDomain = MemoryDomain.HOST_HEAP, - val residency: Residency = Residency.PERSISTENT, val requirement: Requirement = Requirement.PREFERRED, val fallback: DeviceKind = DeviceKind.CPU ) { @@ -21,7 +22,6 @@ public data class Placement( public val CPU_HEAP: Placement = Placement( device = DeviceKind.CPU, domain = MemoryDomain.HOST_HEAP, - residency = Residency.TRANSIENT, requirement = Requirement.PREFERRED ) @@ -29,7 +29,6 @@ public data class Placement( public val MMAP_WEIGHTS: Placement = Placement( device = DeviceKind.CPU, domain = MemoryDomain.MMAP_FILE, - residency = Residency.PERSISTENT, requirement = Requirement.PREFERRED ) @@ -37,7 +36,6 @@ public data class Placement( public val GPU_PREFERRED: Placement = Placement( device = DeviceKind.GPU, domain = MemoryDomain.DEVICE_LOCAL, - residency = Residency.PERSISTENT, requirement = Requirement.PREFERRED, fallback = DeviceKind.CPU ) @@ -66,13 +64,6 @@ public enum class MemoryDomain { DEVICE_LOCAL } -public enum class Residency { - /** Short-lived: activations, temporaries, intermediate results. */ - TRANSIENT, - /** Long-lived: model weights, embeddings, caches. */ - PERSISTENT -} - public enum class Requirement { /** Best-effort: fall back to [Placement.fallback] if unavailable. */ PREFERRED, diff --git a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/StorageSpec.kt b/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/StorageSpec.kt deleted file mode 100644 index 58613fb64..000000000 --- a/skainet-lang/skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/storage/StorageSpec.kt +++ /dev/null @@ -1,108 +0,0 @@ -@file:Suppress("DEPRECATION") // StorageSpec is itself deprecated and built on LogicalDType; both go at the next major - -package sk.ainet.lang.tensor.storage - -import sk.ainet.lang.memory.AllocationSpec -import sk.ainet.lang.memory.ExperimentalMemoryApi -import sk.ainet.lang.memory.Format -import sk.ainet.lang.memory.ScopeKind -import sk.ainet.lang.types.DType - -/** - * A storage specification that captures both logical type AND physical - * encoding + placement intent. This enables factory routing that goes - * beyond dtype-only decisions. - * - * [StorageSpec] replaces the pattern of routing only by [DType] (via - * [sk.ainet.lang.tensor.data.TensorFactoryRegistry]). Existing dtype-based - * lookups remain as a convenience — they build a default [StorageSpec] - * with [TensorEncoding.Dense] and [Ownership.OWNED]. - * - * Deprecated (SKEEP-003 Phase 0): never consumed by any factory; the allocation - * description is [sk.ainet.lang.memory.AllocationSpec] (`Format` + element count + - * domain + scope). Use [toAllocationSpec] to convert. Removed at the next major release. - */ -@Deprecated( - message = "StorageSpec was never consumed; describe allocations with sk.ainet.lang.memory.AllocationSpec (SKEEP-003).", - replaceWith = ReplaceWith("AllocationSpec", "sk.ainet.lang.memory.AllocationSpec"), -) -public data class StorageSpec( - val logicalType: LogicalDType, - val encoding: TensorEncoding = TensorEncoding.Dense(logicalType.sizeInBytes), - val ownership: Ownership = Ownership.OWNED, - val placement: Placement = Placement.CPU_HEAP -) { - /** The [DType] of [logicalType] (SKEEP-003 Phase 0 bridge; see [LogicalDType.toDType]). */ - val dtype: DType get() = logicalType.toDType() - - /** - * The [AllocationSpec] equivalent of this spec for [elementCount] elements: `Format(dtype, - * encoding)`, the placement's memory domain, `MODEL` scope for persistent placements and - * `AMBIENT` otherwise, mutable only when owned. - */ - @OptIn(ExperimentalMemoryApi::class) - public fun toAllocationSpec(elementCount: Long): AllocationSpec = AllocationSpec( - format = Format(dtype, encoding), - elementCount = elementCount, - domain = placement.domain, - scope = if (placement.residency == Residency.PERSISTENT) ScopeKind.MODEL else ScopeKind.AMBIENT, - mutable = ownership == Ownership.OWNED, - ) - - @Suppress("DEPRECATION") // the factories build the deprecated type on purpose - public companion object { - /** Build a default spec from a legacy DType (dense, owned, CPU heap). */ - @Deprecated("StorageSpec is deprecated; build an AllocationSpec (sk.ainet.lang.memory).") - public fun fromDType(dtype: DType): StorageSpec { - val logical = dtype.toLogicalDType() - return StorageSpec( - logicalType = logical, - encoding = TensorEncoding.Dense(logical.sizeInBytes), - ownership = Ownership.OWNED, - placement = Placement.CPU_HEAP - ) - } - - /** Spec for borrowed dense data. */ - @Deprecated("StorageSpec is deprecated; build an AllocationSpec (sk.ainet.lang.memory).") - public fun borrowed(dtype: DType): StorageSpec { - val logical = dtype.toLogicalDType() - return StorageSpec( - logicalType = logical, - encoding = TensorEncoding.Dense(logical.sizeInBytes), - ownership = Ownership.BORROWED, - placement = Placement.CPU_HEAP - ) - } - - /** Spec for Q4_K packed data. */ - @Deprecated("StorageSpec is deprecated; build an AllocationSpec (sk.ainet.lang.memory).") - public fun q4k(placement: Placement = Placement.CPU_HEAP): StorageSpec = StorageSpec( - logicalType = LogicalDType.FLOAT32, - encoding = TensorEncoding.Q4_K, - ownership = Ownership.BORROWED, - placement = placement - ) - - /** Spec for Q8_0 packed data. */ - @Deprecated("StorageSpec is deprecated; build an AllocationSpec (sk.ainet.lang.memory).") - public fun q80(placement: Placement = Placement.CPU_HEAP): StorageSpec = StorageSpec( - logicalType = LogicalDType.FLOAT32, - encoding = TensorEncoding.Q8_0, - ownership = Ownership.BORROWED, - placement = placement - ) - - /** Spec for file-backed weights. */ - @Deprecated("StorageSpec is deprecated; build an AllocationSpec (sk.ainet.lang.memory).") - public fun mmapWeights(dtype: DType): StorageSpec { - val logical = dtype.toLogicalDType() - return StorageSpec( - logicalType = logical, - encoding = TensorEncoding.Dense(logical.sizeInBytes), - ownership = Ownership.FILE_BACKED, - placement = Placement.MMAP_WEIGHTS - ) - } - } -} diff --git a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/memory/AllocationSpecTest.kt b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/memory/AllocationSpecTest.kt index 75ffa640e..9ea853a42 100644 --- a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/memory/AllocationSpecTest.kt +++ b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/memory/AllocationSpecTest.kt @@ -2,9 +2,6 @@ package sk.ainet.lang.memory import sk.ainet.lang.tensor.Shape import sk.ainet.lang.tensor.storage.MemoryDomain -import sk.ainet.lang.tensor.storage.Ownership -import sk.ainet.lang.tensor.storage.Placement -import sk.ainet.lang.tensor.storage.StorageSpec import sk.ainet.lang.tensor.storage.TensorEncoding import sk.ainet.lang.types.BF16 import sk.ainet.lang.types.FP32 @@ -16,9 +13,8 @@ import kotlin.test.assertFalse import kotlin.test.assertNull import kotlin.test.assertTrue -/** SKEEP-003 Phase 0: `AllocationSpec` replaces the never-consumed `StorageSpec`. */ +/** SKEEP-003 Phase 0: `AllocationSpec` replaced the never-consumed `StorageSpec` (deleted in #1142). */ @OptIn(ExperimentalMemoryApi::class) -@Suppress("DEPRECATION") // StorageSpec.toAllocationSpec is the migration path under test class AllocationSpecTest { @Test @@ -62,20 +58,21 @@ class AllocationSpecTest { } @Test - fun storageSpecConvertsToAllocationSpec() { - val weights = StorageSpec.q4k(Placement.MMAP_WEIGHTS).toAllocationSpec(1024) + fun weightSpecCanBeExpressedDirectly() { + val weights = AllocationSpec( + Format(FP32, TensorEncoding.Q4_K), 1024, + domain = MemoryDomain.MMAP_FILE, scope = ScopeKind.MODEL, mutable = false + ) assertEquals(Format(FP32, TensorEncoding.Q4_K), weights.format) assertEquals(1024L, weights.elementCount) assertEquals(MemoryDomain.MMAP_FILE, weights.domain) - assertEquals(ScopeKind.MODEL, weights.scope) // persistent placement → model lifetime - assertFalse(weights.mutable) // borrowed packed bytes + assertEquals(ScopeKind.MODEL, weights.scope) + assertFalse(weights.mutable) - val owned = StorageSpec.fromDType(BF16).toAllocationSpec(10) - assertEquals(Format.dense(BF16), owned.format) + val owned = AllocationSpec(Format.dense(BF16), 10) assertEquals(ScopeKind.AMBIENT, owned.scope) assertTrue(owned.mutable) assertEquals(20L, owned.bytes) - assertEquals(Ownership.OWNED, StorageSpec.fromDType(BF16).ownership) } @Test diff --git a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/AcceptanceCriteriaTest.kt b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/AcceptanceCriteriaTest.kt index a796db6e7..4ebce7538 100644 --- a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/AcceptanceCriteriaTest.kt +++ b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/AcceptanceCriteriaTest.kt @@ -10,7 +10,6 @@ import sk.ainet.lang.types.FP32 import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse -import kotlin.test.assertNotEquals import kotlin.test.assertTrue /** @@ -54,7 +53,6 @@ class AcceptanceCriteriaTest { assertTrue(storage.isFileBacked) assertFalse(storage.isMutable) assertEquals(MemoryDomain.MMAP_FILE, storage.placement.domain) - assertEquals(Residency.PERSISTENT, storage.placement.residency) } // --- AC3: Tensor views zero-copy, copies explicit --- @@ -188,7 +186,6 @@ class AcceptanceCriteriaTest { assertTrue(report.isFileBacked) assertEquals(Ownership.FILE_BACKED, report.ownership) assertEquals(MemoryDomain.MMAP_FILE, report.placement.domain) - assertEquals(Residency.PERSISTENT, report.placement.residency) assertFalse(report.isMutable) } @@ -205,7 +202,6 @@ class AcceptanceCriteriaTest { ) assertFalse(weights.isMutable) - assertEquals(Residency.PERSISTENT, weights.placement.residency) assertTrue(weights.isFileBacked) } @@ -220,25 +216,9 @@ class AcceptanceCriteriaTest { ) assertTrue(activations.isMutable) - assertEquals(Residency.TRANSIENT, activations.placement.residency) assertFalse(activations.isFileBacked) } - @Test - fun ac6_plannerDistinguishesWeightsFromActivations() { - val planner = MemoryPlanner() - - val weightPlacement = planner.suggestWeightPlacement(isFileBacked = true) - assertEquals(MemoryDomain.MMAP_FILE, weightPlacement.domain) - assertEquals(Residency.PERSISTENT, weightPlacement.residency) - - val activationPlacement = planner.suggestActivationPlacement() - assertEquals(MemoryDomain.HOST_HEAP, activationPlacement.domain) - assertEquals(Residency.TRANSIENT, activationPlacement.residency) - - assertNotEquals(weightPlacement, activationPlacement) - } - // --- Aggregate observability --- @Test diff --git a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/LogicalDTypeBridgeTest.kt b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/LogicalDTypeBridgeTest.kt index 745ee2e2e..ec35ec5ef 100644 --- a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/LogicalDTypeBridgeTest.kt +++ b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/LogicalDTypeBridgeTest.kt @@ -94,12 +94,6 @@ class LogicalDTypeBridgeTest { @Test fun descriptorsExposeTheDType() { - assertSame(FP16, StorageSpec.fromDType(FP16).dtype) - assertSame(FP32, StorageSpec.q4k().dtype) - assertSame(FP32, StorageSpec.q80().dtype) - assertSame(BF16, StorageSpec.borrowed(BF16).dtype) - assertSame(Int8, StorageSpec.mmapWeights(Int8).dtype) - val storage = TensorStorage( shape = Shape(2, 3), logicalType = LogicalDType.FLOAT32, diff --git a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/MemoryPlannerTest.kt b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/MemoryPlannerTest.kt deleted file mode 100644 index 87a97d3f7..000000000 --- a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/MemoryPlannerTest.kt +++ /dev/null @@ -1,150 +0,0 @@ -@file:Suppress("DEPRECATION") // LogicalDType legacy path kept under test until removal (SKEEP-003 #1014) - -package sk.ainet.lang.tensor.storage - -import sk.ainet.lang.tensor.Shape -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue -import kotlin.test.assertFailsWith - -class MemoryPlannerTest { - - @Test - fun cpuPlacementResolvesDirectly() { - val planner = MemoryPlanner(availableDevices = setOf(DeviceKind.CPU)) - val result = planner.resolve(Placement.CPU_HEAP) - assertEquals(DeviceKind.CPU, result.actual.device) - assertFalse(result.usedFallback) - } - - @Test - fun gpuPreferredFallsToCpuWhenNoGpu() { - val planner = MemoryPlanner(availableDevices = setOf(DeviceKind.CPU)) - val result = planner.resolve(Placement.GPU_PREFERRED) - assertEquals(DeviceKind.CPU, result.actual.device) - assertEquals(MemoryDomain.HOST_HEAP, result.actual.domain) // DEVICE_LOCAL falls to HOST_HEAP - assertTrue(result.usedFallback) - } - - @Test - fun gpuRequiredThrowsWhenNoGpu() { - val planner = MemoryPlanner(availableDevices = setOf(DeviceKind.CPU)) - val required = Placement( - device = DeviceKind.GPU, - domain = MemoryDomain.DEVICE_LOCAL, - requirement = Requirement.REQUIRED - ) - assertFailsWith { - planner.resolve(required) - } - } - - @Test - fun gpuResolvesDirectlyWhenAvailable() { - val planner = MemoryPlanner(availableDevices = setOf(DeviceKind.CPU, DeviceKind.GPU)) - val result = planner.resolve(Placement.GPU_PREFERRED) - assertEquals(DeviceKind.GPU, result.actual.device) - assertFalse(result.usedFallback) - } - - @Test - fun autoPicksBestDevice() { - val planner = MemoryPlanner(availableDevices = setOf(DeviceKind.CPU, DeviceKind.GPU)) - val result = planner.resolve(Placement(device = DeviceKind.AUTO)) - assertEquals(DeviceKind.GPU, result.actual.device) // GPU preferred over CPU - assertFalse(result.usedFallback) - } - - @Test - fun suggestWeightPlacementFileBacked() { - val planner = MemoryPlanner() - val p = planner.suggestWeightPlacement(isFileBacked = true) - assertEquals(MemoryDomain.MMAP_FILE, p.domain) - assertEquals(Residency.PERSISTENT, p.residency) - } - - @Test - fun suggestActivationPlacement() { - val planner = MemoryPlanner() - val p = planner.suggestActivationPlacement() - assertEquals(MemoryDomain.HOST_HEAP, p.domain) - assertEquals(Residency.TRANSIENT, p.residency) - } -} - -class MemoryTrackerTest { - - @Test - fun trackAndReport() { - val tracker = MemoryTracker() - - val s1 = TensorStorage( - shape = Shape(100), - logicalType = LogicalDType.FLOAT32, - encoding = TensorEncoding.Dense(4), - buffer = BufferHandle.Owned(ByteArray(400)) - ) - val s2 = TensorStorage( - shape = Shape(256), - logicalType = LogicalDType.FLOAT32, - encoding = TensorEncoding.Q4_K, - buffer = BufferHandle.Borrowed(ByteArray(144)) - ) - - tracker.record("weight1", s1) - tracker.record("weight2_q4k", s2) - - val report = tracker.report() - assertEquals(2, report.tensorCount) - assertEquals(1, report.ownedCount) - assertEquals(1, report.borrowedCount) - assertEquals(400L + 1024L, report.totalLogicalBytes) // 100*4 + 256*4 - assertEquals(400L + 144L, report.totalPhysicalBytes) - } - - @Test - fun trackCopies() { - val tracker = MemoryTracker() - tracker.recordCopy("tensor_a", 1024) - tracker.recordCopy("tensor_b", 2048) - - val report = tracker.report() - assertEquals(2L, report.copyCount) - assertEquals(3072L, report.copyBytes) - } - - @Test - fun clearResetsState() { - val tracker = MemoryTracker() - tracker.record("x", TensorStorage( - shape = Shape(10), - logicalType = LogicalDType.FLOAT32, - encoding = TensorEncoding.Dense(4), - buffer = BufferHandle.Owned(ByteArray(40)) - )) - tracker.recordCopy("x", 40) - tracker.clear() - - val report = tracker.report() - assertEquals(0, report.tensorCount) - assertEquals(0L, report.copyCount) - } - - @Test - fun fileBackedTracking() { - val tracker = MemoryTracker() - tracker.record("mmap_weight", TensorStorage( - shape = Shape(1000), - logicalType = LogicalDType.FLOAT16, - encoding = TensorEncoding.Dense(2), - buffer = BufferHandle.FileBacked("/model.bin", 0, 2000), - placement = Placement.MMAP_WEIGHTS - )) - - val report = tracker.report() - assertEquals(1, report.fileBackedCount) - assertEquals(2000L, report.fileBackedBytes) - } -} diff --git a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/TensorStorageContractTest.kt b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/TensorStorageContractTest.kt index 05bc0c1f2..589429936 100644 --- a/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/TensorStorageContractTest.kt +++ b/skainet-lang/skainet-lang-core/src/commonTest/kotlin/sk/ainet/lang/tensor/storage/TensorStorageContractTest.kt @@ -134,11 +134,9 @@ class TensorStorageContractTest { val cpuHeap = Placement.CPU_HEAP assertEquals(DeviceKind.CPU, cpuHeap.device) assertEquals(MemoryDomain.HOST_HEAP, cpuHeap.domain) - assertEquals(Residency.TRANSIENT, cpuHeap.residency) val mmapWeights = Placement.MMAP_WEIGHTS assertEquals(MemoryDomain.MMAP_FILE, mmapWeights.domain) - assertEquals(Residency.PERSISTENT, mmapWeights.residency) val gpuPreferred = Placement.GPU_PREFERRED assertEquals(DeviceKind.GPU, gpuPreferred.device) @@ -196,7 +194,6 @@ class TensorStorageContractTest { ) assertTrue(storage.isFileBacked) assertFalse(storage.isMutable) - assertEquals(Residency.PERSISTENT, storage.placement.residency) assertEquals(MemoryDomain.MMAP_FILE, storage.placement.domain) }