github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/resource/plugins/cpumem/node_test.go (about)

     1  package cpumem
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"testing"
     8  
     9  	"github.com/cockroachdb/errors"
    10  	"github.com/docker/go-units"
    11  	enginetypes "github.com/projecteru2/core/engine/types"
    12  	"github.com/projecteru2/core/resource/plugins/cpumem/types"
    13  	plugintypes "github.com/projecteru2/core/resource/plugins/types"
    14  	coretypes "github.com/projecteru2/core/types"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestAddNode(t *testing.T) {
    19  	ctx := context.Background()
    20  	cm := initCPUMEM(ctx, t)
    21  	nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0)
    22  	node := nodes[0]
    23  	nodeForAdd := "test2"
    24  
    25  	req := plugintypes.NodeResourceRequest{
    26  		"numa-cpu": []string{"0", "1"},
    27  	}
    28  
    29  	info := &enginetypes.Info{NCPU: 2, MemTotal: 4 * units.GB}
    30  
    31  	// existent node
    32  	_, err := cm.AddNode(ctx, node, req, info)
    33  	assert.Equal(t, err, coretypes.ErrNodeExists)
    34  
    35  	// normal case
    36  	r, err := cm.AddNode(ctx, nodeForAdd, req, info)
    37  	assert.Nil(t, err)
    38  	assert.Equal(t, r.Capacity["memory"], int64(4*units.GB*rate/10))
    39  }
    40  
    41  func TestRemoveNode(t *testing.T) {
    42  	ctx := context.Background()
    43  	cm := initCPUMEM(ctx, t)
    44  	nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0)
    45  	node := nodes[0]
    46  	nodeForDel := "test2"
    47  
    48  	_, err := cm.RemoveNode(ctx, node)
    49  	assert.Nil(t, err)
    50  	_, err = cm.RemoveNode(ctx, nodeForDel)
    51  	assert.Nil(t, err)
    52  }
    53  
    54  func TestGetNodesDeployCapacityWithCPUBind(t *testing.T) {
    55  	ctx := context.Background()
    56  	cm := initCPUMEM(ctx, t)
    57  	nodes := generateNodes(ctx, t, cm, 2, 2, 4*units.GB, 100, 0)
    58  
    59  	req := plugintypes.WorkloadResourceRequest{
    60  		"cpu-bind":       true,
    61  		"cpu-request":    0.5,
    62  		"memory-request": "1",
    63  	}
    64  
    65  	// non-existent node
    66  	_, err := cm.GetNodesDeployCapacity(ctx, []string{"xxx"}, req)
    67  	assert.True(t, errors.Is(err, coretypes.ErrInvaildCount))
    68  
    69  	// normal
    70  	r, err := cm.GetNodesDeployCapacity(ctx, nodes, req)
    71  	assert.Nil(t, err)
    72  	assert.True(t, r.Total >= 1)
    73  
    74  	// more cpu
    75  	req = plugintypes.WorkloadResourceRequest{
    76  		"cpu-bind":       true,
    77  		"cpu-request":    2,
    78  		"memory-request": "1",
    79  	}
    80  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
    81  	assert.Nil(t, err)
    82  	assert.True(t, r.Total < 3)
    83  
    84  	// more
    85  	req = plugintypes.WorkloadResourceRequest{
    86  		"cpu-bind":       true,
    87  		"cpu-request":    3,
    88  		"memory-request": "1",
    89  	}
    90  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
    91  	assert.Nil(t, err)
    92  	assert.True(t, r.Total < 2)
    93  
    94  	// less
    95  	req = plugintypes.WorkloadResourceRequest{
    96  		"cpu-bind":       true,
    97  		"cpu-request":    1,
    98  		"memory-request": "1",
    99  	}
   100  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
   101  	assert.Nil(t, err)
   102  	assert.True(t, r.Total < 5)
   103  
   104  	// complex
   105  	nodes = generateNodes(ctx, t, cm, 1, 4, 12*units.GB, 100, 10)
   106  	nodes = append(nodes, generateNodes(ctx, t, cm, 1, 14, 12*units.GB, 100, 11)...)
   107  	nodes = append(nodes, generateNodes(ctx, t, cm, 1, 12, 12*units.GB, 100, 12)...)
   108  	nodes = append(nodes, generateNodes(ctx, t, cm, 1, 18, 12*units.GB, 100, 13)...)
   109  	nodes = append(nodes, generateNodes(ctx, t, cm, 1, 8, 12*units.GB, 100, 14)...)
   110  
   111  	req = plugintypes.WorkloadResourceRequest{
   112  		"cpu-bind":       true,
   113  		"cpu-request":    1.7,
   114  		"memory-request": "1",
   115  	}
   116  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
   117  	assert.Nil(t, err)
   118  	assert.Equal(t, r.Total, 28)
   119  }
   120  
   121  func TestGetNodesDeployCapacityWithMemoryAndCPUBind(t *testing.T) {
   122  	ctx := context.Background()
   123  	cm := initCPUMEM(ctx, t)
   124  	nodes := generateNodes(ctx, t, cm, 2, 2, 1024, 100, 0)
   125  
   126  	req := plugintypes.WorkloadResourceRequest{
   127  		"cpu-bind":       true,
   128  		"cpu-request":    0.1,
   129  		"memory-request": "1024",
   130  	}
   131  
   132  	r, err := cm.GetNodesDeployCapacity(ctx, nodes, req)
   133  	assert.Nil(t, err)
   134  	assert.Equal(t, r.Total, 2)
   135  
   136  	req["memory-request"] = "1025"
   137  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
   138  	assert.Nil(t, err)
   139  	assert.Equal(t, r.Total, 0)
   140  }
   141  
   142  func TestGetNodesDeployCapacityWithMaxShareLimit(t *testing.T) {
   143  	ctx := context.Background()
   144  	cm := initCPUMEM(ctx, t)
   145  	cm.config.Scheduler.MaxShare = 2
   146  	nodes := generateNodes(ctx, t, cm, 1, 6, 12*units.GB, 100, 0)
   147  	node := nodes[0]
   148  
   149  	req := plugintypes.WorkloadResourceRequest{
   150  		"cpu-bind":       true,
   151  		"cpu-request":    1.7,
   152  		"memory-request": "1",
   153  	}
   154  
   155  	r, err := cm.GetNodesDeployCapacity(ctx, nodes, req)
   156  	assert.Nil(t, err)
   157  	assert.Equal(t, r.Total, 2)
   158  
   159  	// numa node
   160  	resource := plugintypes.NodeResource{
   161  		"cpu": 4.0,
   162  		"cpu_map": map[string]int64{
   163  			"0": 0,
   164  			"1": 0,
   165  			"2": 100,
   166  			"3": 100,
   167  		},
   168  		"memory": 12 * units.GB,
   169  	}
   170  
   171  	_, err = cm.SetNodeResourceCapacity(ctx, node, resource, nil, false, true)
   172  	assert.Nil(t, err)
   173  
   174  	req["cpu-request"] = 1.2
   175  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
   176  	assert.Nil(t, err)
   177  	assert.Equal(t, r.Total, 1)
   178  }
   179  
   180  func TestGetNodesDeployCapacityWithMemory(t *testing.T) {
   181  	ctx := context.Background()
   182  	cm := initCPUMEM(ctx, t)
   183  	nodes := generateNodes(ctx, t, cm, 2, 2, 4*units.GiB, 100, 0)
   184  
   185  	req := plugintypes.WorkloadResourceRequest{
   186  		"memory-request": "-1",
   187  	}
   188  
   189  	// negative memory
   190  	_, err := cm.GetNodesDeployCapacity(ctx, nodes, req)
   191  	assert.True(t, errors.Is(err, types.ErrInvalidMemory))
   192  
   193  	// cpu + mem
   194  	req = plugintypes.WorkloadResourceRequest{
   195  		"cpu-request":    1,
   196  		"memory-request": fmt.Sprintf("%v", 512*units.MB),
   197  	}
   198  
   199  	r, err := cm.GetNodesDeployCapacity(ctx, nodes, req)
   200  	assert.Nil(t, err)
   201  	assert.Equal(t, r.Total, 16)
   202  
   203  	// unlimited cpu
   204  	req = plugintypes.WorkloadResourceRequest{
   205  		"memory-request": fmt.Sprintf("%v", 512*units.MB),
   206  	}
   207  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
   208  	assert.Nil(t, err)
   209  	assert.Equal(t, r.Total, 16)
   210  
   211  	// insufficient cpu
   212  	req = plugintypes.WorkloadResourceRequest{
   213  		"cpu-request":    3,
   214  		"memory-request": fmt.Sprintf("%v", 512*units.MB),
   215  	}
   216  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
   217  	assert.Nil(t, err)
   218  	assert.Equal(t, r.Total, 0)
   219  
   220  	// mem_request == 0
   221  	req = plugintypes.WorkloadResourceRequest{
   222  		"cpu-request": 1,
   223  	}
   224  	r, err = cm.GetNodesDeployCapacity(ctx, nodes, req)
   225  	assert.Nil(t, err)
   226  	assert.Equal(t, r.Total, math.MaxInt)
   227  }
   228  
   229  func TestSetNodeResourceCapacity(t *testing.T) {
   230  	ctx := context.Background()
   231  	cm := initCPUMEM(ctx, t)
   232  	nodes := generateNodes(ctx, t, cm, 1, 2, 2*units.GB, 100, 0)
   233  	node := nodes[0]
   234  
   235  	_, err := cm.GetNodeResourceInfo(ctx, node, nil)
   236  	assert.Nil(t, err)
   237  
   238  	nodeResource := plugintypes.NodeResource{
   239  		"cpu_map": map[string]int{
   240  			"2": 100,
   241  			"3": 100,
   242  		},
   243  		"numa_memory": types.NUMAMemory{
   244  			"0": units.GiB,
   245  			"1": units.GiB,
   246  		},
   247  		"numa": types.NUMA{
   248  			"0": "0",
   249  			"1": "0",
   250  			"2": "1",
   251  			"3": "1",
   252  		},
   253  	}
   254  
   255  	newNodeResource := plugintypes.NodeResource{
   256  		"cpu_map": map[string]int{
   257  			"0": 100,
   258  			"1": 100,
   259  		},
   260  		"memory": 2 * units.GB,
   261  		"xxxx":   map[string]interface{}{"cpu": ""},
   262  	}
   263  
   264  	gb := fmt.Sprintf("%v", units.GB)
   265  	nodeResourceRequest := plugintypes.NodeResourceRequest{
   266  		"cpu":         "2:100,3:100",
   267  		"numa-memory": []string{gb, gb},
   268  		"numa-cpu":    []string{"0,1", "2,3"},
   269  	}
   270  
   271  	noChangeRequest := plugintypes.NodeResourceRequest{
   272  		"cpu":    "0:100,1:100,2:100,3:100",
   273  		"memory": fmt.Sprintf("%v", 2*units.GB),
   274  	}
   275  
   276  	r, err := cm.SetNodeResourceCapacity(ctx, node, nodeResource, nil, true, true)
   277  	assert.Nil(t, err)
   278  	assert.Len(t, r.After["cpu_map"], 4)
   279  
   280  	r, err = cm.SetNodeResourceCapacity(ctx, node, nodeResource, nil, true, false)
   281  	assert.Nil(t, err)
   282  	assert.Len(t, r.After["cpu_map"], 2)
   283  	assert.Len(t, r.After["numa_memory"], 2)
   284  	assert.Len(t, r.After["numa"], 4)
   285  
   286  	r, err = cm.SetNodeResourceCapacity(ctx, node, nil, nodeResourceRequest, true, true)
   287  	assert.Nil(t, err)
   288  	assert.Len(t, r.After["cpu_map"], 4)
   289  	assert.Len(t, r.After["numa_memory"], 2)
   290  	assert.Len(t, r.After["numa"], 4)
   291  
   292  	r, err = cm.SetNodeResourceCapacity(ctx, node, nil, nodeResourceRequest, true, false)
   293  	assert.Nil(t, err)
   294  	assert.Len(t, r.After["cpu_map"], 2)
   295  	assert.Len(t, r.After["numa_memory"], 2)
   296  	assert.Len(t, r.After["numa"], 4)
   297  
   298  	r, err = cm.SetNodeResourceCapacity(ctx, node, nil, noChangeRequest, false, true)
   299  	assert.Nil(t, err)
   300  	assert.Len(t, r.After["cpu_map"], 4)
   301  
   302  	r, err = cm.SetNodeResourceCapacity(ctx, node, newNodeResource, nil, false, false)
   303  	assert.Nil(t, err)
   304  	assert.Len(t, r.After["cpu_map"], 2)
   305  	assert.Len(t, r.After["numa"], 0)
   306  }
   307  
   308  func TestGetAndFixNodeResourceInfo(t *testing.T) {
   309  	ctx := context.Background()
   310  	cm := initCPUMEM(ctx, t)
   311  	nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0)
   312  	node := nodes[0]
   313  
   314  	// invalid node
   315  	_, err := cm.GetNodeResourceInfo(ctx, "xxx", nil)
   316  	assert.True(t, errors.Is(err, coretypes.ErrInvaildCount))
   317  
   318  	r, err := cm.GetNodeResourceInfo(ctx, node, nil)
   319  	assert.Nil(t, err)
   320  	assert.Len(t, r.Diffs, 0)
   321  
   322  	r.Capacity["numa"] = types.NUMA{"0": "0", "1": "1"}
   323  	r.Capacity["numa_memory"] = types.NUMAMemory{"0": units.GB, "1": units.GB}
   324  
   325  	_, err = cm.SetNodeResourceInfo(ctx, node, r.Capacity, r.Usage)
   326  	assert.Nil(t, err)
   327  
   328  	workloadsResource := []plugintypes.WorkloadResource{
   329  		{
   330  			"cpu_request":    2.0,
   331  			"cpu_map":        types.CPUMap{"0": 100, "1": 100},
   332  			"memory_request": 2 * units.GB,
   333  			"numa_memory":    types.NUMAMemory{"0": units.GB, "1": units.GB},
   334  		},
   335  	}
   336  	r, err = cm.GetNodeResourceInfo(ctx, node, workloadsResource)
   337  	assert.Nil(t, err)
   338  	assert.Len(t, r.Diffs, 6)
   339  
   340  	r, err = cm.FixNodeResource(ctx, node, workloadsResource)
   341  	assert.Nil(t, err)
   342  	assert.Len(t, r.Diffs, 6)
   343  	assert.Len(t, r.Usage["numa_memory"], 2)
   344  }
   345  
   346  func TestSetNodeResourceInfo(t *testing.T) {
   347  	ctx := context.Background()
   348  	cm := initCPUMEM(ctx, t)
   349  	nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0)
   350  	node := nodes[0]
   351  
   352  	r, err := cm.GetNodeResourceInfo(ctx, node, nil)
   353  	assert.Nil(t, err)
   354  
   355  	_, err = cm.SetNodeResourceInfo(ctx, "node-2", r.Capacity, r.Usage)
   356  	assert.Nil(t, err)
   357  }
   358  
   359  func TestSetNodeResourceUsage(t *testing.T) {
   360  	ctx := context.Background()
   361  	cm := initCPUMEM(ctx, t)
   362  	nodes := generateNodes(ctx, t, cm, 1, 2, 4*units.GB, 100, 0)
   363  	node := nodes[0]
   364  
   365  	_, err := cm.GetNodeResourceInfo(ctx, node, nil)
   366  	assert.Nil(t, err)
   367  
   368  	nodeResource := plugintypes.NodeResource{
   369  		"cpu_map": map[string]int{
   370  			"0": 100,
   371  			"1": 100,
   372  		},
   373  		"memory": 2 * units.GB,
   374  	}
   375  
   376  	nodeResourceRequest := plugintypes.NodeResourceRequest{
   377  		"cpu":    "0:100,1:100",
   378  		"memory": fmt.Sprintf("%v", 2*units.GB),
   379  	}
   380  
   381  	workloadsResource := []plugintypes.WorkloadResource{
   382  		{
   383  			"cpu_request": 2.0,
   384  			"cpu_map": types.CPUMap{
   385  				"0": 100,
   386  				"1": 100,
   387  			},
   388  			"memory_request": 2 * units.GB,
   389  		},
   390  	}
   391  
   392  	r, err := cm.SetNodeResourceUsage(ctx, node, nodeResource, nil, nil, true, true)
   393  	assert.Nil(t, err)
   394  	assert.Len(t, r.After["cpu_map"], 2)
   395  
   396  	r, err = cm.SetNodeResourceUsage(ctx, node, nodeResource, nil, nil, true, false)
   397  	assert.Nil(t, err)
   398  	assert.Len(t, r.After["cpu_map"], 2)
   399  	assert.Equal(t, r.After["cpu"], 0.0)
   400  	assert.Equal(t, r.After["memory"], int64(0))
   401  
   402  	r, err = cm.SetNodeResourceUsage(ctx, node, nil, nodeResourceRequest, nil, true, true)
   403  	assert.Nil(t, err)
   404  	assert.Len(t, r.After["cpu_map"], 2)
   405  
   406  	r, err = cm.SetNodeResourceUsage(ctx, node, nil, nodeResourceRequest, nil, true, false)
   407  	assert.Nil(t, err)
   408  	assert.Len(t, r.After["cpu_map"], 2)
   409  	assert.Equal(t, r.After["cpu"], 0.0)
   410  	assert.Equal(t, r.After["memory"], int64(0))
   411  
   412  	r, err = cm.SetNodeResourceUsage(ctx, node, nil, nil, workloadsResource, true, true)
   413  	assert.Nil(t, err)
   414  	assert.Len(t, r.After["cpu_map"], 2)
   415  
   416  	r, err = cm.SetNodeResourceUsage(ctx, node, nil, nil, workloadsResource, true, false)
   417  	assert.Nil(t, err)
   418  	assert.Len(t, r.After["cpu_map"], 2)
   419  	assert.Equal(t, r.After["cpu"], 0.0)
   420  	assert.Equal(t, r.After["memory"], int64(0))
   421  
   422  	r, err = cm.SetNodeResourceUsage(ctx, node, nil, nil, nil, true, false)
   423  	assert.Nil(t, err)
   424  	assert.Len(t, r.After["cpu_map"], 2)
   425  	assert.Equal(t, r.After["cpu"], 0.0)
   426  	assert.Equal(t, r.After["memory"], int64(0))
   427  
   428  	r, err = cm.SetNodeResourceUsage(ctx, node, nil, nodeResourceRequest, nil, false, false)
   429  	assert.Nil(t, err)
   430  	assert.Len(t, r.After["cpu_map"], 2)
   431  	assert.Equal(t, r.After["cpu"], 2.0)
   432  	assert.Equal(t, r.After["memory"], int64(2*units.GB))
   433  }
   434  
   435  func TestGetMostIdleNode(t *testing.T) {
   436  	ctx := context.Background()
   437  	cm := initCPUMEM(ctx, t)
   438  	nodes := generateNodes(ctx, t, cm, 2, 2, 2*units.GB, 100, 0)
   439  	usage := plugintypes.NodeResourceRequest{"memory": "100"}
   440  
   441  	_, err := cm.SetNodeResourceUsage(ctx, nodes[1], nil, usage, nil, false, false)
   442  	assert.Nil(t, err)
   443  
   444  	r, err := cm.GetMostIdleNode(ctx, nodes)
   445  	assert.Nil(t, err)
   446  	assert.Equal(t, r.Nodename, nodes[0])
   447  
   448  	nodes = append(nodes, "node-x")
   449  	_, err = cm.GetMostIdleNode(ctx, nodes)
   450  	assert.Error(t, err)
   451  }
   452  
   453  func BenchmarkGetNodesCapacity(b *testing.B) {
   454  	b.StopTimer()
   455  	t := &testing.T{}
   456  	ctx := context.Background()
   457  	cm := initCPUMEM(ctx, t)
   458  	nodes := generateNodes(ctx, t, cm, 1000, 24, 128*units.GB, 100, 0)
   459  	req := plugintypes.WorkloadResourceRequest{
   460  		"cpu-bind":       true,
   461  		"cpu-request":    1.3,
   462  		"memory-request": "1",
   463  	}
   464  	b.StartTimer()
   465  
   466  	for i := 0; i < b.N; i++ {
   467  		_, err := cm.GetNodesDeployCapacity(ctx, nodes, req)
   468  		assert.Nil(b, err)
   469  	}
   470  }