Browse code

Make the stats collector to collect network stats.

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>

David Calavera authored on 2015/11/03 11:06:44
Showing 2 changed files
... ...
@@ -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
+}