cpu.go (2829B)
1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cgroup1 18 19 import ( 20 "bufio" 21 "os" 22 "path/filepath" 23 "strconv" 24 25 v1 "github.com/containerd/cgroups/v3/cgroup1/stats" 26 specs "github.com/opencontainers/runtime-spec/specs-go" 27 ) 28 29 func NewCpu(root string) *cpuController { 30 return &cpuController{ 31 root: filepath.Join(root, string(Cpu)), 32 } 33 } 34 35 type cpuController struct { 36 root string 37 } 38 39 func (c *cpuController) Name() Name { 40 return Cpu 41 } 42 43 func (c *cpuController) Path(path string) string { 44 return filepath.Join(c.root, path) 45 } 46 47 func (c *cpuController) Create(path string, resources *specs.LinuxResources) error { 48 if err := os.MkdirAll(c.Path(path), defaultDirPerm); err != nil { 49 return err 50 } 51 if cpu := resources.CPU; cpu != nil { 52 for _, t := range []struct { 53 name string 54 ivalue *int64 55 uvalue *uint64 56 }{ 57 { 58 name: "rt_period_us", 59 uvalue: cpu.RealtimePeriod, 60 }, 61 { 62 name: "rt_runtime_us", 63 ivalue: cpu.RealtimeRuntime, 64 }, 65 { 66 name: "shares", 67 uvalue: cpu.Shares, 68 }, 69 { 70 name: "cfs_period_us", 71 uvalue: cpu.Period, 72 }, 73 { 74 name: "cfs_quota_us", 75 ivalue: cpu.Quota, 76 }, 77 } { 78 var value []byte 79 if t.uvalue != nil { 80 value = []byte(strconv.FormatUint(*t.uvalue, 10)) 81 } else if t.ivalue != nil { 82 value = []byte(strconv.FormatInt(*t.ivalue, 10)) 83 } 84 if value != nil { 85 if err := os.WriteFile( 86 filepath.Join(c.Path(path), "cpu."+t.name), 87 value, 88 defaultFilePerm, 89 ); err != nil { 90 return err 91 } 92 } 93 } 94 } 95 return nil 96 } 97 98 func (c *cpuController) Update(path string, resources *specs.LinuxResources) error { 99 return c.Create(path, resources) 100 } 101 102 func (c *cpuController) Stat(path string, stats *v1.Metrics) error { 103 f, err := os.Open(filepath.Join(c.Path(path), "cpu.stat")) 104 if err != nil { 105 return err 106 } 107 defer f.Close() 108 // get or create the cpu field because cpuacct can also set values on this struct 109 sc := bufio.NewScanner(f) 110 for sc.Scan() { 111 key, v, err := parseKV(sc.Text()) 112 if err != nil { 113 return err 114 } 115 switch key { 116 case "nr_periods": 117 stats.CPU.Throttling.Periods = v 118 case "nr_throttled": 119 stats.CPU.Throttling.ThrottledPeriods = v 120 case "throttled_time": 121 stats.CPU.Throttling.ThrottledTime = v 122 } 123 } 124 return sc.Err() 125 }