-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
metric_helper.go
133 lines (119 loc) · 4.71 KB
/
metric_helper.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
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package dockerstatsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/dockerstatsreceiver"
import (
"fmt"
"strconv"
"strings"
ctypes "github.com/docker/docker/api/types/container"
)
const nanosInASecond = 1e9
// Following functions has been copied from: calculateCPUPercentUnix(), calculateMemUsageUnixNoCache(), calculateMemPercentUnixNoCache()
// https://github.com/docker/cli/blob/a2e9ed3b874fccc177b9349f3b0277612403934f/cli/command/container/stats_helpers.go
// Copyright 2012-2017 Docker, Inc.
// This product includes software developed at Docker, Inc. (https://www.docker.com).
// The following is courtesy of our legal counsel:
// Use and transfer of Docker may be subject to certain restrictions by the
// United States and other governments.
// It is your responsibility to ensure that your use and/or transfer does not
// violate applicable laws.
// For more information, please see https://www.bis.doc.gov
// See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.
func calculateCPUPercent(previous *ctypes.CPUStats, v *ctypes.CPUStats) float64 {
var (
cpuPercent = 0.0
// calculate the change for the cpu usage of the container in between readings
cpuDelta = float64(v.CPUUsage.TotalUsage) - float64(previous.CPUUsage.TotalUsage)
// calculate the change for the entire system between readings
systemDelta = float64(v.SystemUsage) - float64(previous.SystemUsage)
onlineCPUs = float64(v.OnlineCPUs)
)
if onlineCPUs == 0.0 {
onlineCPUs = float64(len(v.CPUUsage.PercpuUsage))
}
if systemDelta > 0.0 && cpuDelta > 0.0 {
cpuPercent = (cpuDelta / systemDelta) * onlineCPUs * 100.0
}
return cpuPercent
}
// calculateMemUsageNoCache calculate memory usage of the container.
// Cache is intentionally excluded to avoid misinterpretation of the output.
//
// On cgroup v1 host, the result is `mem.Usage - mem.Stats["total_inactive_file"]` .
// On cgroup v2 host, the result is `mem.Usage - mem.Stats["inactive_file"] `.
//
// This definition is consistent with cadvisor and containerd/CRI.
// * https://github.com/google/cadvisor/commit/307d1b1cb320fef66fab02db749f07a459245451
// * https://github.com/containerd/cri/commit/6b8846cdf8b8c98c1d965313d66bc8489166059a
//
// On Docker 19.03 and older, the result was `mem.Usage - mem.Stats["cache"]`.
// See https://github.com/moby/moby/issues/40727 for the background.
func calculateMemUsageNoCache(memoryStats *ctypes.MemoryStats) uint64 {
// cgroup v1
if v, isCgroup1 := memoryStats.Stats["total_inactive_file"]; isCgroup1 && v < memoryStats.Usage {
return memoryStats.Usage - v
}
// cgroup v2
if v := memoryStats.Stats["inactive_file"]; v < memoryStats.Usage {
return memoryStats.Usage - v
}
return memoryStats.Usage
}
func calculateMemoryPercent(limit uint64, usedNoCache uint64) float64 {
// MemoryStats.Limit will never be 0 unless the container is not running and we haven't
// got any data from cgroup
if limit != 0 {
return float64(usedNoCache) / float64(limit) * 100.0
}
return 0.0
}
// calculateCPULimit calculate the number of cpus assigned to a container.
//
// Calculation is based on 3 alternatives by the following order:
// - nanocpus: if set by i.e docker run -cpus=2
// - cpusetCpus: if set by i.e docker run -docker run -cpuset-cpus="0,2"
// - cpuquota: if set by i.e docker run -cpu-quota=50000
//
// See https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler for background.
func calculateCPULimit(hostConfig *ctypes.HostConfig) (float64, error) {
var cpuLimit float64
var err error
switch {
case hostConfig.NanoCPUs > 0:
cpuLimit = float64(hostConfig.NanoCPUs) / nanosInASecond
case hostConfig.CpusetCpus != "":
cpuLimit, err = parseCPUSet(hostConfig.CpusetCpus)
if err != nil {
return cpuLimit, err
}
case hostConfig.CPUQuota > 0:
period := hostConfig.CPUPeriod
if period == 0 {
period = 100000 // Default CFS Period
}
cpuLimit = float64(hostConfig.CPUQuota) / float64(period)
}
return cpuLimit, nil
}
// parseCPUSet helper function to decompose -cpuset-cpus value into number os cpus.
func parseCPUSet(line string) (float64, error) {
var numCPUs uint64
lineSlice := strings.Split(line, ",")
for _, l := range lineSlice {
lineParts := strings.Split(l, "-")
if len(lineParts) == 2 {
p0, err0 := strconv.Atoi(lineParts[0])
if err0 != nil {
return 0, fmt.Errorf("invalid -cpuset-cpus value: %w", err0)
}
p1, err1 := strconv.Atoi(lineParts[1])
if err1 != nil {
return 0, fmt.Errorf("invalid -cpuset-cpus value: %w", err1)
}
numCPUs += uint64(p1 - p0 + 1)
} else if len(lineParts) == 1 {
numCPUs++
}
}
return float64(numCPUs), nil
}