func()

in container/libcontainer/handler.go [314:371]


func (h *Handler) schedulerStatsFromProcs() (info.CpuSchedstat, error) {
	pids, err := h.cgroupManager.GetAllPids()
	if err != nil {
		return info.CpuSchedstat{}, fmt.Errorf("Could not get PIDs for container %d: %w", h.pid, err)
	}
	alivePids := make(map[int]struct{}, len(pids))
	for _, pid := range pids {
		f, err := os.Open(path.Join(h.rootFs, "proc", strconv.Itoa(pid), "schedstat"))
		if err != nil {
			return info.CpuSchedstat{}, fmt.Errorf("couldn't open scheduler statistics for process %d: %v", pid, err)
		}
		defer f.Close()
		contents, err := io.ReadAll(f)
		if err != nil {
			return info.CpuSchedstat{}, fmt.Errorf("couldn't read scheduler statistics for process %d: %v", pid, err)
		}
		alivePids[pid] = struct{}{}
		rawMetrics := bytes.Split(bytes.TrimRight(contents, "\n"), []byte(" "))
		if len(rawMetrics) != 3 {
			return info.CpuSchedstat{}, fmt.Errorf("unexpected number of metrics in schedstat file for process %d", pid)
		}
		cacheEntry, ok := h.pidMetricsCache[pid]
		if !ok {
			cacheEntry = &info.CpuSchedstat{}
			h.pidMetricsCache[pid] = cacheEntry
		}
		for i, rawMetric := range rawMetrics {
			metric, err := strconv.ParseUint(string(rawMetric), 10, 64)
			if err != nil {
				return info.CpuSchedstat{}, fmt.Errorf("parsing error while reading scheduler statistics for process: %d: %v", pid, err)
			}
			switch i {
			case 0:
				cacheEntry.RunTime = metric
			case 1:
				cacheEntry.RunqueueTime = metric
			case 2:
				cacheEntry.RunPeriods = metric
			}
		}
	}
	schedstats := h.pidMetricsSaved // copy
	for p, v := range h.pidMetricsCache {
		schedstats.RunPeriods += v.RunPeriods
		schedstats.RunqueueTime += v.RunqueueTime
		schedstats.RunTime += v.RunTime
		if _, alive := alivePids[p]; !alive {
			// PID p is gone: accumulate its stats ...
			h.pidMetricsSaved.RunPeriods += v.RunPeriods
			h.pidMetricsSaved.RunqueueTime += v.RunqueueTime
			h.pidMetricsSaved.RunTime += v.RunTime
			// ... and remove its cache entry, to prevent
			// pidMetricsCache from growing.
			delete(h.pidMetricsCache, p)
		}
	}
	return schedstats, nil
}