@@ -2,67 +2,132 @@ package main
2
2
3
3
import (
4
4
"fmt"
5
+ "os"
6
+ "path/filepath"
7
+ "runtime"
5
8
6
- rspec "github.com/opencontainers/runtime-spec/specs -go"
9
+ "github.com/mndrix/tap -go"
7
10
"github.com/opencontainers/runtime-tools/cgroups"
8
11
"github.com/opencontainers/runtime-tools/validation/util"
9
12
)
10
13
11
- func main () {
12
- var shares uint64 = 1024
13
- var period uint64 = 100000
14
- var quota int64 = 50000
15
- var cpus , mems string = "0-1" , "0"
16
- g , err := util .GetDefaultGenerator ()
17
- if err != nil {
18
- util .Fatal (err )
14
+ const (
15
+ defaultRealtimePeriod uint64 = 1000000
16
+ defaultRealtimeRuntime int64 = 950000
17
+ )
18
+
19
+ func testCPUCgroups () error {
20
+ t := tap .New ()
21
+ t .Header (0 )
22
+ defer t .AutoPlan ()
23
+
24
+ CPUrange := fmt .Sprintf ("0-%d" , runtime .NumCPU ()- 1 )
25
+
26
+ // Test with different combinations of values.
27
+ // NOTE: most systems have only one memory node (mems=="0"), so we cannot
28
+ // simply test with multiple values of mems.
29
+ cases := []struct {
30
+ shares uint64
31
+ period uint64
32
+ quota int64
33
+ cpus string
34
+ mems string
35
+ }{
36
+ {1024 , 100000 , 50000 , "0" , "0" },
37
+ {1024 , 100000 , 50000 , CPUrange , "0" },
38
+ {1024 , 100000 , 200000 , "0" , "0" },
39
+ {1024 , 100000 , 200000 , CPUrange , "0" },
40
+ {1024 , 500000 , 50000 , "0" , "0" },
41
+ {1024 , 500000 , 50000 , CPUrange , "0" },
42
+ {1024 , 500000 , 200000 , "0" , "0" },
43
+ {1024 , 500000 , 200000 , CPUrange , "0" },
44
+ {2048 , 100000 , 50000 , "0" , "0" },
45
+ {2048 , 100000 , 50000 , CPUrange , "0" },
46
+ {2048 , 100000 , 200000 , "0" , "0" },
47
+ {2048 , 100000 , 200000 , CPUrange , "0" },
48
+ {2048 , 500000 , 50000 , "0" , "0" },
49
+ {2048 , 500000 , 50000 , CPUrange , "0" },
50
+ {2048 , 500000 , 200000 , "0" , "0" },
51
+ {2048 , 500000 , 200000 , CPUrange , "0" },
19
52
}
20
- g .SetLinuxCgroupsPath (cgroups .AbsCgroupPath )
21
- g .SetLinuxResourcesCPUShares (shares )
22
- g .SetLinuxResourcesCPUQuota (quota )
23
- g .SetLinuxResourcesCPUPeriod (period )
24
- g .SetLinuxResourcesCPUCpus (cpus )
25
- g .SetLinuxResourcesCPUMems (mems )
26
- err = util .RuntimeOutsideValidate (g , func (config * rspec.Spec , state * rspec.State ) error {
27
- cg , err := cgroups .FindCgroup ()
28
- if err != nil {
29
- return err
30
- }
31
- lcd , err := cg .GetCPUData (state .Pid , config .Linux .CgroupsPath )
53
+
54
+ for _ , c := range cases {
55
+ g , err := util .GetDefaultGenerator ()
32
56
if err != nil {
33
- return err
57
+ return fmt . Errorf ( "cannot get default config from generator: %v" , err )
34
58
}
35
59
36
- if lcd .Shares == nil {
37
- return fmt .Errorf ("unable to get cpu shares, lcd.Shares == %v" , lcd .Shares )
60
+ g .SetLinuxCgroupsPath (cgroups .AbsCgroupPath )
61
+
62
+ if c .shares > 0 {
63
+ g .SetLinuxResourcesCPUShares (c .shares )
38
64
}
39
- if * lcd .Shares != shares {
40
- return fmt .Errorf ("cpus shares limit is not set correctly, expect: %d, actual: %d" , shares , * lcd .Shares )
65
+
66
+ if c .period > 0 {
67
+ g .SetLinuxResourcesCPUPeriod (c .period )
41
68
}
42
69
43
- if lcd . Quota == nil {
44
- return fmt . Errorf ( "unable to get cpu quota, lcd.Quota == %v" , lcd . Quota )
70
+ if c . quota > 0 {
71
+ g . SetLinuxResourcesCPUQuota ( c . quota )
45
72
}
46
- if * lcd .Quota != quota {
47
- return fmt .Errorf ("cpus quota is not set correctly, expect: %d, actual: %d" , quota , * lcd .Quota )
73
+
74
+ if c .cpus != "" {
75
+ g .SetLinuxResourcesCPUCpus (c .cpus )
48
76
}
49
77
50
- if lcd . Period == nil {
51
- return fmt . Errorf ( "unable to get cpu period, lcd.Period == %v" , lcd . Period )
78
+ if c . mems != "" {
79
+ g . SetLinuxResourcesCPUMems ( c . mems )
52
80
}
53
- if * lcd .Period != period {
54
- return fmt .Errorf ("cpus period is not set correctly, expect: %d, actual: %d" , period , * lcd .Period )
81
+
82
+ // NOTE: On most systems where CONFIG_RT_GROUP & CONFIG_RT_GROUP_SCHED are not enabled,
83
+ // the following tests will fail, because sysfs knobs like
84
+ // /sys/fs/cgroup/cpu,cpuacct/cpu.rt_{period,runtime}_us do not exist.
85
+ // So we need to check if the sysfs knobs exist before setting the variables.
86
+ if _ , err := os .Stat (filepath .Join (util .CPUCgroupPrefix , "cpu.rt_period_us" )); ! os .IsNotExist (err ) {
87
+ g .SetLinuxResourcesCPURealtimePeriod (defaultRealtimePeriod )
55
88
}
56
- if lcd .Cpus != cpus {
57
- return fmt .Errorf ("cpus cpus is not set correctly, expect: %s, actual: %s" , cpus , lcd .Cpus )
89
+
90
+ if _ , err := os .Stat (filepath .Join (util .CPUCgroupPrefix , "cpu.rt_runtime_us" )); ! os .IsNotExist (err ) {
91
+ g .SetLinuxResourcesCPURealtimeRuntime (defaultRealtimeRuntime )
58
92
}
59
- if lcd .Mems != mems {
60
- return fmt .Errorf ("cpus mems is not set correctly, expect: %s, actual: %s" , mems , lcd .Mems )
93
+
94
+ if err := util .RuntimeOutsideValidate (g , t , util .ValidateLinuxResourcesCPU ); err != nil {
95
+ return fmt .Errorf ("cannot validate CPU cgroups: %v" , err )
61
96
}
62
- return nil
63
- })
97
+ }
98
+
99
+ return nil
100
+ }
64
101
102
+ func testEmptyCPU () error {
103
+ t := tap .New ()
104
+ t .Header (0 )
105
+ defer t .AutoPlan ()
106
+
107
+ g , err := util .GetDefaultGenerator ()
65
108
if err != nil {
109
+ return fmt .Errorf ("cannot get default config from generator: %v" , err )
110
+ }
111
+ g .InitConfigLinuxResourcesCPU ()
112
+ g .SetLinuxCgroupsPath (cgroups .AbsCgroupPath )
113
+
114
+ if err := util .RuntimeOutsideValidate (g , t , util .ValidateLinuxResourcesCPUEmpty ); err != nil {
115
+ return fmt .Errorf ("cannot validate empty CPU cgroups: %v" , err )
116
+ }
117
+
118
+ return nil
119
+ }
120
+
121
+ func main () {
122
+ if "linux" != runtime .GOOS {
123
+ util .Fatal (fmt .Errorf ("linux-specific cgroup test" ))
124
+ }
125
+
126
+ if err := testCPUCgroups (); err != nil {
127
+ util .Fatal (err )
128
+ }
129
+
130
+ if err := testEmptyCPU (); err != nil {
66
131
util .Fatal (err )
67
132
}
68
133
}
0 commit comments