stats.go 3.14 KB
Newer Older
“李磊”'s avatar
“李磊” committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
}