gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

cpuacct.go (2878B)


      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 cgroup1
     18 
     19 import (
     20 	"bufio"
     21 	"fmt"
     22 	"os"
     23 	"path/filepath"
     24 	"strconv"
     25 	"strings"
     26 
     27 	v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
     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 }