@@ -2,67 +2,132 @@ package main
22
33import (
44 "fmt"
5+ "os"
6+ "path/filepath"
7+ "runtime"
58
6- rspec "github.com/opencontainers/runtime-spec/specs -go"
9+ "github.com/mndrix/tap -go"
710 "github.com/opencontainers/runtime-tools/cgroups"
811 "github.com/opencontainers/runtime-tools/validation/util"
912)
1013
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" },
1952 }
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 ()
3256 if err != nil {
33- return err
57+ return fmt . Errorf ( "cannot get default config from generator: %v" , err )
3458 }
3559
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 )
3864 }
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 )
4168 }
4269
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 )
4572 }
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 )
4876 }
4977
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 )
5280 }
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 )
5588 }
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 )
5892 }
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 )
6196 }
62- return nil
63- })
97+ }
98+
99+ return nil
100+ }
64101
102+ func testEmptyCPU () error {
103+ t := tap .New ()
104+ t .Header (0 )
105+ defer t .AutoPlan ()
106+
107+ g , err := util .GetDefaultGenerator ()
65108 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 {
66131 util .Fatal (err )
67132 }
68133}
0 commit comments