github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/cgroups/fs/cpuacct.go (about) 1 // +build linux 2 3 package fs 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "path/filepath" 9 "strconv" 10 "strings" 11 12 "github.com/opencontainers/runc/libcontainer/cgroups" 13 "github.com/opencontainers/runc/libcontainer/configs" 14 "github.com/opencontainers/runc/libcontainer/system" 15 ) 16 17 const ( 18 cgroupCpuacctStat = "cpuacct.stat" 19 nanosecondsInSecond = 1000000000 20 ) 21 22 var clockTicks = uint64(system.GetClockTicks()) 23 24 type CpuacctGroup struct { 25 } 26 27 func (s *CpuacctGroup) Name() string { 28 return "cpuacct" 29 } 30 31 func (s *CpuacctGroup) Apply(d *cgroupData) error { 32 // we just want to join this group even though we don't set anything 33 if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) { 34 return err 35 } 36 37 return nil 38 } 39 40 func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error { 41 return nil 42 } 43 44 func (s *CpuacctGroup) Remove(d *cgroupData) error { 45 return removePath(d.path("cpuacct")) 46 } 47 48 func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error { 49 userModeUsage, kernelModeUsage, err := getCpuUsageBreakdown(path) 50 if err != nil { 51 return err 52 } 53 54 totalUsage, err := getCgroupParamUint(path, "cpuacct.usage") 55 if err != nil { 56 return err 57 } 58 59 percpuUsage, err := getPercpuUsage(path) 60 if err != nil { 61 return err 62 } 63 64 stats.CpuStats.CpuUsage.TotalUsage = totalUsage 65 stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage 66 stats.CpuStats.CpuUsage.UsageInUsermode = userModeUsage 67 stats.CpuStats.CpuUsage.UsageInKernelmode = kernelModeUsage 68 return nil 69 } 70 71 // Returns user and kernel usage breakdown in nanoseconds. 72 func getCpuUsageBreakdown(path string) (uint64, uint64, error) { 73 userModeUsage := uint64(0) 74 kernelModeUsage := uint64(0) 75 const ( 76 userField = "user" 77 systemField = "system" 78 ) 79 80 // Expected format: 81 // user <usage in ticks> 82 // system <usage in ticks> 83 data, err := ioutil.ReadFile(filepath.Join(path, cgroupCpuacctStat)) 84 if err != nil { 85 return 0, 0, err 86 } 87 fields := strings.Fields(string(data)) 88 if len(fields) != 4 { 89 return 0, 0, fmt.Errorf("failure - %s is expected to have 4 fields", filepath.Join(path, cgroupCpuacctStat)) 90 } 91 if fields[0] != userField { 92 return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[0], cgroupCpuacctStat, userField) 93 } 94 if fields[2] != systemField { 95 return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[2], cgroupCpuacctStat, systemField) 96 } 97 if userModeUsage, err = strconv.ParseUint(fields[1], 10, 64); err != nil { 98 return 0, 0, err 99 } 100 if kernelModeUsage, err = strconv.ParseUint(fields[3], 10, 64); err != nil { 101 return 0, 0, err 102 } 103 104 return (userModeUsage * nanosecondsInSecond) / clockTicks, (kernelModeUsage * nanosecondsInSecond) / clockTicks, nil 105 } 106 107 func getPercpuUsage(path string) ([]uint64, error) { 108 percpuUsage := []uint64{} 109 data, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.usage_percpu")) 110 if err != nil { 111 return percpuUsage, err 112 } 113 for _, value := range strings.Fields(string(data)) { 114 value, err := strconv.ParseUint(value, 10, 64) 115 if err != nil { 116 return percpuUsage, fmt.Errorf("Unable to convert param value to uint64: %s", err) 117 } 118 percpuUsage = append(percpuUsage, value) 119 } 120 return percpuUsage, nil 121 }