...

Source file src/github.com/containerd/cgroups/cpuacct.go

Documentation: github.com/containerd/cgroups

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package cgroups
    18  
    19  import (
    20  	"bufio"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"strconv"
    25  	"strings"
    26  
    27  	v1 "github.com/containerd/cgroups/stats/v1"
    28  )
    29  
    30  const nanosecondsInSecond = 1000000000
    31  
    32  var clockTicks = getClockTicks()
    33  
    34  func NewCpuacct(root string) *cpuacctController {
    35  	return &cpuacctController{
    36  		root: filepath.Join(root, string(Cpuacct)),
    37  	}
    38  }
    39  
    40  type cpuacctController struct {
    41  	root string
    42  }
    43  
    44  func (c *cpuacctController) Name() Name {
    45  	return Cpuacct
    46  }
    47  
    48  func (c *cpuacctController) Path(path string) string {
    49  	return filepath.Join(c.root, path)
    50  }
    51  
    52  func (c *cpuacctController) Stat(path string, stats *v1.Metrics) error {
    53  	user, kernel, err := c.getUsage(path)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	total, err := readUint(filepath.Join(c.Path(path), "cpuacct.usage"))
    58  	if err != nil {
    59  		return err
    60  	}
    61  	percpu, err := c.percpuUsage(path)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	stats.CPU.Usage.Total = total
    66  	stats.CPU.Usage.User = user
    67  	stats.CPU.Usage.Kernel = kernel
    68  	stats.CPU.Usage.PerCPU = percpu
    69  	return nil
    70  }
    71  
    72  func (c *cpuacctController) percpuUsage(path string) ([]uint64, error) {
    73  	var usage []uint64
    74  	data, err := os.ReadFile(filepath.Join(c.Path(path), "cpuacct.usage_percpu"))
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	for _, v := range strings.Fields(string(data)) {
    79  		u, err := strconv.ParseUint(v, 10, 64)
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  		usage = append(usage, u)
    84  	}
    85  	return usage, nil
    86  }
    87  
    88  func (c *cpuacctController) getUsage(path string) (user uint64, kernel uint64, err error) {
    89  	statPath := filepath.Join(c.Path(path), "cpuacct.stat")
    90  	f, err := os.Open(statPath)
    91  	if err != nil {
    92  		return 0, 0, err
    93  	}
    94  	defer f.Close()
    95  	var (
    96  		raw = make(map[string]uint64)
    97  		sc  = bufio.NewScanner(f)
    98  	)
    99  	for sc.Scan() {
   100  		key, v, err := parseKV(sc.Text())
   101  		if err != nil {
   102  			return 0, 0, err
   103  		}
   104  		raw[key] = v
   105  	}
   106  	if err := sc.Err(); err != nil {
   107  		return 0, 0, err
   108  	}
   109  	for _, t := range []struct {
   110  		name  string
   111  		value *uint64
   112  	}{
   113  		{
   114  			name:  "user",
   115  			value: &user,
   116  		},
   117  		{
   118  			name:  "system",
   119  			value: &kernel,
   120  		},
   121  	} {
   122  		v, ok := raw[t.name]
   123  		if !ok {
   124  			return 0, 0, fmt.Errorf("expected field %q but not found in %q", t.name, statPath)
   125  		}
   126  		*t.value = v
   127  	}
   128  	return (user * nanosecondsInSecond) / clockTicks, (kernel * nanosecondsInSecond) / clockTicks, nil
   129  }
   130  

View as plain text