Skip to content

Commit a40b67f

Browse files
committed
Merge pull request #981 from jimmidyson/net-stats-from-proc
Improve perf of interface stats parsing
2 parents fe7e856 + 360c73c commit a40b67f

File tree

1 file changed

+46
-15
lines changed

1 file changed

+46
-15
lines changed

container/libcontainer/helpers.go

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,38 +149,70 @@ func isIgnoredDevice(ifName string) bool {
149149
const netstatsLine = `%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d`
150150

151151
func scanInterfaceStats(netStatsFile string) ([]info.InterfaceStats, error) {
152-
var (
153-
bkt uint64
154-
)
155-
156-
stats := []info.InterfaceStats{}
157-
158152
file, err := os.Open(netStatsFile)
159153
if err != nil {
160-
return stats, fmt.Errorf("failure opening %s: %v", netStatsFile, err)
154+
return nil, fmt.Errorf("failure opening %s: %v", netStatsFile, err)
161155
}
162156
defer file.Close()
163157

164158
scanner := bufio.NewScanner(file)
165159

160+
// Discard header lines
161+
for i := 0; i < 2; i++ {
162+
if b := scanner.Scan(); !b {
163+
return nil, scanner.Err()
164+
}
165+
}
166+
167+
stats := []info.InterfaceStats{}
166168
for scanner.Scan() {
167169
line := scanner.Text()
168170
line = strings.Replace(line, ":", "", -1)
169171

170-
i := info.InterfaceStats{}
172+
fields := strings.Fields(line)
173+
// If the format of the line is invalid then don't trust any of the stats
174+
// in this file.
175+
if len(fields) != 17 {
176+
return nil, fmt.Errorf("invalid interface stats line: %v", line)
177+
}
178+
179+
devName := fields[0]
180+
if isIgnoredDevice(devName) {
181+
continue
182+
}
183+
184+
i := info.InterfaceStats{
185+
Name: devName,
186+
}
171187

172-
_, err := fmt.Sscanf(line, netstatsLine,
173-
&i.Name, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt,
174-
&bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt)
188+
statFields := append(fields[1:5], fields[9:13]...)
189+
statPointers := []*uint64{
190+
&i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped,
191+
&i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped,
192+
}
175193

176-
if err == nil && !isIgnoredDevice(i.Name) {
177-
stats = append(stats, i)
194+
err := setInterfaceStatValues(statFields, statPointers)
195+
if err != nil {
196+
return nil, fmt.Errorf("cannot parse interface stats (%v): %v", err, line)
178197
}
198+
199+
stats = append(stats, i)
179200
}
180201

181202
return stats, nil
182203
}
183204

205+
func setInterfaceStatValues(fields []string, pointers []*uint64) error {
206+
for i, v := range fields {
207+
val, err := strconv.ParseUint(v, 10, 64)
208+
if err != nil {
209+
return err
210+
}
211+
*pointers[i] = val
212+
}
213+
return nil
214+
}
215+
184216
func tcpStatsFromProc(rootFs string, pid int, file string) (info.TcpStat, error) {
185217
tcpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file)
186218

@@ -221,8 +253,7 @@ func scanTcpStats(tcpStatsFile string) (info.TcpStat, error) {
221253
scanner.Split(bufio.ScanLines)
222254

223255
// Discard header line
224-
b := scanner.Scan()
225-
if !b {
256+
if b := scanner.Scan(); !b {
226257
return stats, scanner.Err()
227258
}
228259

0 commit comments

Comments
 (0)