Skip to content

Commit

Permalink
cpuid: read /proc/cpuinfo incrementally
Browse files Browse the repository at this point in the history
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
  • Loading branch information
nixprime authored and gvisor-bot committed Oct 22, 2024
1 parent 4362b11 commit 453f16e
Showing 1 changed file with 19 additions and 13 deletions.
32 changes: 19 additions & 13 deletions pkg/cpuid/native_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
package cpuid

import (
"bufio"
"bytes"
"os"
"strconv"
"strings"

"gvisor.dev/gvisor/pkg/log"
)
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 453f16e

Please sign in to comment.