123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- // +build linux
- package fs
- import (
- "fmt"
- "io/ioutil"
- "path/filepath"
- "strconv"
- "strings"
- "github.com/opencontainers/runc/libcontainer/cgroups"
- "github.com/opencontainers/runc/libcontainer/configs"
- "github.com/opencontainers/runc/libcontainer/system"
- )
- const (
- cgroupCpuacctStat = "cpuacct.stat"
- nanosecondsInSecond = 1000000000
- )
- var clockTicks = uint64(system.GetClockTicks())
- type CpuacctGroup struct {
- }
- func (s *CpuacctGroup) Name() string {
- return "cpuacct"
- }
- func (s *CpuacctGroup) Apply(d *cgroupData) error {
- // we just want to join this group even though we don't set anything
- if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
- }
- func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error {
- return nil
- }
- func (s *CpuacctGroup) Remove(d *cgroupData) error {
- return removePath(d.path("cpuacct"))
- }
- func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
- userModeUsage, kernelModeUsage, err := getCpuUsageBreakdown(path)
- if err != nil {
- return err
- }
- totalUsage, err := getCgroupParamUint(path, "cpuacct.usage")
- if err != nil {
- return err
- }
- percpuUsage, err := getPercpuUsage(path)
- if err != nil {
- return err
- }
- stats.CpuStats.CpuUsage.TotalUsage = totalUsage
- stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage
- stats.CpuStats.CpuUsage.UsageInUsermode = userModeUsage
- stats.CpuStats.CpuUsage.UsageInKernelmode = kernelModeUsage
- return nil
- }
- // Returns user and kernel usage breakdown in nanoseconds.
- func getCpuUsageBreakdown(path string) (uint64, uint64, error) {
- userModeUsage := uint64(0)
- kernelModeUsage := uint64(0)
- const (
- userField = "user"
- systemField = "system"
- )
- // Expected format:
- // user <usage in ticks>
- // system <usage in ticks>
- data, err := ioutil.ReadFile(filepath.Join(path, cgroupCpuacctStat))
- if err != nil {
- return 0, 0, err
- }
- fields := strings.Fields(string(data))
- if len(fields) != 4 {
- return 0, 0, fmt.Errorf("failure - %s is expected to have 4 fields", filepath.Join(path, cgroupCpuacctStat))
- }
- if fields[0] != userField {
- return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[0], cgroupCpuacctStat, userField)
- }
- if fields[2] != systemField {
- return 0, 0, fmt.Errorf("unexpected field %q in %q, expected %q", fields[2], cgroupCpuacctStat, systemField)
- }
- if userModeUsage, err = strconv.ParseUint(fields[1], 10, 64); err != nil {
- return 0, 0, err
- }
- if kernelModeUsage, err = strconv.ParseUint(fields[3], 10, 64); err != nil {
- return 0, 0, err
- }
- return (userModeUsage * nanosecondsInSecond) / clockTicks, (kernelModeUsage * nanosecondsInSecond) / clockTicks, nil
- }
- func getPercpuUsage(path string) ([]uint64, error) {
- percpuUsage := []uint64{}
- data, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.usage_percpu"))
- if err != nil {
- return percpuUsage, err
- }
- for _, value := range strings.Fields(string(data)) {
- value, err := strconv.ParseUint(value, 10, 64)
- if err != nil {
- return percpuUsage, fmt.Errorf("Unable to convert param value to uint64: %s", err)
- }
- percpuUsage = append(percpuUsage, value)
- }
- return percpuUsage, nil
- }
|