13399: Adjust locking strategy to avoid starvation.
[arvados.git] / services / crunch-dispatch-slurm / priority.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package main
6
7 const defaultSpread int64 = 10
8
9 // wantNice calculates appropriate nice values for a set of SLURM
10 // jobs. The returned slice will have len(jobs) elements.
11 //
12 // spread is a positive amount of space to leave between adjacent
13 // priorities when making adjustments. Generally, increasing spread
14 // reduces the total number of adjustments made. A smaller spread
15 // produces lower nice values, which is useful for old SLURM versions
16 // with a limited "nice" range and for sites where SLURM is also
17 // running non-Arvados jobs with low nice values.
18 //
19 // If spread<1, a sensible default (10) is used.
20 func wantNice(jobs []*slurmJob, spread int64) []int64 {
21         if len(jobs) == 0 {
22                 return nil
23         }
24
25         if spread < 1 {
26                 spread = defaultSpread
27         }
28         renice := make([]int64, len(jobs))
29
30         // highest usable priority (without going out of order)
31         var target int64
32         for i, job := range jobs {
33                 if i == 0 {
34                         // renice[0] is always zero, so our highest
35                         // priority container gets the highest
36                         // possible slurm priority.
37                         target = job.priority + job.nice
38                 } else if space := target - job.priority; space >= 0 && space < (spread-1)*10 {
39                         // Ordering is correct, and interval isn't too
40                         // large. Leave existing nice value alone.
41                         renice[i] = job.nice
42                         target = job.priority
43                 } else {
44                         target -= (spread - 1)
45                         if possible := job.priority + job.nice; target > possible {
46                                 // renice[i] is already 0, that's the
47                                 // best we can do
48                                 target = possible
49                         } else {
50                                 renice[i] = possible - target
51                         }
52                 }
53                 target--
54         }
55         return renice
56 }