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  }