volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/numaaware/provider/cpumanager/cpu_mng_test.go (about)

     1  /*
     2  Copyright 2021 The Volcano Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cpumanager
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/api/resource"
    25  	"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
    26  	"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
    27  	"k8s.io/utils/cpuset"
    28  
    29  	"volcano.sh/volcano/pkg/scheduler/api"
    30  	"volcano.sh/volcano/pkg/scheduler/plugins/numaaware/policy"
    31  )
    32  
    33  var numaInfo = api.NumatopoInfo{
    34  	CPUDetail: topology.CPUDetails{
    35  		0: {NUMANodeID: 0, CoreID: 0, SocketID: 0},
    36  		1: {NUMANodeID: 0, CoreID: 0, SocketID: 0},
    37  		2: {NUMANodeID: 0, CoreID: 1, SocketID: 0},
    38  		3: {NUMANodeID: 0, CoreID: 1, SocketID: 0},
    39  		4: {NUMANodeID: 1, CoreID: 2, SocketID: 1},
    40  		5: {NUMANodeID: 1, CoreID: 2, SocketID: 1},
    41  		6: {NUMANodeID: 1, CoreID: 3, SocketID: 1},
    42  		7: {NUMANodeID: 1, CoreID: 3, SocketID: 1},
    43  	},
    44  }
    45  
    46  func Test_GetTopologyHints(t *testing.T) {
    47  	teseCases := []struct {
    48  		name        string
    49  		container   v1.Container
    50  		resNumaSets api.ResNumaSets
    51  		expect      []policy.TopologyHint
    52  	}{
    53  		{
    54  			name: "test-1",
    55  			container: v1.Container{
    56  				Resources: v1.ResourceRequirements{
    57  					Requests: v1.ResourceList{
    58  						"cpu": *resource.NewQuantity(4, ""),
    59  					},
    60  				},
    61  			},
    62  			resNumaSets: api.ResNumaSets{
    63  				"cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
    64  			},
    65  			expect: []policy.TopologyHint{
    66  				{
    67  					NUMANodeAffinity: func() bitmask.BitMask {
    68  						mask, _ := bitmask.NewBitMask(0)
    69  						return mask
    70  					}(),
    71  					Preferred: true,
    72  				},
    73  				{
    74  					NUMANodeAffinity: func() bitmask.BitMask {
    75  						mask, _ := bitmask.NewBitMask(1)
    76  						return mask
    77  					}(),
    78  					Preferred: true,
    79  				},
    80  				{
    81  					NUMANodeAffinity: func() bitmask.BitMask {
    82  						mask, _ := bitmask.NewBitMask(0, 1)
    83  						return mask
    84  					}(),
    85  					Preferred: false,
    86  				},
    87  			},
    88  		},
    89  		{
    90  			name: "test-2",
    91  			container: v1.Container{
    92  				Resources: v1.ResourceRequirements{
    93  					Requests: v1.ResourceList{
    94  						"cpu": *resource.NewQuantity(4, ""),
    95  					},
    96  				},
    97  			},
    98  			resNumaSets: api.ResNumaSets{
    99  				"cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7),
   100  			},
   101  			expect: []policy.TopologyHint{
   102  				{
   103  					NUMANodeAffinity: func() bitmask.BitMask {
   104  						mask, _ := bitmask.NewBitMask(1)
   105  						return mask
   106  					}(),
   107  					Preferred: true,
   108  				},
   109  				{
   110  					NUMANodeAffinity: func() bitmask.BitMask {
   111  						mask, _ := bitmask.NewBitMask(0, 1)
   112  						return mask
   113  					}(),
   114  					Preferred: false,
   115  				},
   116  			},
   117  		},
   118  		{
   119  			name: "test-3",
   120  			container: v1.Container{
   121  				Resources: v1.ResourceRequirements{
   122  					Requests: v1.ResourceList{
   123  						"cpu": *resource.NewQuantity(5, ""),
   124  					},
   125  				},
   126  			},
   127  			resNumaSets: api.ResNumaSets{
   128  				"cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   129  			},
   130  			expect: []policy.TopologyHint{
   131  				{
   132  					NUMANodeAffinity: func() bitmask.BitMask {
   133  						mask, _ := bitmask.NewBitMask(0, 1)
   134  						return mask
   135  					}(),
   136  					Preferred: true,
   137  				},
   138  			},
   139  		},
   140  		{
   141  			name: "test-4",
   142  			container: v1.Container{
   143  				Resources: v1.ResourceRequirements{
   144  					Requests: v1.ResourceList{
   145  						"cpu": *resource.NewQuantity(8, ""),
   146  					},
   147  				},
   148  			},
   149  			resNumaSets: api.ResNumaSets{
   150  				"cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   151  			},
   152  			expect: []policy.TopologyHint{
   153  				{
   154  					NUMANodeAffinity: func() bitmask.BitMask {
   155  						mask, _ := bitmask.NewBitMask(0, 1)
   156  						return mask
   157  					}(),
   158  					Preferred: true,
   159  				},
   160  			},
   161  		},
   162  		{
   163  			name: "test-5",
   164  			container: v1.Container{
   165  				Resources: v1.ResourceRequirements{
   166  					Requests: v1.ResourceList{
   167  						"cpu": *resource.NewQuantity(9, ""),
   168  					},
   169  				},
   170  			},
   171  			resNumaSets: api.ResNumaSets{
   172  				"cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   173  			},
   174  			expect: []policy.TopologyHint{},
   175  		},
   176  		{
   177  			name: "test-6",
   178  			container: v1.Container{
   179  				Resources: v1.ResourceRequirements{
   180  					Requests: v1.ResourceList{
   181  						"cpu": *resource.NewQuantity(4, ""),
   182  					},
   183  				},
   184  			},
   185  			resNumaSets: api.ResNumaSets{
   186  				"cpu": cpuset.New(2, 3, 4, 5),
   187  			},
   188  			expect: []policy.TopologyHint{
   189  				{
   190  					NUMANodeAffinity: func() bitmask.BitMask {
   191  						mask, _ := bitmask.NewBitMask(0, 1)
   192  						return mask
   193  					}(),
   194  					Preferred: false,
   195  				},
   196  			},
   197  		},
   198  	}
   199  
   200  	for _, testcase := range teseCases {
   201  		provider := NewProvider()
   202  		topologyHintmap := provider.GetTopologyHints(&testcase.container, &numaInfo, testcase.resNumaSets)
   203  		if !(reflect.DeepEqual(topologyHintmap["cpu"], testcase.expect) ||
   204  			(len(topologyHintmap["cpu"]) == 0 && len(testcase.expect) == 0)) {
   205  			t.Errorf("%s failed. topologyHintmap = %v\n", testcase.name, topologyHintmap)
   206  		}
   207  	}
   208  }
   209  
   210  func Test_Allocate(t *testing.T) {
   211  	teseCases := []struct {
   212  		name        string
   213  		container   v1.Container
   214  		resNumaSets api.ResNumaSets
   215  		bestHit     *policy.TopologyHint
   216  		expect      cpuset.CPUSet
   217  	}{
   218  		{
   219  			name: "test-1",
   220  			container: v1.Container{
   221  				Resources: v1.ResourceRequirements{
   222  					Requests: v1.ResourceList{
   223  						"cpu": *resource.NewQuantity(4, ""),
   224  					},
   225  				},
   226  			},
   227  			resNumaSets: api.ResNumaSets{
   228  				"cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   229  			},
   230  			bestHit: &policy.TopologyHint{
   231  				NUMANodeAffinity: func() bitmask.BitMask {
   232  					mask, _ := bitmask.NewBitMask(0)
   233  					return mask
   234  				}(),
   235  				Preferred: true,
   236  			},
   237  			expect: cpuset.New(0, 1, 2, 3),
   238  		},
   239  		{
   240  			name: "test-2",
   241  			container: v1.Container{
   242  				Resources: v1.ResourceRequirements{
   243  					Requests: v1.ResourceList{
   244  						"cpu": *resource.NewQuantity(4, ""),
   245  					},
   246  				},
   247  			},
   248  			resNumaSets: api.ResNumaSets{
   249  				"cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7),
   250  			},
   251  			bestHit: &policy.TopologyHint{
   252  				NUMANodeAffinity: func() bitmask.BitMask {
   253  					mask, _ := bitmask.NewBitMask(1)
   254  					return mask
   255  				}(),
   256  				Preferred: true,
   257  			},
   258  			expect: cpuset.New(4, 5, 6, 7),
   259  		},
   260  		{
   261  			name: "test-3",
   262  			container: v1.Container{
   263  				Resources: v1.ResourceRequirements{
   264  					Requests: v1.ResourceList{
   265  						"cpu": *resource.NewQuantity(5, ""),
   266  					},
   267  				},
   268  			},
   269  			resNumaSets: api.ResNumaSets{
   270  				"cpu": cpuset.New(0, 1, 2, 3, 4, 5, 6, 7),
   271  			},
   272  			bestHit: &policy.TopologyHint{
   273  				NUMANodeAffinity: func() bitmask.BitMask {
   274  					mask, _ := bitmask.NewBitMask(0, 1)
   275  					return mask
   276  				}(),
   277  				Preferred: true,
   278  			},
   279  			expect: cpuset.New(0, 1, 2, 3, 4),
   280  		},
   281  		{
   282  			name: "test-4",
   283  			container: v1.Container{
   284  				Resources: v1.ResourceRequirements{
   285  					Requests: v1.ResourceList{
   286  						"cpu": *resource.NewQuantity(5, ""),
   287  					},
   288  				},
   289  			},
   290  			resNumaSets: api.ResNumaSets{
   291  				"cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7),
   292  			},
   293  			bestHit: &policy.TopologyHint{
   294  				NUMANodeAffinity: func() bitmask.BitMask {
   295  					mask, _ := bitmask.NewBitMask(0, 1)
   296  					return mask
   297  				}(),
   298  				Preferred: true,
   299  			},
   300  			expect: cpuset.New(1, 4, 5, 6, 7),
   301  		},
   302  		{
   303  			name: "test-5",
   304  			container: v1.Container{
   305  				Resources: v1.ResourceRequirements{
   306  					Requests: v1.ResourceList{
   307  						"cpu": *resource.NewQuantity(8, ""),
   308  					},
   309  				},
   310  			},
   311  			resNumaSets: api.ResNumaSets{
   312  				"cpu": cpuset.New(1, 2, 3, 4, 5, 6, 7),
   313  			},
   314  			bestHit: &policy.TopologyHint{
   315  				NUMANodeAffinity: func() bitmask.BitMask {
   316  					mask, _ := bitmask.NewBitMask(0, 1)
   317  					return mask
   318  				}(),
   319  				Preferred: true,
   320  			},
   321  			expect: cpuset.New(),
   322  		},
   323  	}
   324  
   325  	for _, testcase := range teseCases {
   326  		provider := NewProvider()
   327  		assignMap := provider.Allocate(&testcase.container, testcase.bestHit, &numaInfo, testcase.resNumaSets)
   328  		if !(reflect.DeepEqual(assignMap["cpu"], testcase.expect)) {
   329  			t.Errorf("%s failed.\n", testcase.name)
   330  		}
   331  	}
   332  }