Skip to content

Commit a564e20

Browse files
committed
cleanup
Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
1 parent 05735a2 commit a564e20

File tree

16 files changed

+217
-1746
lines changed

16 files changed

+217
-1746
lines changed

Gopkg.lock

Lines changed: 3 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@
2323
[[override]]
2424
name = "github.com/Sirupsen/logrus"
2525
source = "github.com/sirupsen/logrus"
26+
27+
[[override]]
28+
name = "github.com/docker/go-units"
29+
branch = "master"

main.go

Lines changed: 106 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"flag"
77
"fmt"
88
"io"
9+
"io/ioutil"
910
"os"
10-
"path"
1111
"path/filepath"
1212
"strconv"
1313
"strings"
@@ -18,7 +18,6 @@ import (
1818
units "github.com/docker/go-units"
1919
"github.com/jessfraz/magneto/types"
2020
"github.com/jessfraz/magneto/version"
21-
"github.com/opencontainers/runc/libcontainer/cgroups"
2221
"github.com/opencontainers/runc/libcontainer/system"
2322
specs "github.com/opencontainers/runtime-spec/specs-go"
2423
"github.com/sirupsen/logrus"
@@ -42,6 +41,8 @@ const (
4241
specFile = "config.json"
4342
stateFile = "state.json"
4443
defaultRoot = "/run/runc"
44+
45+
nanoSecondsPerSecond = 1e9
4546
)
4647

4748
var (
@@ -89,8 +90,8 @@ type containerStats struct {
8990
MemoryPercentage float64
9091
NetworkRx float64
9192
NetworkTx float64
92-
BlockRead float64
93-
BlockWrite float64
93+
BlockRead uint64
94+
BlockWrite uint64
9495
PidsCurrent uint64
9596
mu sync.RWMutex
9697
bufReader *bufio.Reader
@@ -112,12 +113,13 @@ func main() {
112113
clockTicksPerSecond: uint64(system.GetClockTicks()),
113114
bufReader: bufio.NewReaderSize(nil, 128),
114115
}
115-
go s.Collect()
116+
117+
go s.collect()
116118

117119
for range time.Tick(5 * time.Second) {
118120
printHeader()
119121
if err := s.Display(w); err != nil {
120-
logrus.Errorf("Displaying stats failed: %v", err)
122+
logrus.Error(err)
121123
}
122124
w.Flush()
123125
}
@@ -133,44 +135,42 @@ func usageAndExit(message string, exitCode int) {
133135
os.Exit(exitCode)
134136
}
135137

136-
func (s *containerStats) Collect() {
138+
func (s *containerStats) collect() {
137139
var (
138140
previousCPU uint64
139141
previousSystem uint64
140142
dec = json.NewDecoder(os.Stdin)
141143
u = make(chan error, 1)
142144
)
145+
143146
go func() {
144147
for {
145-
var e event
148+
var (
149+
e event
150+
memPercent, cpuPercent float64
151+
blkRead, blkWrite uint64 // Only used on Linux
152+
mem, memLimit float64
153+
netRx, netTx float64
154+
pidsCurrent uint64
155+
)
156+
146157
if err := dec.Decode(&e); err != nil {
147158
u <- err
148-
return
159+
time.Sleep(100 * time.Millisecond)
160+
continue
149161
}
162+
150163
if e.Type != "stats" {
151164
// do nothing since there are no other events yet
152-
return
153-
}
154-
155-
var memPercent = 0.0
156-
var cpuPercent = 0.0
157-
158-
v := e.Data.CgroupStats
159-
if v == nil {
160-
return
165+
continue
161166
}
167+
v := e.Data
162168

163-
resources, err := getContainerResources(e.ID)
169+
/*resources, err := getContainerResources(e.ID)
164170
if err != nil {
165171
u <- fmt.Errorf("Getting container's configured resources failed: %v", err)
166-
return
167-
}
168-
169-
// MemoryStats.Limit will never be 0 unless the container is not running and we haven't
170-
// got any data from cgroup
171-
if int(*resources.Memory.Limit) != 0 {
172-
memPercent = float64(v.MemoryStats.Usage.Usage) / float64(*resources.Memory.Limit) * 100.0
173-
}
172+
continue
173+
}*/
174174

175175
systemUsage, err := s.getSystemCPUUsage()
176176
if err != nil {
@@ -179,68 +179,93 @@ func (s *containerStats) Collect() {
179179
}
180180

181181
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, systemUsage, v)
182-
previousCPU = v.CpuStats.CpuUsage.TotalUsage
182+
previousCPU = v.CPU.Usage.Total
183183
previousSystem = systemUsage
184-
blkRead, blkWrite := calculateBlockIO(v.BlkioStats)
184+
185+
blkRead, blkWrite = calculateBlockIO(v.Blkio)
186+
187+
mem = calculateMemUsageNoCache(v.Memory)
188+
memLimit = float64(v.Memory.Usage.Limit)
189+
memPercent = calculateMemPercentNoCache(s.MemoryLimit, s.Memory)
190+
191+
//netRx, netTx = calculateNetwork(e.Data.Interfaces)
192+
193+
pidsCurrent = v.Pids.Current
194+
195+
// set the stats
185196
s.mu.Lock()
186197
s.CPUPercentage = cpuPercent
187-
s.Memory = float64(v.MemoryStats.Usage.Usage)
188-
s.MemoryLimit = float64(*resources.Memory.Limit)
198+
s.BlockRead = blkRead
199+
s.BlockWrite = blkWrite
200+
s.Memory = mem
201+
s.MemoryLimit = memLimit
189202
s.MemoryPercentage = memPercent
190-
s.NetworkRx, s.NetworkTx = calculateNetwork(e.Data.Interfaces)
191-
s.BlockRead = float64(blkRead)
192-
s.BlockWrite = float64(blkWrite)
193-
s.PidsCurrent = v.PidsStats.Current
203+
s.NetworkRx = netRx
204+
s.NetworkTx = netTx
205+
s.PidsCurrent = pidsCurrent
194206
s.mu.Unlock()
207+
195208
u <- nil
196209
}
197210
}()
211+
198212
for {
199213
select {
200214
case err := <-u:
201-
if err != nil {
202-
s.mu.Lock()
203-
s.err = err
204-
s.mu.Unlock()
205-
logrus.Fatal(err)
206-
return
207-
}
215+
s.setError(err)
216+
continue
208217
}
209218
}
210219
}
211220

221+
var it = 0
222+
212223
func (s *containerStats) Display(w io.Writer) error {
213224
s.mu.RLock()
214225
defer s.mu.RUnlock()
226+
227+
// check the error here
215228
if s.err != nil {
216229
return s.err
217230
}
218-
fmt.Fprintf(w, "%.2f%%\t%s / %s\t%.2f%%\t%s / %s\t%s / %s\t%d\n",
231+
232+
fmt.Fprintf(w, "%.2f%%\t%s / %s\t%.2f%%\t%s / %s\t%d / %d\t%d\n",
219233
s.CPUPercentage,
220234
units.HumanSize(s.Memory), units.HumanSize(s.MemoryLimit),
221235
s.MemoryPercentage,
222236
units.HumanSize(s.NetworkRx), units.HumanSize(s.NetworkTx),
223-
units.HumanSize(s.BlockRead), units.HumanSize(s.BlockWrite),
237+
s.BlockRead, s.BlockWrite,
224238
s.PidsCurrent)
239+
240+
logrus.Infof("displayed stats %d", it)
241+
it++
225242
return nil
226243
}
227244

228-
func calculateCPUPercent(previousCPU, previousSystem, systemUsage uint64, v *cgroups.Stats) float64 {
245+
// setError sets container statistics error
246+
func (s *containerStats) setError(err error) {
247+
s.mu.Lock()
248+
defer s.mu.Unlock()
249+
s.err = err
250+
}
251+
252+
func calculateCPUPercent(previousCPU, previousSystem, systemUsage uint64, v types.Stats) float64 {
229253
var (
230254
cpuPercent = 0.0
231255
// calculate the change for the cpu usage of the container in between readings
232-
cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage) - float64(previousCPU)
256+
cpuDelta = float64(v.CPU.Usage.Total) - float64(previousCPU)
233257
// calculate the change for the entire system between readings
234258
systemDelta = float64(systemUsage) - float64(previousSystem)
235259
)
236260

237261
if systemDelta > 0.0 && cpuDelta > 0.0 {
238-
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0
262+
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPU.Usage.Percpu)) * 100.0
239263
}
240264
return cpuPercent
241265
}
242266

243-
func calculateBlockIO(blkio cgroups.BlkioStats) (blkRead uint64, blkWrite uint64) {
267+
func calculateBlockIO(blkio types.Blkio) (uint64, uint64) {
268+
var blkRead, blkWrite uint64
244269
for _, bioEntry := range blkio.IoServiceBytesRecursive {
245270
switch strings.ToLower(bioEntry.Op) {
246271
case "read":
@@ -249,7 +274,7 @@ func calculateBlockIO(blkio cgroups.BlkioStats) (blkRead uint64, blkWrite uint64
249274
blkWrite = blkWrite + bioEntry.Value
250275
}
251276
}
252-
return
277+
return blkRead, blkWrite
253278
}
254279

255280
func calculateNetwork(network []*types.NetworkInterface) (float64, float64) {
@@ -262,7 +287,20 @@ func calculateNetwork(network []*types.NetworkInterface) (float64, float64) {
262287
return rx, tx
263288
}
264289

265-
const nanoSecondsPerSecond = 1e9
290+
// calculateMemUsageNoCache calculate memory usage of the container.
291+
// Page cache is intentionally excluded to avoid misinterpretation of the output.
292+
func calculateMemUsageNoCache(mem types.Memory) float64 {
293+
return float64(mem.Usage.Usage - mem.Cache)
294+
}
295+
296+
func calculateMemPercentNoCache(limit float64, usedNoCache float64) float64 {
297+
// MemoryStats.Limit will never be 0 unless the container is not running and we haven't
298+
// got any data from cgroup
299+
if limit != 0 {
300+
return usedNoCache / limit * 100.0
301+
}
302+
return 0
303+
}
266304

267305
// getSystemCPUUsage returns the host system's cpu usage in
268306
// nanoseconds. An error is returned if the format of the underlying
@@ -293,21 +331,22 @@ func (s *containerStats) getSystemCPUUsage() (uint64, error) {
293331
switch parts[0] {
294332
case "cpu":
295333
if len(parts) < 8 {
296-
return 0, fmt.Errorf("Bad CPU fields")
334+
return 0, fmt.Errorf("invalid number of cpu fields")
297335
}
298336
var totalClockTicks uint64
299337
for _, i := range parts[1:8] {
300338
v, err := strconv.ParseUint(i, 10, 64)
301339
if err != nil {
302-
return 0, fmt.Errorf("Bad CPU int %s: %v", i, err)
340+
return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
303341
}
304342
totalClockTicks += v
305343
}
306344
return (totalClockTicks * nanoSecondsPerSecond) /
307345
s.clockTicksPerSecond, nil
308346
}
309347
}
310-
return 0, fmt.Errorf("Bad stat file format")
348+
349+
return 0, fmt.Errorf("invalid stat format. Error trying to parse the '/proc/stat' file")
311350
}
312351

313352
func getContainerResources(id string) (*specs.LinuxResources, error) {
@@ -317,7 +356,7 @@ func getContainerResources(id string) (*specs.LinuxResources, error) {
317356
}
318357

319358
// check to make sure a container exists with this ID
320-
statePath := path.Join(abs, id, stateFile)
359+
statePath := filepath.Join(abs, id, stateFile)
321360

322361
// read the state.json for the container so we can find out the bundle path
323362
f, err := os.Open(statePath)
@@ -334,7 +373,7 @@ func getContainerResources(id string) (*specs.LinuxResources, error) {
334373
}
335374

336375
bundle := searchLabels(state.Config.Labels, "bundle")
337-
specPath := path.Join(bundle, specFile)
376+
specPath := filepath.Join(bundle, specFile)
338377

339378
// read the runtime.json for the container so we know things like limits set
340379
// this is only if a container ID is not passed we assume we are in a directory
@@ -351,6 +390,18 @@ func getContainerResources(id string) (*specs.LinuxResources, error) {
351390
if err = json.NewDecoder(f).Decode(&spec); err != nil {
352391
return nil, err
353392
}
393+
if spec.Linux.Resources.Memory.Limit == nil {
394+
// set the memory limit manually
395+
b, err := ioutil.ReadFile(filepath.Join(state.CgroupPaths["memory"], "memory.limit_in_bytes"))
396+
if err != nil {
397+
return nil, err
398+
}
399+
i, err := units.RAMInBytes(strings.TrimSpace(string(b)) + "b")
400+
if err != nil {
401+
return nil, err
402+
}
403+
spec.Linux.Resources.Memory.Limit = &i
404+
}
354405
return spec.Linux.Resources, nil
355406
}
356407

0 commit comments

Comments
 (0)