diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index c1c2cdb9b5..503c227261 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -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 { diff --git a/daemon/daemon_windows.go b/daemon/daemon_windows.go index f1dbd75c91..f63900e56c 100644 --- a/daemon/daemon_windows.go +++ b/daemon/daemon_windows.go @@ -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 { diff --git a/daemon/stats_unix.go b/daemon/stats_unix.go index 0afc953266..ebc4d31da6 100644 --- a/daemon/stats_unix.go +++ b/daemon/stats_unix.go @@ -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 diff --git a/daemon/stats_windows.go b/daemon/stats_windows.go index 0306332b48..e8547482a1 100644 --- a/daemon/stats_windows.go +++ b/daemon/stats_windows.go @@ -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