github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/fs2/psi.go (about) 1 package fs2 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "os" 8 "strconv" 9 "strings" 10 11 "golang.org/x/sys/unix" 12 13 "github.com/opencontainers/runc/libcontainer/cgroups" 14 ) 15 16 func statPSI(dirPath string, file string) (*cgroups.PSIStats, error) { 17 f, err := cgroups.OpenFile(dirPath, file, os.O_RDONLY) 18 if err != nil { 19 if errors.Is(err, os.ErrNotExist) { 20 // Kernel < 4.20, or CONFIG_PSI is not set, 21 // or PSI stats are turned off for the cgroup 22 // ("echo 0 > cgroup.pressure", kernel >= 6.1). 23 return nil, nil 24 } 25 return nil, err 26 } 27 defer f.Close() 28 29 var psistats cgroups.PSIStats 30 sc := bufio.NewScanner(f) 31 for sc.Scan() { 32 parts := strings.Fields(sc.Text()) 33 var pv *cgroups.PSIData 34 switch parts[0] { 35 case "some": 36 pv = &psistats.Some 37 case "full": 38 pv = &psistats.Full 39 } 40 if pv != nil { 41 *pv, err = parsePSIData(parts[1:]) 42 if err != nil { 43 return nil, &parseError{Path: dirPath, File: file, Err: err} 44 } 45 } 46 } 47 if err := sc.Err(); err != nil { 48 if errors.Is(err, unix.ENOTSUP) { 49 // Some kernels (e.g. CS9) may return ENOTSUP on read 50 // if psi=1 kernel cmdline parameter is required. 51 return nil, nil 52 } 53 return nil, &parseError{Path: dirPath, File: file, Err: err} 54 } 55 return &psistats, nil 56 } 57 58 func parsePSIData(psi []string) (cgroups.PSIData, error) { 59 data := cgroups.PSIData{} 60 for _, f := range psi { 61 kv := strings.SplitN(f, "=", 2) 62 if len(kv) != 2 { 63 return data, fmt.Errorf("invalid psi data: %q", f) 64 } 65 var pv *float64 66 switch kv[0] { 67 case "avg10": 68 pv = &data.Avg10 69 case "avg60": 70 pv = &data.Avg60 71 case "avg300": 72 pv = &data.Avg300 73 case "total": 74 v, err := strconv.ParseUint(kv[1], 10, 64) 75 if err != nil { 76 return data, fmt.Errorf("invalid %s PSI value: %w", kv[0], err) 77 } 78 data.Total = v 79 } 80 if pv != nil { 81 v, err := strconv.ParseFloat(kv[1], 64) 82 if err != nil { 83 return data, fmt.Errorf("invalid %s PSI value: %w", kv[0], err) 84 } 85 *pv = v 86 } 87 } 88 return data, nil 89 }