Currently, we get the network stats each time per subscriber, causing a
high load of cpu when there are several subscribers per container.
This change makes the daemon to collect once and publish N times, where N is the
number of subscribers per container.
Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -8,8 +8,6 @@ import ( |
| 8 | 8 |
"github.com/docker/docker/api/types/versions/v1p20" |
| 9 | 9 |
"github.com/docker/docker/daemon/execdriver" |
| 10 | 10 |
"github.com/docker/docker/pkg/version" |
| 11 |
- lntypes "github.com/docker/libnetwork/types" |
|
| 12 |
- "github.com/opencontainers/runc/libcontainer" |
|
| 13 | 11 |
) |
| 14 | 12 |
|
| 15 | 13 |
// ContainerStatsConfig holds information for configuring the runtime |
| ... | ... |
@@ -45,10 +43,6 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats |
| 45 | 45 |
var preCPUStats types.CPUStats |
| 46 | 46 |
getStatJSON := func(v interface{}) *types.StatsJSON {
|
| 47 | 47 |
update := v.(*execdriver.ResourceStats) |
| 48 |
- // Retrieve the nw statistics from libnetwork and inject them in the Stats |
|
| 49 |
- if nwStats, err := daemon.getNetworkStats(container); err == nil {
|
|
| 50 |
- update.Stats.Interfaces = nwStats |
|
| 51 |
- } |
|
| 52 | 48 |
ss := convertStatsToAPITypes(update.Stats) |
| 53 | 49 |
ss.PreCPUStats = preCPUStats |
| 54 | 50 |
ss.MemoryStats.Limit = uint64(update.MemoryLimit) |
| ... | ... |
@@ -129,37 +123,3 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats |
| 129 | 129 |
} |
| 130 | 130 |
} |
| 131 | 131 |
} |
| 132 |
- |
|
| 133 |
-func (daemon *Daemon) getNetworkStats(c *Container) ([]*libcontainer.NetworkInterface, error) {
|
|
| 134 |
- var list []*libcontainer.NetworkInterface |
|
| 135 |
- |
|
| 136 |
- sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID) |
|
| 137 |
- if err != nil {
|
|
| 138 |
- return list, err |
|
| 139 |
- } |
|
| 140 |
- |
|
| 141 |
- stats, err := sb.Statistics() |
|
| 142 |
- if err != nil {
|
|
| 143 |
- return list, err |
|
| 144 |
- } |
|
| 145 |
- |
|
| 146 |
- // Convert libnetwork nw stats into libcontainer nw stats |
|
| 147 |
- for ifName, ifStats := range stats {
|
|
| 148 |
- list = append(list, convertLnNetworkStats(ifName, ifStats)) |
|
| 149 |
- } |
|
| 150 |
- |
|
| 151 |
- return list, nil |
|
| 152 |
-} |
|
| 153 |
- |
|
| 154 |
-func convertLnNetworkStats(name string, stats *lntypes.InterfaceStatistics) *libcontainer.NetworkInterface {
|
|
| 155 |
- n := &libcontainer.NetworkInterface{Name: name}
|
|
| 156 |
- n.RxBytes = stats.RxBytes |
|
| 157 |
- n.RxPackets = stats.RxPackets |
|
| 158 |
- n.RxErrors = stats.RxErrors |
|
| 159 |
- n.RxDropped = stats.RxDropped |
|
| 160 |
- n.TxBytes = stats.TxBytes |
|
| 161 |
- n.TxPackets = stats.TxPackets |
|
| 162 |
- n.TxErrors = stats.TxErrors |
|
| 163 |
- n.TxDropped = stats.TxDropped |
|
| 164 |
- return n |
|
| 165 |
-} |
| ... | ... |
@@ -14,6 +14,8 @@ import ( |
| 14 | 14 |
"github.com/docker/docker/daemon/execdriver" |
| 15 | 15 |
derr "github.com/docker/docker/errors" |
| 16 | 16 |
"github.com/docker/docker/pkg/pubsub" |
| 17 |
+ lntypes "github.com/docker/libnetwork/types" |
|
| 18 |
+ "github.com/opencontainers/runc/libcontainer" |
|
| 17 | 19 |
"github.com/opencontainers/runc/libcontainer/system" |
| 18 | 20 |
) |
| 19 | 21 |
|
| ... | ... |
@@ -118,6 +120,11 @@ func (s *statsCollector) run() {
|
| 118 | 118 |
continue |
| 119 | 119 |
} |
| 120 | 120 |
stats.SystemUsage = systemUsage |
| 121 |
+ |
|
| 122 |
+ // Retrieve the nw statistics from libnetwork and inject them in the Stats |
|
| 123 |
+ if nwStats, err := s.getNetworkStats(pair.container); err == nil {
|
|
| 124 |
+ stats.Interfaces = nwStats |
|
| 125 |
+ } |
|
| 121 | 126 |
pair.publisher.Publish(stats) |
| 122 | 127 |
} |
| 123 | 128 |
} |
| ... | ... |
@@ -170,3 +177,37 @@ func (s *statsCollector) getSystemCPUUsage() (uint64, error) {
|
| 170 | 170 |
} |
| 171 | 171 |
return 0, derr.ErrorCodeBadStatFormat |
| 172 | 172 |
} |
| 173 |
+ |
|
| 174 |
+func (s *statsCollector) getNetworkStats(c *Container) ([]*libcontainer.NetworkInterface, error) {
|
|
| 175 |
+ var list []*libcontainer.NetworkInterface |
|
| 176 |
+ |
|
| 177 |
+ sb, err := c.daemon.netController.SandboxByID(c.NetworkSettings.SandboxID) |
|
| 178 |
+ if err != nil {
|
|
| 179 |
+ return list, err |
|
| 180 |
+ } |
|
| 181 |
+ |
|
| 182 |
+ stats, err := sb.Statistics() |
|
| 183 |
+ if err != nil {
|
|
| 184 |
+ return list, err |
|
| 185 |
+ } |
|
| 186 |
+ |
|
| 187 |
+ // Convert libnetwork nw stats into libcontainer nw stats |
|
| 188 |
+ for ifName, ifStats := range stats {
|
|
| 189 |
+ list = append(list, convertLnNetworkStats(ifName, ifStats)) |
|
| 190 |
+ } |
|
| 191 |
+ |
|
| 192 |
+ return list, nil |
|
| 193 |
+} |
|
| 194 |
+ |
|
| 195 |
+func convertLnNetworkStats(name string, stats *lntypes.InterfaceStatistics) *libcontainer.NetworkInterface {
|
|
| 196 |
+ n := &libcontainer.NetworkInterface{Name: name}
|
|
| 197 |
+ n.RxBytes = stats.RxBytes |
|
| 198 |
+ n.RxPackets = stats.RxPackets |
|
| 199 |
+ n.RxErrors = stats.RxErrors |
|
| 200 |
+ n.RxDropped = stats.RxDropped |
|
| 201 |
+ n.TxBytes = stats.TxBytes |
|
| 202 |
+ n.TxPackets = stats.TxPackets |
|
| 203 |
+ n.TxErrors = stats.TxErrors |
|
| 204 |
+ n.TxDropped = stats.TxDropped |
|
| 205 |
+ return n |
|
| 206 |
+} |