| 269 | } |
| 270 | |
| 271 | func processStatsFromProcs(rootFs string, cgroupPath string, rootPid int) (info.ProcessStats, error) { |
| 272 | var fdCount, socketCount uint64 |
| 273 | filePath := path.Join(cgroupPath, "cgroup.procs") |
| 274 | out, err := os.ReadFile(filePath) |
| 275 | if err != nil { |
| 276 | return info.ProcessStats{}, fmt.Errorf("couldn't open cpu cgroup procs file %v : %v", filePath, err) |
| 277 | } |
| 278 | |
| 279 | pids := strings.Split(string(out), "\n") |
| 280 | |
| 281 | // EOL is also treated as a new line while reading "cgroup.procs" file with os.ReadFile. |
| 282 | // The last value is an empty string "". Ex: pids = ["22", "1223", ""] |
| 283 | // Trim the last value |
| 284 | if len(pids) != 0 && pids[len(pids)-1] == "" { |
| 285 | pids = pids[:len(pids)-1] |
| 286 | } |
| 287 | |
| 288 | for _, pid := range pids { |
| 289 | dirPath := path.Join(rootFs, "/proc", pid, "fd") |
| 290 | fds, err := os.ReadDir(dirPath) |
| 291 | if err != nil { |
| 292 | klog.V(4).Infof("error while listing directory %q to measure fd count: %v", dirPath, err) |
| 293 | continue |
| 294 | } |
| 295 | fdCount += uint64(len(fds)) |
| 296 | for _, fd := range fds { |
| 297 | fdPath := path.Join(dirPath, fd.Name()) |
| 298 | linkName, err := os.Readlink(fdPath) |
| 299 | if err != nil { |
| 300 | klog.V(4).Infof("error while reading %q link: %v", fdPath, err) |
| 301 | continue |
| 302 | } |
| 303 | if strings.HasPrefix(linkName, "socket") { |
| 304 | socketCount++ |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | processStats := info.ProcessStats{ |
| 310 | ProcessCount: uint64(len(pids)), |
| 311 | FdCount: fdCount, |
| 312 | SocketCount: socketCount, |
| 313 | } |
| 314 | |
| 315 | if rootPid > 0 { |
| 316 | processStats.Ulimits = processRootProcUlimits(rootFs, rootPid) |
| 317 | } |
| 318 | |
| 319 | return processStats, nil |
| 320 | } |
| 321 | |
| 322 | func (h *Handler) schedulerStatsFromProcs() (info.CpuSchedstat, error) { |
| 323 | pids, err := h.cgroupManager.GetAllPids() |