/
proc.go
151 lines (112 loc) · 3.19 KB
/
proc.go
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2017-2021 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain
// rights in this software.
package main
import (
"fmt"
"time"
proc "github.com/c9s/goprocinfo/linux"
)
// #include <unistd.h>
import "C"
// ProcLimit is the maximum number of proceses to inspect per VM
const ProcLimit = 100
var (
ClkTck = float64(C.sysconf(C._SC_CLK_TCK))
PageSize = uint64(C.getpagesize())
)
type ProcStats struct {
*proc.ProcessStat // embed
*proc.ProcessStatm // embed
// time at beginning and end of data collection
Begin, End time.Time
}
type VMProcStats struct {
Name, Namespace string
// A and B are two snapshots of ProcStats
A, B map[int]*ProcStats
// queried from bridge
RxRate, TxRate float64
}
// Time returns total time executed for all processes in MB
func (p *VMProcStats) Time() time.Duration {
var tics uint64
for _, v := range p.B {
tics += v.Utime + v.Stime
}
return time.Duration(float64(tics)/ClkTck) * time.Second
}
// Size returns total memory size for all processes in MB
func (p *VMProcStats) Size() uint64 {
var pages uint64
for _, v := range p.B {
pages += v.ProcessStatm.Size
}
return pages * PageSize
}
// Resident returns total resident memory size for all processes in MB
func (p *VMProcStats) Resident() uint64 {
var pages uint64
for _, v := range p.B {
pages += v.ProcessStatm.Resident
}
return pages * PageSize
}
// Share returns total resident memory size for all processes in MB
func (p *VMProcStats) Share() uint64 {
var pages uint64
for _, v := range p.B {
pages += v.ProcessStatm.Share
}
return pages * PageSize
}
// Count walks the tree and returns the number of processes
func (p *VMProcStats) Count() int {
return len(p.B)
}
func (p *VMProcStats) cpuHelper(fn func(*ProcStats, *ProcStats) float64) float64 {
var res float64
// find overlapping PIDs in p.A and p.B
for pid, v := range p.A {
if v2, ok := p.B[pid]; ok {
res += fn(v, v2)
}
}
return res
}
func (p *VMProcStats) CPU() float64 {
return p.cpuHelper(ProcCPU)
}
func (p *VMProcStats) GuestCPU() float64 {
return p.cpuHelper(ProcGuestCPU)
}
// GetProcStats reads the ProcStats for the given PID.
func GetProcStats(pid int) (*ProcStats, error) {
var err error
p := &ProcStats{
Begin: time.Now(),
}
p.ProcessStat, err = proc.ReadProcessStat(fmt.Sprintf("/proc/%v/stat", pid))
if err != nil {
return nil, fmt.Errorf("unable to read process stat: %v", err)
}
p.ProcessStatm, err = proc.ReadProcessStatm(fmt.Sprintf("/proc/%v/statm", pid))
if err != nil {
return nil, fmt.Errorf("unable to read process statm: %v", err)
}
p.End = time.Now()
return p, nil
}
// ProcCPU computes CPU % between two snapshots of proc
func ProcCPU(p, p2 *ProcStats) float64 {
// compute number of tics used in window by process
tics := float64((p2.Utime + p2.Stime) - (p.Utime + p.Stime))
d := p2.End.Sub(p.Begin)
return tics / ClkTck / d.Seconds()
}
// ProcGuestCPU computes guest CPU % between two snapshots of proc
func ProcGuestCPU(p, p2 *ProcStats) float64 {
vtics := float64(p2.GuestTime - p.GuestTime)
d := p2.End.Sub(p.Begin)
return vtics / ClkTck / d.Seconds()
}