Browse code

add cpu.cfs_period_us support

Signed-off-by: Ma Shimiao <mashimiao.fnst@cn.fujitsu.com>

Ma Shimiao authored on 2015/04/08 17:58:59
Showing 22 changed files
... ...
@@ -55,6 +55,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
55 55
 	flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
56 56
 	flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
57 57
 	flCPUShares := cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
58
+	flCpuPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
58 59
 	flCpuQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
59 60
 	flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
60 61
 	flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
... ...
@@ -275,6 +276,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
275 275
 	v.Set("cpusetmems", *flCPUSetMems)
276 276
 	v.Set("cpushares", strconv.FormatInt(*flCPUShares, 10))
277 277
 	v.Set("cpuquota", strconv.FormatInt(*flCpuQuota, 10))
278
+	v.Set("cpuperiod", strconv.FormatInt(*flCpuPeriod, 10))
278 279
 	v.Set("memory", strconv.FormatInt(memory, 10))
279 280
 	v.Set("memswap", strconv.FormatInt(memorySwap, 10))
280 281
 	v.Set("cgroupparent", *flCgroupParent)
... ...
@@ -1294,6 +1294,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht
1294 1294
 	buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
1295 1295
 	buildConfig.Memory = int64ValueOrZero(r, "memory")
1296 1296
 	buildConfig.CpuShares = int64ValueOrZero(r, "cpushares")
1297
+	buildConfig.CpuPeriod = int64ValueOrZero(r, "cpuperiod")
1297 1298
 	buildConfig.CpuQuota = int64ValueOrZero(r, "cpuquota")
1298 1299
 	buildConfig.CpuSetCpus = r.FormValue("cpusetcpus")
1299 1300
 	buildConfig.CpuSetMems = r.FormValue("cpusetmems")
... ...
@@ -152,6 +152,7 @@ type Info struct {
152 152
 	DriverStatus       [][2]string
153 153
 	MemoryLimit        bool
154 154
 	SwapLimit          bool
155
+	CpuCfsPeriod       bool
155 156
 	CpuCfsQuota        bool
156 157
 	IPv4Forwarding     bool
157 158
 	Debug              bool
... ...
@@ -124,6 +124,7 @@ type Builder struct {
124 124
 	cpuSetCpus   string
125 125
 	cpuSetMems   string
126 126
 	cpuShares    int64
127
+	cpuPeriod    int64
127 128
 	cpuQuota     int64
128 129
 	cgroupParent string
129 130
 	memory       int64
... ...
@@ -556,6 +556,7 @@ func (b *Builder) create() (*daemon.Container, error) {
556 556
 
557 557
 	hostConfig := &runconfig.HostConfig{
558 558
 		CpuShares:    b.cpuShares,
559
+		CpuPeriod:    b.cpuPeriod,
559 560
 		CpuQuota:     b.cpuQuota,
560 561
 		CpusetCpus:   b.cpuSetCpus,
561 562
 		CpusetMems:   b.cpuSetMems,
... ...
@@ -49,6 +49,7 @@ type Config struct {
49 49
 	Memory         int64
50 50
 	MemorySwap     int64
51 51
 	CpuShares      int64
52
+	CpuPeriod      int64
52 53
 	CpuQuota       int64
53 54
 	CpuSetCpus     string
54 55
 	CpuSetMems     string
... ...
@@ -164,6 +165,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
164 164
 		ConfigFile:      buildConfig.ConfigFile,
165 165
 		dockerfileName:  buildConfig.DockerfileName,
166 166
 		cpuShares:       buildConfig.CpuShares,
167
+		cpuPeriod:       buildConfig.CpuPeriod,
167 168
 		cpuQuota:        buildConfig.CpuQuota,
168 169
 		cpuSetCpus:      buildConfig.CpuSetCpus,
169 170
 		cpuSetMems:      buildConfig.CpuSetMems,
... ...
@@ -778,6 +778,7 @@ _docker_run() {
778 778
 		--cidfile
779 779
 		--cpuset
780 780
 		--cpu-shares -c
781
+		--cpu-period
781 782
 		--cpu-quota
782 783
 		--device
783 784
 		--dns
... ...
@@ -383,6 +383,7 @@ func populateCommand(c *Container, env []string) error {
383 383
 		CpuShares:      c.hostConfig.CpuShares,
384 384
 		CpusetCpus:     c.hostConfig.CpusetCpus,
385 385
 		CpusetMems:     c.hostConfig.CpusetMems,
386
+		CpuPeriod:      c.hostConfig.CpuPeriod,
386 387
 		CpuQuota:       c.hostConfig.CpuQuota,
387 388
 		BlkioWeight:    c.hostConfig.BlkioWeight,
388 389
 		Rlimits:        rlimits,
... ...
@@ -1170,6 +1170,10 @@ func (daemon *Daemon) verifyHostConfig(hostConfig *runconfig.HostConfig) ([]stri
1170 1170
 	if hostConfig.Memory == 0 && hostConfig.MemorySwap > 0 {
1171 1171
 		return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.")
1172 1172
 	}
1173
+	if hostConfig.CpuPeriod > 0 && !daemon.SystemConfig().CpuCfsPeriod {
1174
+		warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.")
1175
+		hostConfig.CpuPeriod = 0
1176
+	}
1173 1177
 	if hostConfig.CpuQuota > 0 && !daemon.SystemConfig().CpuCfsQuota {
1174 1178
 		warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.")
1175 1179
 		hostConfig.CpuQuota = 0
... ...
@@ -106,6 +106,7 @@ type Resources struct {
106 106
 	CpuShares      int64            `json:"cpu_shares"`
107 107
 	CpusetCpus     string           `json:"cpuset_cpus"`
108 108
 	CpusetMems     string           `json:"cpuset_mems"`
109
+	CpuPeriod      int64            `json:"cpu_period"`
109 110
 	CpuQuota       int64            `json:"cpu_quota"`
110 111
 	BlkioWeight    int64            `json:"blkio_weight"`
111 112
 	Rlimits        []*ulimit.Rlimit `json:"rlimits"`
... ...
@@ -53,6 +53,7 @@ func SetupCgroups(container *configs.Config, c *Command) error {
53 53
 		container.Cgroups.MemorySwap = c.Resources.MemorySwap
54 54
 		container.Cgroups.CpusetCpus = c.Resources.CpusetCpus
55 55
 		container.Cgroups.CpusetMems = c.Resources.CpusetMems
56
+		container.Cgroups.CpuPeriod = c.Resources.CpuPeriod
56 57
 		container.Cgroups.CpuQuota = c.Resources.CpuQuota
57 58
 		container.Cgroups.BlkioWeight = c.Resources.BlkioWeight
58 59
 		container.Cgroups.OomKillDisable = c.Resources.OomKillDisable
... ...
@@ -109,6 +109,9 @@ lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
109 109
 {{if .Resources.CpuShares}}
110 110
 lxc.cgroup.cpu.shares = {{.Resources.CpuShares}}
111 111
 {{end}}
112
+{{if .Resources.CpuPeriod}}
113
+lxc.cgroup.cpu.cfs_period_us = {{.Resources.CpuPeriod}}
114
+{{end}}
112 115
 {{if .Resources.CpusetCpus}}
113 116
 lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}}
114 117
 {{end}}
... ...
@@ -64,6 +64,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
64 64
 		DriverStatus:       daemon.GraphDriver().Status(),
65 65
 		MemoryLimit:        daemon.SystemConfig().MemoryLimit,
66 66
 		SwapLimit:          daemon.SystemConfig().SwapLimit,
67
+		CpuCfsPeriod:       daemon.SystemConfig().CpuCfsPeriod,
67 68
 		CpuCfsQuota:        daemon.SystemConfig().CpuCfsQuota,
68 69
 		IPv4Forwarding:     !daemon.SystemConfig().IPv4ForwardingDisabled,
69 70
 		Debug:              os.Getenv("DEBUG") != "",
... ...
@@ -13,6 +13,7 @@ docker-create - Create a new container
13 13
 [**--cap-add**[=*[]*]]
14 14
 [**--cap-drop**[=*[]*]]
15 15
 [**--cidfile**[=*CIDFILE*]]
16
+[**--cpu-period**[=*0*]]
16 17
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
17 18
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
18 19
 [**--cpu-quota**[=*0*]]
... ...
@@ -78,6 +79,9 @@ IMAGE [COMMAND] [ARG...]
78 78
 **--cgroup-parent**=""
79 79
    Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
80 80
 
81
+**--cpu-peroid**=0
82
+    Limit the CPU CFS (Completely Fair Scheduler) period
83
+
81 84
 **--cpuset-cpus**=""
82 85
    CPUs in which to allow execution (0-3, 0,1)
83 86
 
... ...
@@ -13,6 +13,7 @@ docker-run - Run a command in a new container
13 13
 [**--cap-add**[=*[]*]]
14 14
 [**--cap-drop**[=*[]*]]
15 15
 [**--cidfile**[=*CIDFILE*]]
16
+[**--cpu-period**[=*0*]]
16 17
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
17 18
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
18 19
 [**-d**|**--detach**[=*false*]]
... ...
@@ -138,6 +139,11 @@ division of CPU shares:
138 138
 **--cidfile**=""
139 139
    Write the container ID to the file
140 140
 
141
+**--cpu-period**=0
142
+   Limit the CPU CFS (Completely Fair Scheduler) period
143
+
144
+   Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
145
+
141 146
 **--cpuset-cpus**=""
142 147
    CPUs in which to allow execution (0-3, 0,1)
143 148
 
... ...
@@ -147,6 +147,7 @@ Create a container
147 147
                "Memory": 0,
148 148
                "MemorySwap": 0,
149 149
                "CpuShares": 512,
150
+               "CpuPeriod": 100000,
150 151
                "CpusetCpus": "0,1",
151 152
                "CpusetMems": "0,1",
152 153
                "BlkioWeight": 300,
... ...
@@ -193,6 +194,7 @@ Json Parameters:
193 193
       always use this with `memory`, and make the value larger than `memory`.
194 194
 -   **CpuShares** - An integer value containing the CPU Shares for container
195 195
       (ie. the relative weight vs other containers).
196
+-   **CpuPeriod** - The length of a CPU period (in microseconds).
196 197
 -   **Cpuset** - The same as CpusetCpus, but deprecated, please don't use.
197 198
 -   **CpusetCpus** - String value containing the cgroups CpusetCpus to use.
198 199
 -   **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
... ...
@@ -350,6 +352,7 @@ Return low-level information on the container `id`
350 350
 			"CpusetCpus": "",
351 351
 			"CpusetMems": "",
352 352
 			"CpuShares": 0,
353
+			"CpuPeriod": 100000,
353 354
 			"Devices": [],
354 355
 			"Dns": null,
355 356
 			"DnsSearch": null,
... ...
@@ -950,6 +950,7 @@ Creates a new container.
950 950
       --cidfile=""               Write the container ID to the file
951 951
       --cpuset-cpus=""           CPUs in which to allow execution (0-3, 0,1)
952 952
       --cpuset-mems=""           Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
953
+      --cpu-period=0             Limit the CPU CFS (Completely Fair Scheduler) period
953 954
       --cpu-quota=0              Limit the CPU CFS (Completely Fair Scheduler) quota
954 955
       --device=[]                Add a host device to the container
955 956
       --dns=[]                   Set custom DNS servers
... ...
@@ -1907,6 +1908,7 @@ To remove an image using its digest:
1907 1907
       --cidfile=""               Write the container ID to the file
1908 1908
       --cpuset-cpus=""           CPUs in which to allow execution (0-3, 0,1)
1909 1909
       --cpuset-mems=""           Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
1910
+      --cpu-period=0             Limit the CPU CFS (Completely Fair Scheduler) period
1910 1911
       --cpu-quota=0              Limit the CPU CFS (Completely Fair Scheduler) quota
1911 1912
       -d, --detach=false         Run container in background and print container ID
1912 1913
       --device=[]                Add a host device to the container
... ...
@@ -483,6 +483,7 @@ container:
483 483
     -m, --memory="": Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
484 484
     -memory-swap="": Total memory limit (memory + swap, format: <number><optional unit>, where unit = b, k, m or g)
485 485
     -c, --cpu-shares=0: CPU shares (relative weight)
486
+    --cpu-period=0: Limit the CPU CFS (Completely Fair Scheduler) period
486 487
     --cpuset-cpus="": CPUs in which to allow execution (0-3, 0,1)
487 488
     --cpuset-mems="": Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
488 489
     --cpu-quota=0: Limit the CPU CFS (Completely Fair Scheduler) quota
... ...
@@ -620,6 +621,20 @@ division of CPU shares:
620 620
     101    {C1}		1	100% of CPU1
621 621
     102    {C1}		2	100% of CPU2
622 622
 
623
+### CPU period constraint
624
+
625
+The default CPU CFS (Completely Fair Scheduler) period is 100ms. We can use
626
+`--cpu-period` to set the period of CPUs to limit the container's CPU usage. 
627
+And usually `--cpu-period` should work with `--cpu-quota`.
628
+
629
+Examples:
630
+
631
+    $ docker run -ti --cpu-period=50000 --cpu-quota=25000 ubuntu:14.04 /bin/bash
632
+
633
+If there is 1 CPU, this means the container can get 50% CPU worth of run-time every 50ms.
634
+
635
+For more information, see the [CFS documentation on bandwidth limiting](https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt).
636
+
623 637
 ### Cpuset constraint
624 638
 
625 639
 We can set cpus in which to allow execution for containers.
... ...
@@ -1164,6 +1164,28 @@ func (s *DockerSuite) TestRunProcWritableInPrivilegedContainers(c *check.C) {
1164 1164
 	}
1165 1165
 }
1166 1166
 
1167
+func (s *DockerSuite) TestRunWithCpuPeriod(c *check.C) {
1168
+	runCmd := exec.Command(dockerBinary, "run", "--cpu-period", "50000", "--name", "test", "busybox", "true")
1169
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
1170
+	if err != nil {
1171
+		c.Fatalf("failed to run container: %v, output: %q", err, out)
1172
+	}
1173
+	out = strings.TrimSpace(out)
1174
+	if strings.Contains(out, "Your kernel does not support CPU cfs period") {
1175
+		c.Skip("Your kernel does not support CPU cfs period, skip this test")
1176
+	}
1177
+
1178
+	cmd := exec.Command(dockerBinary, "inspect", "-f", "{{.HostConfig.CpuPeriod}}", "test")
1179
+	out, _, err = runCommandWithOutput(cmd)
1180
+	if err != nil {
1181
+		c.Fatalf("failed to inspect container: %s, %v", out, err)
1182
+	}
1183
+	out = strings.TrimSpace(out)
1184
+	if out != "50000" {
1185
+		c.Errorf("setting the CPU CFS period failed")
1186
+	}
1187
+}
1188
+
1167 1189
 func (s *DockerSuite) TestRunWithCpuset(c *check.C) {
1168 1190
 	cmd := exec.Command(dockerBinary, "run", "--cpuset", "0", "busybox", "true")
1169 1191
 	if code, err := runCommand(cmd); err != nil || code != 0 {
... ...
@@ -15,6 +15,7 @@ import (
15 15
 type SysInfo struct {
16 16
 	MemoryLimit            bool
17 17
 	SwapLimit              bool
18
+	CpuCfsPeriod           bool
18 19
 	CpuCfsQuota            bool
19 20
 	IPv4ForwardingDisabled bool
20 21
 	AppArmor               bool
... ...
@@ -50,8 +51,15 @@ func New(quiet bool) *SysInfo {
50 50
 			logrus.Warnf("%v", err)
51 51
 		}
52 52
 	} else {
53
-		_, err1 := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_quota_us"))
54
-		sysInfo.CpuCfsQuota = err1 == nil
53
+		_, err := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_period_us"))
54
+		logrus.Warnf("%s", cgroupCpuMountpoint)
55
+		sysInfo.CpuCfsPeriod = err == nil
56
+		if !sysInfo.CpuCfsPeriod && !quiet {
57
+			logrus.Warnf("WARING: Your kernel does not support cgroup cfs period")
58
+		}
59
+		_, err = ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_quota_us"))
60
+		logrus.Warnf("%s", cgroupCpuMountpoint)
61
+		sysInfo.CpuCfsQuota = err == nil
55 62
 		if !sysInfo.CpuCfsQuota && !quiet {
56 63
 			logrus.Warn("Your kernel does not support cgroup cfs quotas")
57 64
 		}
... ...
@@ -166,9 +166,10 @@ type HostConfig struct {
166 166
 	Binds           []string
167 167
 	ContainerIDFile string
168 168
 	LxcConf         *LxcConfig
169
-	Memory          int64  // Memory limit (in bytes)
170
-	MemorySwap      int64  // Total memory usage (memory + swap); set `-1` to disable swap
171
-	CpuShares       int64  // CPU shares (relative weight vs. other containers)
169
+	Memory          int64 // Memory limit (in bytes)
170
+	MemorySwap      int64 // Total memory usage (memory + swap); set `-1` to disable swap
171
+	CpuShares       int64 // CPU shares (relative weight vs. other containers)
172
+	CpuPeriod       int64
172 173
 	CpusetCpus      string // CpusetCpus 0-2, 0,1
173 174
 	CpusetMems      string // CpusetMems 0-2, 0,1
174 175
 	CpuQuota        int64
... ...
@@ -64,6 +64,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
64 64
 		flUser            = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: <name|uid>[:<group|gid>])")
65 65
 		flWorkingDir      = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
66 66
 		flCpuShares       = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
67
+		flCpuPeriod       = cmd.Int64([]string{"-cpu-period"}, 0, "Limit CPU CFS (Completely Fair Scheduler) period")
67 68
 		flCpusetCpus      = cmd.String([]string{"#-cpuset", "-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
68 69
 		flCpusetMems      = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
69 70
 		flCpuQuota        = cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS quota")
... ...
@@ -319,6 +320,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
319 319
 		Memory:          flMemory,
320 320
 		MemorySwap:      MemorySwap,
321 321
 		CpuShares:       *flCpuShares,
322
+		CpuPeriod:       *flCpuPeriod,
322 323
 		CpusetCpus:      *flCpusetCpus,
323 324
 		CpusetMems:      *flCpusetMems,
324 325
 		CpuQuota:        *flCpuQuota,