cpuid: read /proc/cpuinfo incrementally

On machines with many CPUs, reading all of /proc/cpuinfo spends a surprising
amount of time generating information for each CPU; reduce this time by reading
incrementally until we find the CPU frequency. On such machines, this saves
3-4ms on sentry startup.

PiperOrigin-RevId: 688609950
This commit is contained in:
Jamie Liu
2024-10-22 10:52:30 -07:00
committed by gVisor bot
parent 4362b11be9
commit 453f16e729
+19 -13
View File
@@ -18,9 +18,10 @@
package cpuid
import (
"bufio"
"bytes"
"os"
"strconv"
"strings"
"gvisor.dev/gvisor/pkg/log"
)
@@ -180,39 +181,44 @@ var (
// filter installation. This value is used to create the fake /proc/cpuinfo
// from a FeatureSet.
func readMaxCPUFreq() {
cpuinfob, err := os.ReadFile("/proc/cpuinfo")
cpuinfoFile, err := os.Open("/proc/cpuinfo")
if err != nil {
// Leave it as 0... the VDSO bails out in the same way.
log.Warningf("Could not read /proc/cpuinfo: %v", err)
log.Warningf("Could not open /proc/cpuinfo: %v", err)
return
}
cpuinfo := string(cpuinfob)
defer cpuinfoFile.Close()
// We get the value straight from host /proc/cpuinfo. On machines with
// frequency scaling enabled, this will only get the current value
// which will likely be inaccurate. This is fine on machines with
// frequency scaling disabled.
for _, line := range strings.Split(cpuinfo, "\n") {
if strings.Contains(line, "cpu MHz") {
splitMHz := strings.Split(line, ":")
s := bufio.NewScanner(cpuinfoFile)
for s.Scan() {
line := s.Bytes()
if bytes.Contains(line, []byte("cpu MHz")) {
splitMHz := bytes.Split(line, []byte(":"))
if len(splitMHz) < 2 {
log.Warningf("Could not read /proc/cpuinfo: malformed cpu MHz line")
log.Warningf("Could not parse /proc/cpuinfo: malformed cpu MHz line: %q", line)
return
}
// If there was a problem, leave cpuFreqMHz as 0.
var err error
cpuFreqMHz, err = strconv.ParseFloat(strings.TrimSpace(splitMHz[1]), 64)
splitMHzStr := string(bytes.TrimSpace(splitMHz[1]))
f64MHz, err := strconv.ParseFloat(splitMHzStr, 64)
if err != nil {
log.Warningf("Could not parse cpu MHz value %v: %v", splitMHz[1], err)
cpuFreqMHz = 0
log.Warningf("Could not parse cpu MHz value %q: %v", splitMHzStr, err)
return
}
cpuFreqMHz = f64MHz
return
}
}
if err := s.Err(); err != nil {
log.Warningf("Could not read /proc/cpuinfo: %v", err)
return
}
log.Warningf("Could not parse /proc/cpuinfo, it is empty or does not contain cpu MHz")
}
// xgetbv reads an extended control register.