package stats import ( "fmt" "math" "time" "linkfog.com/public/lib/cgroup" "linkfog.com/public/lib/cgroup/types" "linkfog.com/public/lib/common" ) type Stats struct { pid int memDir string cpuDir string ioDir string fifo *common.Fifo // for cpu stats preIoStats *types.IOStats // for io stats } func NewStats(pid int, refreshDura, cpuRateRange time.Duration) *Stats { poolLen := math.Ceil(float64(cpuRateRange.Nanoseconds())/float64(refreshDura)) + 1 if poolLen <= 1 { poolLen = 2 } return NewStatsWithPoolLen(pid, int(poolLen)) } func NewStatsWithPoolLen(pid int, poolLen int) *Stats { stats := &Stats{ pid: pid, fifo: common.NewFifo(poolLen), } return stats } func (s *Stats) TryCgroupPath() error { var err error s.memDir, err = cgroup.GetContainerMemoryCgroupPath(s.pid) if err != nil { return fmt.Errorf("get container (pid:%d) mem cgroup path err:%v", s.pid, err) } s.cpuDir, err = cgroup.GetContainerCPUCgroupPath(s.pid) if err != nil { return fmt.Errorf("get container (pid:%d) cpu cgroup path err:%v", s.pid, err) } s.ioDir, err = cgroup.GetContainerIOCgroupPath(s.pid) if err != nil { return fmt.Errorf("get container (pid:%d) io cgroup path err:%v", s.pid, err) } return nil } func (s *Stats) GetMemoryWorkingSet() (usage float64, err error) { var memStats types.MemoryStats memStats, err = GetMemoryStats(s.memDir) if err != nil { return } usage = float64(memStats.WorkingSet) return } func (s *Stats) GetCPUUsage() (usage float64, err error) { var cpuStats types.CPUStats cpuStats, err = GetCPUStats(s.cpuDir) if err != nil { return } s.fifo.Push(cpuStats) if s.fifo.Len() >= s.fifo.MaxLen() { frontStats := s.fifo.Front().Value.(types.CPUStats) backStats := s.fifo.Back().Value.(types.CPUStats) front := metric{ value: float64(frontStats.TotalUsage) / float64(time.Second), ts: frontStats.Timestamp.Unix(), } back := metric{ value: float64(backStats.TotalUsage) / float64(time.Second), ts: backStats.Timestamp.Unix(), } usage = calculateRate(front, back) } return } func (s *Stats) GetIOUsage() (map[string]*types.IOUsage, error) { curIoStats, err := GetIOStats(s.ioDir) if err != nil { return nil, err } ioUsage := make(map[string]*types.IOUsage, 0) if s.preIoStats != nil { for dev, curIoStat := range curIoStats.Stats { ioUsage[dev] = &types.IOUsage{} if preIoStat, ok := s.preIoStats.Stats[dev]; ok { if curIoStat.Read != 0 { pre := metric{value: float64(preIoStat.Read), ts: s.preIoStats.Timestamp.Unix()} cur := metric{value: float64(curIoStat.Read), ts: curIoStats.Timestamp.Unix()} ioUsage[dev].Read = calculateRate(pre, cur) } if curIoStat.Write != 0 { pre := metric{value: float64(preIoStat.Write), ts: s.preIoStats.Timestamp.Unix()} cur := metric{value: float64(curIoStat.Write), ts: curIoStats.Timestamp.Unix()} ioUsage[dev].Write = calculateRate(pre, cur) } } } } s.preIoStats = curIoStats return ioUsage, nil } func (s *Stats) GetMemoryDir() string { return s.memDir } func (s *Stats) GetCPUDir() string { return s.cpuDir } func (s *Stats) GetIODir() string { return s.ioDir }