@@ -6,8 +6,20 @@ package reclaim_test
66import (
77 "testing"
88
9+ . "go.uber.org/mock/gomock"
10+ v1 "k8s.io/api/core/v1"
11+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+ "k8s.io/apimachinery/pkg/types"
13+
14+ schedulingv1alpha2 "github.com/kai-scheduler/KAI-scheduler/pkg/apis/scheduling/v1alpha2"
15+ commonconstants "github.com/kai-scheduler/KAI-scheduler/pkg/common/constants"
916 "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/integration_tests/integration_tests_utils"
17+ "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/reclaim"
18+ "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/common_info"
19+ "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/node_info"
20+ "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/pod_info"
1021 "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/pod_status"
22+ "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/resource_info"
1123 "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/constants"
1224 "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/test_utils"
1325 "github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/test_utils/jobs_fake"
@@ -19,6 +31,128 @@ func TestReclaimFractionalIntegrationTest(t *testing.T) {
1931 integration_tests_utils .RunTests (t , getReclaimFractionalTestsMetadata ())
2032}
2133
34+ func TestReclaimCanUseFullyEvictedFractionalGpuForDifferentComputeMode (t * testing.T ) {
35+ test_utils .InitTestingInfrastructure ()
36+ controller := NewController (t )
37+ defer controller .Finish ()
38+
39+ const gpuGroup = "time-slicing-group"
40+ topology := test_utils.TestTopologyBasic {
41+ Name : "reclaim all time-slicing fractions before using GPU for sm-sharing" ,
42+ Jobs : []* jobs_fake.TestJobBasic {
43+ {
44+ Name : "running_job0" ,
45+ RequiredGPUsPerTask : 0.5 ,
46+ Priority : constants .PriorityTrainNumber ,
47+ QueueName : "queue0" ,
48+ Tasks : []* tasks_fake.TestTaskBasic {
49+ {
50+ NodeName : "node0" ,
51+ GPUGroups : []string {gpuGroup },
52+ State : pod_status .Running ,
53+ },
54+ {
55+ NodeName : "node0" ,
56+ GPUGroups : []string {gpuGroup },
57+ State : pod_status .Running ,
58+ },
59+ },
60+ },
61+ {
62+ Name : "pending_job0" ,
63+ RequiredGPUsPerTask : 0.5 ,
64+ Priority : constants .PriorityTrainNumber ,
65+ QueueName : "queue1" ,
66+ Tasks : []* tasks_fake.TestTaskBasic {
67+ {
68+ State : pod_status .Pending ,
69+ Annotations : map [string ]string {
70+ commonconstants .GpuComputeSharingMode : string (schedulingv1alpha2 .GPUComputeSharingModeSMSharing ),
71+ },
72+ },
73+ },
74+ },
75+ },
76+ Nodes : map [string ]nodes_fake.TestNodeBasic {
77+ "node0" : {
78+ GPUs : 1 ,
79+ },
80+ },
81+ Queues : []test_utils.TestQueueBasic {
82+ {
83+ Name : "queue0" ,
84+ DeservedGPUs : 0 ,
85+ },
86+ {
87+ Name : "queue1" ,
88+ DeservedGPUs : 1 ,
89+ },
90+ },
91+ Mocks : & test_utils.TestMock {
92+ CacheRequirements : & test_utils.CacheMocking {
93+ NumberOfCacheEvictions : 2 ,
94+ NumberOfPipelineActions : 1 ,
95+ },
96+ },
97+ }
98+
99+ ssn := test_utils .BuildSession (topology , controller )
100+ addReservationPodToNodeForReclaimTest (ssn .ClusterInfo .Nodes ["node0" ], gpuGroup , schedulingv1alpha2 .GPUComputeSharingModeTimeSlicing )
101+
102+ reclaim .New ().Execute (ssn )
103+
104+ runningTasks := ssn .ClusterInfo .PodGroupInfos ["running_job0" ].GetAllPodsMap ()
105+ for taskID , task := range runningTasks {
106+ if task .Status != pod_status .Releasing {
107+ t .Fatalf ("expected time-slicing task %s to be releasing, got %s" , taskID , task .Status )
108+ }
109+ }
110+
111+ pendingTask := ssn .ClusterInfo .PodGroupInfos ["pending_job0" ].GetAllPodsMap ()[common_info .PodID ("pending_job0-0" )]
112+ if pendingTask .Status != pod_status .Pipelined {
113+ t .Fatalf ("expected sm-sharing task to be pipelined, got status %s" , pendingTask .Status )
114+ }
115+ if pendingTask .NodeName != "node0" {
116+ t .Fatalf ("expected sm-sharing task on node0, got %s" , pendingTask .NodeName )
117+ }
118+ gpuGroups := pendingTask .GPUGroupIDs ()
119+ if len (gpuGroups ) != 1 || gpuGroups [0 ] == gpuGroup {
120+ t .Fatalf ("expected sm-sharing task to use a new gpu group, got %v" , gpuGroups )
121+ }
122+ if pendingTask .FractionalGpuGroups [0 ].ComputeSharingMode != schedulingv1alpha2 .GPUComputeSharingModeSMSharing {
123+ t .Fatalf ("expected sm-sharing mode, got %s" , pendingTask .FractionalGpuGroups [0 ].ComputeSharingMode )
124+ }
125+ }
126+
127+ func addReservationPodToNodeForReclaimTest (
128+ node * node_info.NodeInfo , gpuGroup string , mode schedulingv1alpha2.GPUComputeSharingMode ,
129+ ) {
130+ pod := & v1.Pod {
131+ ObjectMeta : metav1.ObjectMeta {
132+ UID : types .UID ("reservation-" + gpuGroup ),
133+ Name : commonconstants .GPUReservationPodPrefix + "-node0-test" ,
134+ Namespace : commonconstants .DefaultResourceReservationName ,
135+ Labels : map [string ]string {
136+ commonconstants .GPUGroup : gpuGroup ,
137+ },
138+ Annotations : map [string ]string {
139+ commonconstants .PodGroupAnnotationForPod : "reservation" ,
140+ commonconstants .GpuComputeSharingMode : string (mode ),
141+ },
142+ },
143+ Spec : v1.PodSpec {
144+ NodeName : node .Name ,
145+ Containers : []v1.Container {
146+ {Name : "reservation" },
147+ },
148+ },
149+ Status : v1.PodStatus {Phase : v1 .PodRunning },
150+ }
151+ task := pod_info .NewTaskInfo (pod , resource_info .NewResourceVectorMap ())
152+ task .Status = pod_status .Running
153+ node .PodInfos [task .UID ] = task
154+ }
155+
22156func getReclaimFractionalTestsMetadata () []integration_tests_utils.TestTopologyMetadata {
23157 return []integration_tests_utils.TestTopologyMetadata {
24158 {
0 commit comments