daemon: move code related to stats together
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
dd3b71d17c
commit
f691b13450
4 changed files with 309 additions and 306 deletions
|
@ -19,10 +19,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containerd/cgroups/v3"
|
||||
statsV1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
statsV2 "github.com/containerd/cgroups/v3/cgroup2/stats"
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/blkiodev"
|
||||
pblkiodev "github.com/docker/docker/api/types/blkiodev"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
|
@ -1409,242 +1406,6 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container
|
|||
return nil
|
||||
}
|
||||
|
||||
func copyBlkioEntry(entries []*statsV1.BlkIOEntry) []types.BlkioStatEntry {
|
||||
out := make([]types.BlkioStatEntry, len(entries))
|
||||
for i, re := range entries {
|
||||
out[i] = types.BlkioStatEntry{
|
||||
Major: re.Major,
|
||||
Minor: re.Minor,
|
||||
Op: re.Op,
|
||||
Value: re.Value,
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
|
||||
c.Lock()
|
||||
task, err := c.GetRunningTask()
|
||||
c.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs, err := task.Stats(context.Background())
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "container not found") {
|
||||
return nil, containerNotFound(c.ID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
s := &types.StatsJSON{}
|
||||
s.Read = cs.Read
|
||||
stats := cs.Metrics
|
||||
switch t := stats.(type) {
|
||||
case *statsV1.Metrics:
|
||||
return daemon.statsV1(s, t)
|
||||
case *statsV2.Metrics:
|
||||
return daemon.statsV2(s, t)
|
||||
default:
|
||||
return nil, errors.Errorf("unexpected type of metrics %+v", t)
|
||||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) statsV1(s *types.StatsJSON, stats *statsV1.Metrics) (*types.StatsJSON, error) {
|
||||
if stats.Blkio != nil {
|
||||
s.BlkioStats = types.BlkioStats{
|
||||
IoServiceBytesRecursive: copyBlkioEntry(stats.Blkio.IoServiceBytesRecursive),
|
||||
IoServicedRecursive: copyBlkioEntry(stats.Blkio.IoServicedRecursive),
|
||||
IoQueuedRecursive: copyBlkioEntry(stats.Blkio.IoQueuedRecursive),
|
||||
IoServiceTimeRecursive: copyBlkioEntry(stats.Blkio.IoServiceTimeRecursive),
|
||||
IoWaitTimeRecursive: copyBlkioEntry(stats.Blkio.IoWaitTimeRecursive),
|
||||
IoMergedRecursive: copyBlkioEntry(stats.Blkio.IoMergedRecursive),
|
||||
IoTimeRecursive: copyBlkioEntry(stats.Blkio.IoTimeRecursive),
|
||||
SectorsRecursive: copyBlkioEntry(stats.Blkio.SectorsRecursive),
|
||||
}
|
||||
}
|
||||
if stats.CPU != nil {
|
||||
s.CPUStats = types.CPUStats{
|
||||
CPUUsage: types.CPUUsage{
|
||||
TotalUsage: stats.CPU.Usage.Total,
|
||||
PercpuUsage: stats.CPU.Usage.PerCPU,
|
||||
UsageInKernelmode: stats.CPU.Usage.Kernel,
|
||||
UsageInUsermode: stats.CPU.Usage.User,
|
||||
},
|
||||
ThrottlingData: types.ThrottlingData{
|
||||
Periods: stats.CPU.Throttling.Periods,
|
||||
ThrottledPeriods: stats.CPU.Throttling.ThrottledPeriods,
|
||||
ThrottledTime: stats.CPU.Throttling.ThrottledTime,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Memory != nil {
|
||||
raw := map[string]uint64{
|
||||
"cache": stats.Memory.Cache,
|
||||
"rss": stats.Memory.RSS,
|
||||
"rss_huge": stats.Memory.RSSHuge,
|
||||
"mapped_file": stats.Memory.MappedFile,
|
||||
"dirty": stats.Memory.Dirty,
|
||||
"writeback": stats.Memory.Writeback,
|
||||
"pgpgin": stats.Memory.PgPgIn,
|
||||
"pgpgout": stats.Memory.PgPgOut,
|
||||
"pgfault": stats.Memory.PgFault,
|
||||
"pgmajfault": stats.Memory.PgMajFault,
|
||||
"inactive_anon": stats.Memory.InactiveAnon,
|
||||
"active_anon": stats.Memory.ActiveAnon,
|
||||
"inactive_file": stats.Memory.InactiveFile,
|
||||
"active_file": stats.Memory.ActiveFile,
|
||||
"unevictable": stats.Memory.Unevictable,
|
||||
"hierarchical_memory_limit": stats.Memory.HierarchicalMemoryLimit,
|
||||
"hierarchical_memsw_limit": stats.Memory.HierarchicalSwapLimit,
|
||||
"total_cache": stats.Memory.TotalCache,
|
||||
"total_rss": stats.Memory.TotalRSS,
|
||||
"total_rss_huge": stats.Memory.TotalRSSHuge,
|
||||
"total_mapped_file": stats.Memory.TotalMappedFile,
|
||||
"total_dirty": stats.Memory.TotalDirty,
|
||||
"total_writeback": stats.Memory.TotalWriteback,
|
||||
"total_pgpgin": stats.Memory.TotalPgPgIn,
|
||||
"total_pgpgout": stats.Memory.TotalPgPgOut,
|
||||
"total_pgfault": stats.Memory.TotalPgFault,
|
||||
"total_pgmajfault": stats.Memory.TotalPgMajFault,
|
||||
"total_inactive_anon": stats.Memory.TotalInactiveAnon,
|
||||
"total_active_anon": stats.Memory.TotalActiveAnon,
|
||||
"total_inactive_file": stats.Memory.TotalInactiveFile,
|
||||
"total_active_file": stats.Memory.TotalActiveFile,
|
||||
"total_unevictable": stats.Memory.TotalUnevictable,
|
||||
}
|
||||
if stats.Memory.Usage != nil {
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
Stats: raw,
|
||||
Usage: stats.Memory.Usage.Usage,
|
||||
MaxUsage: stats.Memory.Usage.Max,
|
||||
Limit: stats.Memory.Usage.Limit,
|
||||
Failcnt: stats.Memory.Usage.Failcnt,
|
||||
}
|
||||
} else {
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
Stats: raw,
|
||||
}
|
||||
}
|
||||
|
||||
// if the container does not set memory limit, use the machineMemory
|
||||
if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
|
||||
s.MemoryStats.Limit = daemon.machineMemory
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Pids != nil {
|
||||
s.PidsStats = types.PidsStats{
|
||||
Current: stats.Pids.Current,
|
||||
Limit: stats.Pids.Limit,
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) statsV2(s *types.StatsJSON, stats *statsV2.Metrics) (*types.StatsJSON, error) {
|
||||
if stats.Io != nil {
|
||||
var isbr []types.BlkioStatEntry
|
||||
for _, re := range stats.Io.Usage {
|
||||
isbr = append(isbr,
|
||||
types.BlkioStatEntry{
|
||||
Major: re.Major,
|
||||
Minor: re.Minor,
|
||||
Op: "read",
|
||||
Value: re.Rbytes,
|
||||
},
|
||||
types.BlkioStatEntry{
|
||||
Major: re.Major,
|
||||
Minor: re.Minor,
|
||||
Op: "write",
|
||||
Value: re.Wbytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
s.BlkioStats = types.BlkioStats{
|
||||
IoServiceBytesRecursive: isbr,
|
||||
// Other fields are unsupported
|
||||
}
|
||||
}
|
||||
|
||||
if stats.CPU != nil {
|
||||
s.CPUStats = types.CPUStats{
|
||||
CPUUsage: types.CPUUsage{
|
||||
TotalUsage: stats.CPU.UsageUsec * 1000,
|
||||
// PercpuUsage is not supported
|
||||
UsageInKernelmode: stats.CPU.SystemUsec * 1000,
|
||||
UsageInUsermode: stats.CPU.UserUsec * 1000,
|
||||
},
|
||||
ThrottlingData: types.ThrottlingData{
|
||||
Periods: stats.CPU.NrPeriods,
|
||||
ThrottledPeriods: stats.CPU.NrThrottled,
|
||||
ThrottledTime: stats.CPU.ThrottledUsec * 1000,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Memory != nil {
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
// Stats is not compatible with v1
|
||||
Stats: map[string]uint64{
|
||||
"anon": stats.Memory.Anon,
|
||||
"file": stats.Memory.File,
|
||||
"kernel_stack": stats.Memory.KernelStack,
|
||||
"slab": stats.Memory.Slab,
|
||||
"sock": stats.Memory.Sock,
|
||||
"shmem": stats.Memory.Shmem,
|
||||
"file_mapped": stats.Memory.FileMapped,
|
||||
"file_dirty": stats.Memory.FileDirty,
|
||||
"file_writeback": stats.Memory.FileWriteback,
|
||||
"anon_thp": stats.Memory.AnonThp,
|
||||
"inactive_anon": stats.Memory.InactiveAnon,
|
||||
"active_anon": stats.Memory.ActiveAnon,
|
||||
"inactive_file": stats.Memory.InactiveFile,
|
||||
"active_file": stats.Memory.ActiveFile,
|
||||
"unevictable": stats.Memory.Unevictable,
|
||||
"slab_reclaimable": stats.Memory.SlabReclaimable,
|
||||
"slab_unreclaimable": stats.Memory.SlabUnreclaimable,
|
||||
"pgfault": stats.Memory.Pgfault,
|
||||
"pgmajfault": stats.Memory.Pgmajfault,
|
||||
"workingset_refault": stats.Memory.WorkingsetRefault,
|
||||
"workingset_activate": stats.Memory.WorkingsetActivate,
|
||||
"workingset_nodereclaim": stats.Memory.WorkingsetNodereclaim,
|
||||
"pgrefill": stats.Memory.Pgrefill,
|
||||
"pgscan": stats.Memory.Pgscan,
|
||||
"pgsteal": stats.Memory.Pgsteal,
|
||||
"pgactivate": stats.Memory.Pgactivate,
|
||||
"pgdeactivate": stats.Memory.Pgdeactivate,
|
||||
"pglazyfree": stats.Memory.Pglazyfree,
|
||||
"pglazyfreed": stats.Memory.Pglazyfreed,
|
||||
"thp_fault_alloc": stats.Memory.ThpFaultAlloc,
|
||||
"thp_collapse_alloc": stats.Memory.ThpCollapseAlloc,
|
||||
},
|
||||
Usage: stats.Memory.Usage,
|
||||
// MaxUsage is not supported
|
||||
Limit: stats.Memory.UsageLimit,
|
||||
}
|
||||
// if the container does not set memory limit, use the machineMemory
|
||||
if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
|
||||
s.MemoryStats.Limit = daemon.machineMemory
|
||||
}
|
||||
if stats.MemoryEvents != nil {
|
||||
// Failcnt is set to the "oom" field of the "memory.events" file.
|
||||
// See https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
|
||||
s.MemoryStats.Failcnt = stats.MemoryEvents.Oom
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Pids != nil {
|
||||
s.PidsStats = types.PidsStats{
|
||||
Current: stats.Pids.Current,
|
||||
Limit: stats.Pids.Limit,
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// setDefaultIsolation determines the default isolation mode for the
|
||||
// daemon to run in. This is only applicable on Windows
|
||||
func (daemon *Daemon) setDefaultIsolation() error {
|
||||
|
|
|
@ -10,11 +10,9 @@ import (
|
|||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
"github.com/Microsoft/hcsshim/osversion"
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd/local"
|
||||
"github.com/docker/docker/libcontainerd/remote"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
|
@ -26,7 +24,6 @@ import (
|
|||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/parsers/operatingsystem"
|
||||
"github.com/docker/docker/pkg/platform"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/runconfig"
|
||||
|
@ -513,70 +510,6 @@ func driverOptions(_ *config.Config) nwconfig.Option {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
|
||||
c.Lock()
|
||||
task, err := c.GetRunningTask()
|
||||
c.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Obtain the stats from HCS via libcontainerd
|
||||
stats, err := task.Stats(context.Background())
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
return nil, containerNotFound(c.ID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start with an empty structure
|
||||
s := &types.StatsJSON{}
|
||||
s.Stats.Read = stats.Read
|
||||
s.Stats.NumProcs = platform.NumProcs()
|
||||
|
||||
if stats.HCSStats != nil {
|
||||
hcss := stats.HCSStats
|
||||
// Populate the CPU/processor statistics
|
||||
s.CPUStats = types.CPUStats{
|
||||
CPUUsage: types.CPUUsage{
|
||||
TotalUsage: hcss.Processor.TotalRuntime100ns,
|
||||
UsageInKernelmode: hcss.Processor.RuntimeKernel100ns,
|
||||
UsageInUsermode: hcss.Processor.RuntimeUser100ns,
|
||||
},
|
||||
}
|
||||
|
||||
// Populate the memory statistics
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
Commit: hcss.Memory.UsageCommitBytes,
|
||||
CommitPeak: hcss.Memory.UsageCommitPeakBytes,
|
||||
PrivateWorkingSet: hcss.Memory.UsagePrivateWorkingSetBytes,
|
||||
}
|
||||
|
||||
// Populate the storage statistics
|
||||
s.StorageStats = types.StorageStats{
|
||||
ReadCountNormalized: hcss.Storage.ReadCountNormalized,
|
||||
ReadSizeBytes: hcss.Storage.ReadSizeBytes,
|
||||
WriteCountNormalized: hcss.Storage.WriteCountNormalized,
|
||||
WriteSizeBytes: hcss.Storage.WriteSizeBytes,
|
||||
}
|
||||
|
||||
// Populate the network statistics
|
||||
s.Networks = make(map[string]types.NetworkStats)
|
||||
for _, nstats := range hcss.Network {
|
||||
s.Networks[nstats.EndpointId] = types.NetworkStats{
|
||||
RxBytes: nstats.BytesReceived,
|
||||
RxPackets: nstats.PacketsReceived,
|
||||
RxDropped: nstats.DroppedPacketsIncoming,
|
||||
TxBytes: nstats.BytesSent,
|
||||
TxPackets: nstats.PacketsSent,
|
||||
TxDropped: nstats.DroppedPacketsOutgoing,
|
||||
}
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// setDefaultIsolation determine the default isolation mode for the
|
||||
// daemon to run in. This is only applicable on Windows
|
||||
func (daemon *Daemon) setDefaultIsolation() error {
|
||||
|
|
|
@ -4,11 +4,252 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
statsV1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
statsV2 "github.com/containerd/cgroups/v3/cgroup2/stats"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func copyBlkioEntry(entries []*statsV1.BlkIOEntry) []types.BlkioStatEntry {
|
||||
out := make([]types.BlkioStatEntry, len(entries))
|
||||
for i, re := range entries {
|
||||
out[i] = types.BlkioStatEntry{
|
||||
Major: re.Major,
|
||||
Minor: re.Minor,
|
||||
Op: re.Op,
|
||||
Value: re.Value,
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
|
||||
c.Lock()
|
||||
task, err := c.GetRunningTask()
|
||||
c.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs, err := task.Stats(context.Background())
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "container not found") {
|
||||
return nil, containerNotFound(c.ID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
s := &types.StatsJSON{}
|
||||
s.Read = cs.Read
|
||||
stats := cs.Metrics
|
||||
switch t := stats.(type) {
|
||||
case *statsV1.Metrics:
|
||||
return daemon.statsV1(s, t)
|
||||
case *statsV2.Metrics:
|
||||
return daemon.statsV2(s, t)
|
||||
default:
|
||||
return nil, errors.Errorf("unexpected type of metrics %+v", t)
|
||||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) statsV1(s *types.StatsJSON, stats *statsV1.Metrics) (*types.StatsJSON, error) {
|
||||
if stats.Blkio != nil {
|
||||
s.BlkioStats = types.BlkioStats{
|
||||
IoServiceBytesRecursive: copyBlkioEntry(stats.Blkio.IoServiceBytesRecursive),
|
||||
IoServicedRecursive: copyBlkioEntry(stats.Blkio.IoServicedRecursive),
|
||||
IoQueuedRecursive: copyBlkioEntry(stats.Blkio.IoQueuedRecursive),
|
||||
IoServiceTimeRecursive: copyBlkioEntry(stats.Blkio.IoServiceTimeRecursive),
|
||||
IoWaitTimeRecursive: copyBlkioEntry(stats.Blkio.IoWaitTimeRecursive),
|
||||
IoMergedRecursive: copyBlkioEntry(stats.Blkio.IoMergedRecursive),
|
||||
IoTimeRecursive: copyBlkioEntry(stats.Blkio.IoTimeRecursive),
|
||||
SectorsRecursive: copyBlkioEntry(stats.Blkio.SectorsRecursive),
|
||||
}
|
||||
}
|
||||
if stats.CPU != nil {
|
||||
s.CPUStats = types.CPUStats{
|
||||
CPUUsage: types.CPUUsage{
|
||||
TotalUsage: stats.CPU.Usage.Total,
|
||||
PercpuUsage: stats.CPU.Usage.PerCPU,
|
||||
UsageInKernelmode: stats.CPU.Usage.Kernel,
|
||||
UsageInUsermode: stats.CPU.Usage.User,
|
||||
},
|
||||
ThrottlingData: types.ThrottlingData{
|
||||
Periods: stats.CPU.Throttling.Periods,
|
||||
ThrottledPeriods: stats.CPU.Throttling.ThrottledPeriods,
|
||||
ThrottledTime: stats.CPU.Throttling.ThrottledTime,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Memory != nil {
|
||||
raw := map[string]uint64{
|
||||
"cache": stats.Memory.Cache,
|
||||
"rss": stats.Memory.RSS,
|
||||
"rss_huge": stats.Memory.RSSHuge,
|
||||
"mapped_file": stats.Memory.MappedFile,
|
||||
"dirty": stats.Memory.Dirty,
|
||||
"writeback": stats.Memory.Writeback,
|
||||
"pgpgin": stats.Memory.PgPgIn,
|
||||
"pgpgout": stats.Memory.PgPgOut,
|
||||
"pgfault": stats.Memory.PgFault,
|
||||
"pgmajfault": stats.Memory.PgMajFault,
|
||||
"inactive_anon": stats.Memory.InactiveAnon,
|
||||
"active_anon": stats.Memory.ActiveAnon,
|
||||
"inactive_file": stats.Memory.InactiveFile,
|
||||
"active_file": stats.Memory.ActiveFile,
|
||||
"unevictable": stats.Memory.Unevictable,
|
||||
"hierarchical_memory_limit": stats.Memory.HierarchicalMemoryLimit,
|
||||
"hierarchical_memsw_limit": stats.Memory.HierarchicalSwapLimit,
|
||||
"total_cache": stats.Memory.TotalCache,
|
||||
"total_rss": stats.Memory.TotalRSS,
|
||||
"total_rss_huge": stats.Memory.TotalRSSHuge,
|
||||
"total_mapped_file": stats.Memory.TotalMappedFile,
|
||||
"total_dirty": stats.Memory.TotalDirty,
|
||||
"total_writeback": stats.Memory.TotalWriteback,
|
||||
"total_pgpgin": stats.Memory.TotalPgPgIn,
|
||||
"total_pgpgout": stats.Memory.TotalPgPgOut,
|
||||
"total_pgfault": stats.Memory.TotalPgFault,
|
||||
"total_pgmajfault": stats.Memory.TotalPgMajFault,
|
||||
"total_inactive_anon": stats.Memory.TotalInactiveAnon,
|
||||
"total_active_anon": stats.Memory.TotalActiveAnon,
|
||||
"total_inactive_file": stats.Memory.TotalInactiveFile,
|
||||
"total_active_file": stats.Memory.TotalActiveFile,
|
||||
"total_unevictable": stats.Memory.TotalUnevictable,
|
||||
}
|
||||
if stats.Memory.Usage != nil {
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
Stats: raw,
|
||||
Usage: stats.Memory.Usage.Usage,
|
||||
MaxUsage: stats.Memory.Usage.Max,
|
||||
Limit: stats.Memory.Usage.Limit,
|
||||
Failcnt: stats.Memory.Usage.Failcnt,
|
||||
}
|
||||
} else {
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
Stats: raw,
|
||||
}
|
||||
}
|
||||
|
||||
// if the container does not set memory limit, use the machineMemory
|
||||
if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
|
||||
s.MemoryStats.Limit = daemon.machineMemory
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Pids != nil {
|
||||
s.PidsStats = types.PidsStats{
|
||||
Current: stats.Pids.Current,
|
||||
Limit: stats.Pids.Limit,
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) statsV2(s *types.StatsJSON, stats *statsV2.Metrics) (*types.StatsJSON, error) {
|
||||
if stats.Io != nil {
|
||||
var isbr []types.BlkioStatEntry
|
||||
for _, re := range stats.Io.Usage {
|
||||
isbr = append(isbr,
|
||||
types.BlkioStatEntry{
|
||||
Major: re.Major,
|
||||
Minor: re.Minor,
|
||||
Op: "read",
|
||||
Value: re.Rbytes,
|
||||
},
|
||||
types.BlkioStatEntry{
|
||||
Major: re.Major,
|
||||
Minor: re.Minor,
|
||||
Op: "write",
|
||||
Value: re.Wbytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
s.BlkioStats = types.BlkioStats{
|
||||
IoServiceBytesRecursive: isbr,
|
||||
// Other fields are unsupported
|
||||
}
|
||||
}
|
||||
|
||||
if stats.CPU != nil {
|
||||
s.CPUStats = types.CPUStats{
|
||||
CPUUsage: types.CPUUsage{
|
||||
TotalUsage: stats.CPU.UsageUsec * 1000,
|
||||
// PercpuUsage is not supported
|
||||
UsageInKernelmode: stats.CPU.SystemUsec * 1000,
|
||||
UsageInUsermode: stats.CPU.UserUsec * 1000,
|
||||
},
|
||||
ThrottlingData: types.ThrottlingData{
|
||||
Periods: stats.CPU.NrPeriods,
|
||||
ThrottledPeriods: stats.CPU.NrThrottled,
|
||||
ThrottledTime: stats.CPU.ThrottledUsec * 1000,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Memory != nil {
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
// Stats is not compatible with v1
|
||||
Stats: map[string]uint64{
|
||||
"anon": stats.Memory.Anon,
|
||||
"file": stats.Memory.File,
|
||||
"kernel_stack": stats.Memory.KernelStack,
|
||||
"slab": stats.Memory.Slab,
|
||||
"sock": stats.Memory.Sock,
|
||||
"shmem": stats.Memory.Shmem,
|
||||
"file_mapped": stats.Memory.FileMapped,
|
||||
"file_dirty": stats.Memory.FileDirty,
|
||||
"file_writeback": stats.Memory.FileWriteback,
|
||||
"anon_thp": stats.Memory.AnonThp,
|
||||
"inactive_anon": stats.Memory.InactiveAnon,
|
||||
"active_anon": stats.Memory.ActiveAnon,
|
||||
"inactive_file": stats.Memory.InactiveFile,
|
||||
"active_file": stats.Memory.ActiveFile,
|
||||
"unevictable": stats.Memory.Unevictable,
|
||||
"slab_reclaimable": stats.Memory.SlabReclaimable,
|
||||
"slab_unreclaimable": stats.Memory.SlabUnreclaimable,
|
||||
"pgfault": stats.Memory.Pgfault,
|
||||
"pgmajfault": stats.Memory.Pgmajfault,
|
||||
"workingset_refault": stats.Memory.WorkingsetRefault,
|
||||
"workingset_activate": stats.Memory.WorkingsetActivate,
|
||||
"workingset_nodereclaim": stats.Memory.WorkingsetNodereclaim,
|
||||
"pgrefill": stats.Memory.Pgrefill,
|
||||
"pgscan": stats.Memory.Pgscan,
|
||||
"pgsteal": stats.Memory.Pgsteal,
|
||||
"pgactivate": stats.Memory.Pgactivate,
|
||||
"pgdeactivate": stats.Memory.Pgdeactivate,
|
||||
"pglazyfree": stats.Memory.Pglazyfree,
|
||||
"pglazyfreed": stats.Memory.Pglazyfreed,
|
||||
"thp_fault_alloc": stats.Memory.ThpFaultAlloc,
|
||||
"thp_collapse_alloc": stats.Memory.ThpCollapseAlloc,
|
||||
},
|
||||
Usage: stats.Memory.Usage,
|
||||
// MaxUsage is not supported
|
||||
Limit: stats.Memory.UsageLimit,
|
||||
}
|
||||
// if the container does not set memory limit, use the machineMemory
|
||||
if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
|
||||
s.MemoryStats.Limit = daemon.machineMemory
|
||||
}
|
||||
if stats.MemoryEvents != nil {
|
||||
// Failcnt is set to the "oom" field of the "memory.events" file.
|
||||
// See https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
|
||||
s.MemoryStats.Failcnt = stats.MemoryEvents.Oom
|
||||
}
|
||||
}
|
||||
|
||||
if stats.Pids != nil {
|
||||
s.PidsStats = types.PidsStats{
|
||||
Current: stats.Pids.Current,
|
||||
Limit: stats.Pids.Limit,
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Resolve Network SandboxID in case the container reuse another container's network stack
|
||||
func (daemon *Daemon) getNetworkSandboxID(c *container.Container) (string, error) {
|
||||
curr := c
|
||||
|
|
|
@ -1,10 +1,78 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/platform"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
|
||||
c.Lock()
|
||||
task, err := c.GetRunningTask()
|
||||
c.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Obtain the stats from HCS via libcontainerd
|
||||
stats, err := task.Stats(context.Background())
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
return nil, containerNotFound(c.ID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start with an empty structure
|
||||
s := &types.StatsJSON{}
|
||||
s.Stats.Read = stats.Read
|
||||
s.Stats.NumProcs = platform.NumProcs()
|
||||
|
||||
if stats.HCSStats != nil {
|
||||
hcss := stats.HCSStats
|
||||
// Populate the CPU/processor statistics
|
||||
s.CPUStats = types.CPUStats{
|
||||
CPUUsage: types.CPUUsage{
|
||||
TotalUsage: hcss.Processor.TotalRuntime100ns,
|
||||
UsageInKernelmode: hcss.Processor.RuntimeKernel100ns,
|
||||
UsageInUsermode: hcss.Processor.RuntimeUser100ns,
|
||||
},
|
||||
}
|
||||
|
||||
// Populate the memory statistics
|
||||
s.MemoryStats = types.MemoryStats{
|
||||
Commit: hcss.Memory.UsageCommitBytes,
|
||||
CommitPeak: hcss.Memory.UsageCommitPeakBytes,
|
||||
PrivateWorkingSet: hcss.Memory.UsagePrivateWorkingSetBytes,
|
||||
}
|
||||
|
||||
// Populate the storage statistics
|
||||
s.StorageStats = types.StorageStats{
|
||||
ReadCountNormalized: hcss.Storage.ReadCountNormalized,
|
||||
ReadSizeBytes: hcss.Storage.ReadSizeBytes,
|
||||
WriteCountNormalized: hcss.Storage.WriteCountNormalized,
|
||||
WriteSizeBytes: hcss.Storage.WriteSizeBytes,
|
||||
}
|
||||
|
||||
// Populate the network statistics
|
||||
s.Networks = make(map[string]types.NetworkStats)
|
||||
for _, nstats := range hcss.Network {
|
||||
s.Networks[nstats.EndpointId] = types.NetworkStats{
|
||||
RxBytes: nstats.BytesReceived,
|
||||
RxPackets: nstats.PacketsReceived,
|
||||
RxDropped: nstats.DroppedPacketsIncoming,
|
||||
TxBytes: nstats.BytesSent,
|
||||
TxPackets: nstats.PacketsSent,
|
||||
TxDropped: nstats.DroppedPacketsOutgoing,
|
||||
}
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Windows network stats are obtained directly through HCS, hence this is a no-op.
|
||||
func (daemon *Daemon) getNetworkStats(c *container.Container) (map[string]types.NetworkStats, error) {
|
||||
return make(map[string]types.NetworkStats), nil
|
||||
|
|
Loading…
Reference in a new issue