Merge branch 'main' from workbench2.git
[arvados.git] / services / crunch-dispatch-slurm / priority_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package dispatchslurm
6
7 import (
8         . "gopkg.in/check.v1"
9 )
10
11 var _ = Suite(&PrioritySuite{})
12
13 type PrioritySuite struct{}
14
15 func (s *PrioritySuite) TestReniceCorrect(c *C) {
16         for _, test := range []struct {
17                 spread int64
18                 in     []*slurmJob
19                 out    []int64
20         }{
21                 {
22                         0,
23                         nil,
24                         nil,
25                 },
26                 {
27                         0,
28                         []*slurmJob{},
29                         nil,
30                 },
31                 {
32                         10,
33                         []*slurmJob{{priority: 4294000111, nice: 10000}},
34                         []int64{0},
35                 },
36                 {
37                         10,
38                         []*slurmJob{
39                                 {priority: 4294000111, nice: 10000},
40                                 {priority: 4294000111, nice: 10000},
41                                 {priority: 4294000111, nice: 10000},
42                                 {priority: 4294000111, nice: 10000},
43                         },
44                         []int64{0, 10, 20, 30},
45                 },
46                 { // smaller spread than necessary, but correctly ordered => leave nice alone
47                         10,
48                         []*slurmJob{
49                                 {priority: 4294000113, nice: 0},
50                                 {priority: 4294000112, nice: 1},
51                                 {priority: 4294000111, nice: 99},
52                         },
53                         []int64{0, 1, 99},
54                 },
55                 { // larger spread than necessary, but less than 10x => leave nice alone
56                         10,
57                         []*slurmJob{
58                                 {priority: 4294000144, nice: 0},
59                                 {priority: 4294000122, nice: 20},
60                                 {priority: 4294000111, nice: 30},
61                         },
62                         []int64{0, 20, 30},
63                 },
64                 { // > 10x spread => reduce nice to achieve spread=10
65                         10,
66                         []*slurmJob{
67                                 {priority: 4000, nice: 0},    // max pri 4000
68                                 {priority: 3000, nice: 999},  // max pri 3999
69                                 {priority: 2000, nice: 1998}, // max pri 3998
70                         },
71                         []int64{0, 9, 18},
72                 },
73                 { // > 10x spread, but spread=10 is impossible without negative nice
74                         10,
75                         []*slurmJob{
76                                 {priority: 4000, nice: 0},    // max pri 4000
77                                 {priority: 3000, nice: 500},  // max pri 3500
78                                 {priority: 2000, nice: 2000}, // max pri 4000
79                         },
80                         []int64{0, 0, 510},
81                 },
82                 { // default spread, needs reorder
83                         0,
84                         []*slurmJob{
85                                 {priority: 4000, nice: 0}, // max pri 4000
86                                 {priority: 5000, nice: 0}, // max pri 5000
87                                 {priority: 6000, nice: 0}, // max pri 6000
88                         },
89                         []int64{0, 1000 + defaultSpread, 2000 + defaultSpread*2},
90                 },
91                 { // minimum spread
92                         1,
93                         []*slurmJob{
94                                 {priority: 4000, nice: 0}, // max pri 4000
95                                 {priority: 5000, nice: 0}, // max pri 5000
96                                 {priority: 6000, nice: 0}, // max pri 6000
97                                 {priority: 3000, nice: 0}, // max pri 3000
98                         },
99                         []int64{0, 1001, 2002, 0},
100                 },
101         } {
102                 c.Logf("spread=%d %+v -> %+v", test.spread, test.in, test.out)
103                 c.Check(wantNice(test.in, test.spread), DeepEquals, test.out)
104
105                 if len(test.in) == 0 {
106                         continue
107                 }
108                 // After making the adjustments, calling wantNice
109                 // again should return the same recommendations.
110                 updated := make([]*slurmJob, len(test.in))
111                 for i, in := range test.in {
112                         updated[i] = &slurmJob{
113                                 nice:     test.out[i],
114                                 priority: in.priority + in.nice - test.out[i],
115                         }
116                 }
117                 c.Check(wantNice(updated, test.spread), DeepEquals, test.out)
118         }
119 }
120
121 func (s *PrioritySuite) TestReniceChurn(c *C) {
122         const spread = 10
123         jobs := make([]*slurmJob, 1000)
124         for i := range jobs {
125                 jobs[i] = &slurmJob{priority: 4294000000 - int64(i), nice: 10000}
126         }
127         adjustments := 0
128         queue := jobs
129         for len(queue) > 0 {
130                 renice := wantNice(queue, spread)
131                 for i := range queue {
132                         if renice[i] == queue[i].nice {
133                                 continue
134                         }
135                         queue[i].priority += queue[i].nice - renice[i]
136                         queue[i].nice = renice[i]
137                         adjustments++
138                 }
139                 queue = queue[1:]
140         }
141         c.Logf("processed queue of %d with %d renice ops", len(jobs), adjustments)
142         c.Check(adjustments < len(jobs)*len(jobs)/10, Equals, true)
143 }