github.com/elastic/gosigar@v0.14.3/cgroup/cpuacct.go (about)

     1  package cgroup
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/elastic/gosigar/sys/linux"
    12  )
    13  
    14  var clockTicks = uint64(linux.GetClockTicks())
    15  
    16  // CPUAccountingSubsystem contains metrics from the "cpuacct" subsystem.
    17  type CPUAccountingSubsystem struct {
    18  	Metadata
    19  	TotalNanos  uint64   `json:"total_nanos"`
    20  	UsagePerCPU []uint64 `json:"usage_percpu_nanos"`
    21  	// CPU time statistics for tasks in this cgroup.
    22  	Stats CPUAccountingStats `json:"stats,omitempty"`
    23  }
    24  
    25  // CPUAccountingStats contains the stats reported from the cpuacct subsystem.
    26  type CPUAccountingStats struct {
    27  	UserNanos   uint64 `json:"user_nanos"`
    28  	SystemNanos uint64 `json:"system_nanos"`
    29  }
    30  
    31  // get reads metrics from the "cpuacct" subsystem. path is the filepath to the
    32  // cgroup hierarchy to read.
    33  func (cpuacct *CPUAccountingSubsystem) get(path string) error {
    34  	if err := cpuacctStat(path, cpuacct); err != nil {
    35  		return err
    36  	}
    37  
    38  	if err := cpuacctUsage(path, cpuacct); err != nil {
    39  		return err
    40  	}
    41  
    42  	if err := cpuacctUsagePerCPU(path, cpuacct); err != nil {
    43  		return err
    44  	}
    45  
    46  	return nil
    47  }
    48  
    49  func cpuacctStat(path string, cpuacct *CPUAccountingSubsystem) error {
    50  	f, err := os.Open(filepath.Join(path, "cpuacct.stat"))
    51  	if err != nil {
    52  		if os.IsNotExist(err) {
    53  			return nil
    54  		}
    55  		return err
    56  	}
    57  	defer f.Close()
    58  
    59  	sc := bufio.NewScanner(f)
    60  	for sc.Scan() {
    61  		t, v, err := parseCgroupParamKeyValue(sc.Text())
    62  		if err != nil {
    63  			return err
    64  		}
    65  		switch t {
    66  		case "user":
    67  			cpuacct.Stats.UserNanos = convertJiffiesToNanos(v)
    68  		case "system":
    69  			cpuacct.Stats.SystemNanos = convertJiffiesToNanos(v)
    70  		}
    71  	}
    72  
    73  	return sc.Err()
    74  }
    75  
    76  func cpuacctUsage(path string, cpuacct *CPUAccountingSubsystem) error {
    77  	var err error
    78  	cpuacct.TotalNanos, err = parseUintFromFile(path, "cpuacct.usage")
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	return nil
    84  }
    85  
    86  func cpuacctUsagePerCPU(path string, cpuacct *CPUAccountingSubsystem) error {
    87  	contents, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.usage_percpu"))
    88  	if err != nil {
    89  		if os.IsNotExist(err) {
    90  			return nil
    91  		}
    92  		return err
    93  	}
    94  
    95  	var values []uint64
    96  	usages := bytes.Fields(contents)
    97  	for _, usage := range usages {
    98  		value, err := parseUint(usage)
    99  		if err != nil {
   100  			return err
   101  		}
   102  
   103  		values = append(values, value)
   104  	}
   105  	cpuacct.UsagePerCPU = values
   106  
   107  	return nil
   108  }
   109  
   110  func convertJiffiesToNanos(j uint64) uint64 {
   111  	return (j * uint64(time.Second)) / clockTicks
   112  }