From 453f16e729db7965b037fda7e18a927bdba93c88 Mon Sep 17 00:00:00 2001 From: Jamie Liu Date: Tue, 22 Oct 2024 10:49:17 -0700 Subject: [PATCH] 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 --- pkg/cpuid/native_amd64.go | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/pkg/cpuid/native_amd64.go b/pkg/cpuid/native_amd64.go index 5351925f3d..5c79606bfe 100644 --- a/pkg/cpuid/native_amd64.go +++ b/pkg/cpuid/native_amd64.go @@ -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.