github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/cgroup/common/cgroup_linux.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright 2022 The Katalyst Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package common
    21  
    22  import (
    23  	"bufio"
    24  	"fmt"
    25  	"io/ioutil"
    26  	"math"
    27  	"os"
    28  	"path/filepath"
    29  	"strconv"
    30  	"strings"
    31  
    32  	"github.com/opencontainers/runc/libcontainer/cgroups"
    33  )
    34  
    35  // CheckCgroup2UnifiedMode return whether it is in cgroupv2 env
    36  func CheckCgroup2UnifiedMode() bool {
    37  	return cgroups.IsCgroup2UnifiedMode()
    38  }
    39  
    40  func ReadTasksFile(file string) ([]string, error) {
    41  	f, err := os.Open(file)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	defer f.Close()
    46  
    47  	var (
    48  		s      = bufio.NewScanner(f)
    49  		result = []string{}
    50  	)
    51  
    52  	for s.Scan() {
    53  		if t := s.Text(); t != "" {
    54  			result = append(result, t)
    55  		}
    56  	}
    57  	return result, s.Err()
    58  }
    59  
    60  func GetCgroupParamInt(cgroupPath, cgroupFile string) (int64, error) {
    61  	fileName := filepath.Join(cgroupPath, cgroupFile)
    62  	contents, err := ioutil.ReadFile(fileName)
    63  	if err != nil {
    64  		return 0, err
    65  	}
    66  
    67  	trimmed := strings.TrimSpace(string(contents))
    68  	if trimmed == "max" {
    69  		return math.MaxInt64, nil
    70  	}
    71  
    72  	res, err := strconv.ParseInt(trimmed, 10, 64)
    73  	if err != nil {
    74  		return res, fmt.Errorf("unable to parse %q as a uint from Cgroup file %q", string(contents), fileName)
    75  	}
    76  	return res, nil
    77  }
    78  
    79  // ParseCgroupNumaValue parse cgroup numa stat files like memory.numa_stat, the format is like "anon N0=1686843392 N1=1069957120 N2=316747776 N3=163962880"
    80  func ParseCgroupNumaValue(cgroupPath, cgroupFile string) (map[string]map[int]uint64, error) {
    81  	fileName := filepath.Join(cgroupPath, cgroupFile)
    82  	content, err := ioutil.ReadFile(fileName)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	result := make(map[string]map[int]uint64)
    88  	lines := strings.Split(string(content), "\n")
    89  	for _, line := range lines {
    90  		cols := strings.Fields(line)
    91  		if len(cols) <= 1 {
    92  			continue
    93  		}
    94  
    95  		key := cols[0]
    96  		numaInfo := make(map[int]uint64)
    97  		for _, pair := range cols[1:] {
    98  			parts := strings.Split(pair, "=")
    99  			if len(parts) != 2 {
   100  				return nil, fmt.Errorf("failed to parse line [%v]", line)
   101  			}
   102  
   103  			if !strings.HasPrefix(parts[0], "N") {
   104  				return nil, fmt.Errorf("failed to parse line [%v]", line)
   105  			}
   106  
   107  			numaID, err := strconv.Atoi(strings.TrimPrefix(parts[0], "N"))
   108  			if err != nil {
   109  				return nil, fmt.Errorf("failed to parse line [%v]", line)
   110  			}
   111  			val, err := strconv.ParseUint(parts[1], 10, 64)
   112  			if err != nil {
   113  				return nil, fmt.Errorf("failed to parse line [%v]", line)
   114  			}
   115  			numaInfo[numaID] = val
   116  		}
   117  		if len(numaInfo) > 0 {
   118  			result[key] = numaInfo
   119  		}
   120  	}
   121  
   122  	return result, nil
   123  }
   124  
   125  // WriteFileIfChange writes data to the cgroup joined by dir and
   126  // file if new data is not equal to the old data and return the old data.
   127  func WriteFileIfChange(dir, file, data string) (error, bool, string) {
   128  	oldData, err := cgroups.ReadFile(dir, file)
   129  	if err != nil {
   130  		return err, false, ""
   131  	}
   132  
   133  	if strings.TrimSpace(data) != strings.TrimSpace(oldData) {
   134  		if err := cgroups.WriteFile(dir, file, data); err != nil {
   135  			return err, false, oldData
   136  		} else {
   137  			return nil, true, oldData
   138  		}
   139  	}
   140  	return nil, false, oldData
   141  }
   142  
   143  // IsCPUIdleSupported checks if cpu idle supported by
   144  // checking if the cpu.idle interface file exists
   145  func IsCPUIdleSupported() bool {
   146  	_, err := GetKubernetesAnyExistAbsCgroupPath(CgroupSubsysCPU, "cpu.idle")
   147  	return err == nil
   148  }