package cgroups import ( "fmt" "io/ioutil" "path/filepath" "strconv" "strings" ) const nanosecondsInSecond = 1000000000 var clockTicks = getClockTicks() func NewCpuacct(root string) *cpuacctController { return &cpuacctController{ root: filepath.Join(root, string(Cpuacct)), } } type cpuacctController struct { root string } func (c *cpuacctController) Name() Name { return Cpuacct } func (c *cpuacctController) Path(path string) string { return filepath.Join(c.root, path) } func (c *cpuacctController) Stat(path string, stats *Stats) error { user, kernel, err := c.getUsage(path) if err != nil { return err } total, err := readUint(filepath.Join(c.Path(path), "cpuacct.usage")) if err != nil { return err } percpu, err := c.percpuUsage(path) if err != nil { return err } stats.cpuMu.Lock() cpu := stats.Cpu if cpu == nil { cpu = &CpuStat{} stats.Cpu = cpu } stats.cpuMu.Unlock() cpu.Usage.Total = total cpu.Usage.User = user cpu.Usage.Kernel = kernel cpu.Usage.PerCpu = percpu return nil } func (c *cpuacctController) percpuUsage(path string) ([]uint64, error) { var usage []uint64 data, err := ioutil.ReadFile(filepath.Join(c.Path(path), "cpuacct.usage_percpu")) if err != nil { return nil, err } for _, v := range strings.Fields(string(data)) { u, err := strconv.ParseUint(v, 10, 64) if err != nil { return nil, err } usage = append(usage, u) } return usage, nil } func (c *cpuacctController) getUsage(path string) (user uint64, kernel uint64, err error) { statPath := filepath.Join(c.Path(path), "cpuacct.stat") data, err := ioutil.ReadFile(statPath) if err != nil { return 0, 0, err } fields := strings.Fields(string(data)) if len(fields) != 4 { return 0, 0, fmt.Errorf("%q is expected to have 4 fields", statPath) } for _, t := range []struct { index int name string value *uint64 }{ { index: 0, name: "user", value: &user, }, { index: 2, name: "system", value: &kernel, }, } { if fields[t.index] != t.name { return 0, 0, fmt.Errorf("expected field %q but found %q in %q", t.name, fields[t.index], statPath) } v, err := strconv.ParseUint(fields[t.index+1], 10, 64) if err != nil { return 0, 0, err } *t.value = v } return (user * nanosecondsInSecond) / clockTicks, (kernel * nanosecondsInSecond) / clockTicks, nil }