github.com/intel/goresctrl@v0.5.0/pkg/utils/sysfs.go (about) 1 /* 2 Copyright 2022 Intel Corporation 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 utils 18 19 import ( 20 "fmt" 21 "os" 22 "strconv" 23 "strings" 24 25 goresctrlpath "github.com/intel/goresctrl/pkg/path" 26 ) 27 28 const ( 29 SysfsUncoreBasepath = "sys/devices/system/cpu/intel_uncore_frequency" 30 SysfsCpuBasepath = "sys/devices/system/cpu" 31 ) 32 33 func setCPUFreqValue(cpu ID, setting string, value int) error { 34 return writeFileInt(cpuFreqPath(cpu, setting), value) 35 } 36 37 // GetCPUFreqValue returns information of the currently used CPU frequency 38 func GetCPUFreqValue(cpu ID, setting string) (int, error) { 39 raw, err := os.ReadFile(cpuFreqPath(cpu, setting)) 40 if err != nil { 41 return 0, err 42 } 43 44 value, err := strconv.Atoi(strings.TrimSpace(string(raw))) 45 if err != nil { 46 return 0, err 47 } 48 49 return value, nil 50 } 51 52 func cpuFreqPath(cpu ID, setting string) string { 53 return goresctrlpath.Path(SysfsCpuBasepath, fmt.Sprintf("cpu%d", cpu), "cpufreq", setting) 54 } 55 56 // SetCPUScalingMinFreq sets the scaling_min_freq value of a given CPU 57 func SetCPUScalingMinFreq(cpu ID, freq int) error { 58 return setCPUFreqValue(cpu, "scaling_min_freq", freq) 59 } 60 61 // SetCPUScalingMaxFreq sets the scaling_max_freq value of a given CPU 62 func SetCPUScalingMaxFreq(cpu ID, freq int) error { 63 return setCPUFreqValue(cpu, "scaling_max_freq", freq) 64 } 65 66 // SetCPUsScalingMinFreq sets the scaling_min_freq value of a given set of CPUs 67 func SetCPUsScalingMinFreq(cpus []ID, freq int) error { 68 for _, cpu := range cpus { 69 if err := SetCPUScalingMinFreq(cpu, freq); err != nil { 70 return err 71 } 72 } 73 74 return nil 75 } 76 77 // SetCPUsScalingMaxFreq sets the scaling_max_freq value of a given set of CPUs 78 func SetCPUsScalingMaxFreq(cpus []ID, freq int) error { 79 for _, cpu := range cpus { 80 if err := SetCPUScalingMaxFreq(cpu, freq); err != nil { 81 return err 82 } 83 } 84 85 return nil 86 } 87 88 // UncoreFreqAvailable returns true if the uncore frequency control functions are available. 89 func UncoreFreqAvailable() bool { 90 _, err := os.Stat(goresctrlpath.Path(SysfsUncoreBasepath)) 91 return err == nil 92 } 93 94 // SetUncoreMinFreq sets the minimum uncore frequency of a CPU die. Frequency is specified in kHz. 95 func SetUncoreMinFreq(pkg, die ID, freqKhz int) error { 96 return setUncoreFreqValue(pkg, die, "min_freq_khz", freqKhz) 97 } 98 99 // SetUncoreMaxFreq sets the maximum uncore frequency of a CPU die. Frequency is specified in kHz. 100 func SetUncoreMaxFreq(pkg, die ID, freqKhz int) error { 101 return setUncoreFreqValue(pkg, die, "max_freq_khz", freqKhz) 102 } 103 104 func uncoreFreqPath(pkg, die ID, attribute string) string { 105 return goresctrlpath.Path(SysfsUncoreBasepath, fmt.Sprintf("package_%02d_die_%02d", pkg, die), attribute) 106 } 107 108 func getUncoreFreqValue(pkg, die ID, attribute string) (int, error) { 109 return readFileInt(uncoreFreqPath(pkg, die, attribute)) 110 } 111 112 func setUncoreFreqValue(pkg, die ID, attribute string, value int) error { 113 // Bounds checking 114 if hwMinFreq, err := getUncoreFreqValue(pkg, die, "initial_min_freq_khz"); err != nil { 115 return err 116 } else if value < hwMinFreq { 117 value = hwMinFreq 118 } 119 if hwMaxFreq, err := getUncoreFreqValue(pkg, die, "initial_max_freq_khz"); err != nil { 120 return err 121 } else if value > hwMaxFreq { 122 value = hwMaxFreq 123 } 124 125 return writeFileInt(uncoreFreqPath(pkg, die, attribute), value) 126 } 127 128 func writeFileInt(path string, value int) error { 129 return os.WriteFile(path, []byte(strconv.Itoa(value)), 0644) 130 } 131 132 func readFileInt(path string) (int, error) { 133 data, err := os.ReadFile(path) 134 if err != nil { 135 return 0, err 136 } 137 i, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 32) 138 return int(i), err 139 }