Skip to content

Commit fba575d

Browse files
authored
Parsing for /proc/softirqs (#436)
* Add parsing for softirqs Also fixes some linting and formatting issues Signed-off-by: abbeywoodyear <[email protected]>
1 parent d917e64 commit fba575d

7 files changed

+276
-10
lines changed

fixtures.ttar

+24-8
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ Inter-| Receive | Transmit
156156
eth0: 438 5 0 0 0 0 0 0 648 8 0 0 0 0 0 0
157157
Mode: 644
158158
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
159+
Path: fixtures/proc/26231/net/netstat
160+
Lines: 4
161+
TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed EmbryonicRsts PruneCalled RcvPruned OfoPruned OutOfWindowIcmps LockDroppedIcmps ArpFilter TW TWRecycled TWKilled PAWSActive PAWSEstab DelayedACKs DelayedACKLocked DelayedACKLost ListenOverflows ListenDrops TCPHPHits TCPPureAcks TCPHPAcks TCPRenoRecovery TCPSackRecovery TCPSACKReneging TCPSACKReorder TCPRenoReorder TCPTSReorder TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo TCPLostRetransmit TCPRenoFailures TCPSackFailures TCPLossFailures TCPFastRetrans TCPSlowStartRetrans TCPTimeouts TCPLossProbes TCPLossProbeRecovery TCPRenoRecoveryFail TCPSackRecoveryFail TCPRcvCollapsed TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv TCPAbortOnData TCPAbortOnClose TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger TCPAbortFailed TCPMemoryPressures TCPMemoryPressuresChrono TCPSACKDiscard TCPDSACKIgnoredOld TCPDSACKIgnoredNoUndo TCPSpuriousRTOs TCPMD5NotFound TCPMD5Unexpected TCPMD5Failure TCPSackShifted TCPSackMerged TCPSackShiftFallback TCPBacklogDrop PFMemallocDrop TCPMinTTLDrop TCPDeferAcceptDrop IPReversePathFilter TCPTimeWaitOverflow TCPReqQFullDoCookies TCPReqQFullDrop TCPRetransFail TCPRcvCoalesce TCPOFOQueue TCPOFODrop TCPOFOMerge TCPChallengeACK TCPSYNChallenge TCPFastOpenActive TCPFastOpenActiveFail TCPFastOpenPassive TCPFastOpenPassiveFail TCPFastOpenListenOverflow TCPFastOpenCookieReqd TCPFastOpenBlackhole TCPSpuriousRtxHostQueues BusyPollRxPackets TCPAutoCorking TCPFromZeroWindowAdv TCPToZeroWindowAdv TCPWantZeroWindowAdv TCPSynRetrans TCPOrigDataSent TCPHystartTrainDetect TCPHystartTrainCwnd TCPHystartDelayDetect TCPHystartDelayCwnd TCPACKSkippedSynRecv TCPACKSkippedPAWS TCPACKSkippedSeq TCPACKSkippedFinWait2 TCPACKSkippedTimeWait TCPACKSkippedChallenge TCPWinProbe TCPKeepAlive TCPMTUPFail TCPMTUPSuccess TCPWqueueTooBig
162+
TcpExt: 0 0 0 1 0 0 0 0 0 0 83 0 0 0 3640 287 1 7460 0 0 134193 1335 829 0 4 0 1 0 0 0 0 1 19 0 0 0 0 3 0 32 100 4 0 0 0 7460 2421 49 1 62 6 0 23 0 7 0 0 0 0 19 2 0 0 0 0 0 6 0 0 0 0 3 0 0 0 0 92425 65515 0 2421 4 4 0 0 0 0 0 0 0 0 0 10 0 0 0 16 2221 0 0 2 45 0 0 3 0 0 0 0 456 0 0 0
163+
IpExt: InNoRoutes InTruncatedPkts InMcastPkts OutMcastPkts InBcastPkts OutBcastPkts InOctets OutOctets InMcastOctets OutMcastOctets InBcastOctets OutBcastOctets InCsumErrors InNoECTPkts InECT1Pkts InECT0Pkts InCEPkts ReasmOverlaps
164+
IpExt: 0 0 208 214 118 111 190585481 7512674 26093 25903 14546 13628 0 134215 0 0 0 0
165+
Mode: 644
166+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
159167
Path: fixtures/proc/26231/net/snmp
160168
Lines: 12
161169
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
@@ -172,14 +180,6 @@ UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InC
172180
UdpLite: 0 0 0 0 0 0 0 0
173181
Mode: 644
174182
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
175-
Path: fixtures/proc/26231/net/netstat
176-
Lines: 4
177-
TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed EmbryonicRsts PruneCalled RcvPruned OfoPruned OutOfWindowIcmps LockDroppedIcmps ArpFilter TW TWRecycled TWKilled PAWSActive PAWSEstab DelayedACKs DelayedACKLocked DelayedACKLost ListenOverflows ListenDrops TCPHPHits TCPPureAcks TCPHPAcks TCPRenoRecovery TCPSackRecovery TCPSACKReneging TCPSACKReorder TCPRenoReorder TCPTSReorder TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo TCPLostRetransmit TCPRenoFailures TCPSackFailures TCPLossFailures TCPFastRetrans TCPSlowStartRetrans TCPTimeouts TCPLossProbes TCPLossProbeRecovery TCPRenoRecoveryFail TCPSackRecoveryFail TCPRcvCollapsed TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv TCPAbortOnData TCPAbortOnClose TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger TCPAbortFailed TCPMemoryPressures TCPMemoryPressuresChrono TCPSACKDiscard TCPDSACKIgnoredOld TCPDSACKIgnoredNoUndo TCPSpuriousRTOs TCPMD5NotFound TCPMD5Unexpected TCPMD5Failure TCPSackShifted TCPSackMerged TCPSackShiftFallback TCPBacklogDrop PFMemallocDrop TCPMinTTLDrop TCPDeferAcceptDrop IPReversePathFilter TCPTimeWaitOverflow TCPReqQFullDoCookies TCPReqQFullDrop TCPRetransFail TCPRcvCoalesce TCPOFOQueue TCPOFODrop TCPOFOMerge TCPChallengeACK TCPSYNChallenge TCPFastOpenActive TCPFastOpenActiveFail TCPFastOpenPassive TCPFastOpenPassiveFail TCPFastOpenListenOverflow TCPFastOpenCookieReqd TCPFastOpenBlackhole TCPSpuriousRtxHostQueues BusyPollRxPackets TCPAutoCorking TCPFromZeroWindowAdv TCPToZeroWindowAdv TCPWantZeroWindowAdv TCPSynRetrans TCPOrigDataSent TCPHystartTrainDetect TCPHystartTrainCwnd TCPHystartDelayDetect TCPHystartDelayCwnd TCPACKSkippedSynRecv TCPACKSkippedPAWS TCPACKSkippedSeq TCPACKSkippedFinWait2 TCPACKSkippedTimeWait TCPACKSkippedChallenge TCPWinProbe TCPKeepAlive TCPMTUPFail TCPMTUPSuccess TCPWqueueTooBig
178-
TcpExt: 0 0 0 1 0 0 0 0 0 0 83 0 0 0 3640 287 1 7460 0 0 134193 1335 829 0 4 0 1 0 0 0 0 1 19 0 0 0 0 3 0 32 100 4 0 0 0 7460 2421 49 1 62 6 0 23 0 7 0 0 0 0 19 2 0 0 0 0 0 6 0 0 0 0 3 0 0 0 0 92425 65515 0 2421 4 4 0 0 0 0 0 0 0 0 0 10 0 0 0 16 2221 0 0 2 45 0 0 3 0 0 0 0 456 0 0 0
179-
IpExt: InNoRoutes InTruncatedPkts InMcastPkts OutMcastPkts InBcastPkts OutBcastPkts InOctets OutOctets InMcastOctets OutMcastOctets InBcastOctets OutBcastOctets InCsumErrors InNoECTPkts InECT1Pkts InECT0Pkts InCEPkts ReasmOverlaps
180-
IpExt: 0 0 208 214 118 111 190585481 7512674 26093 25903 14546 13628 0 134215 0 0 0 0
181-
Mode: 644
182-
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183183
Path: fixtures/proc/26231/net/snmp6
184184
Lines: 92
185185
Ip6InReceives 92166
@@ -274,6 +274,7 @@ UdpLite6RcvbufErrors 0
274274
UdpLite6SndbufErrors 0
275275
UdpLite6InCsumErrors 0
276276
Mode: 644
277+
Mode: 664
277278
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
278279
Directory: fixtures/proc/26231/ns
279280
Mode: 755
@@ -2773,6 +2774,21 @@ kmem_cache_node 904 928 512 32 4 : tunables 0 0 0 : sla
27732774
kmem_cache 904 936 832 39 8 : tunables 0 0 0 : slabdata 24 24 0
27742775
Mode: 644
27752776
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2777+
Path: fixtures/proc/softirqs
2778+
Lines: 11
2779+
CPU0 CPU1
2780+
HI: 3 0
2781+
TIMER: 2776180 247490
2782+
NET_TX: 2419 772
2783+
NET_RX: 55919 28694
2784+
BLOCK: 174915 262755
2785+
IRQ_POLL: 0 0
2786+
TASKLET: 209 75
2787+
SCHED: 2278692 815209
2788+
HRTIMER: 1281 220
2789+
RCU: 605871 532783
2790+
Mode: 444
2791+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
27762792
Path: fixtures/proc/stat
27772793
Lines: 16
27782794
cpu 301854 612 111922 8979004 3552 2 3944 0 0 0

proc_netstat.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func (p Proc) Netstat() (ProcNetstat, error) {
183183
// and returns a ProcNetstat structure.
184184
func parseNetstat(r io.Reader, fileName string) (ProcNetstat, error) {
185185
var (
186-
scanner = bufio.NewScanner(r)
186+
scanner = bufio.NewScanner(r)
187187
procNetstat = ProcNetstat{}
188188
)
189189

proc_netstat_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
// Copyright 2022 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
114
package procfs
215

316
import (

proc_snmp6.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (p Proc) Snmp6() (ProcSnmp6, error) {
160160
// and returns a map contains those metrics.
161161
func parseSNMP6Stats(r io.Reader) (ProcSnmp6, error) {
162162
var (
163-
scanner = bufio.NewScanner(r)
163+
scanner = bufio.NewScanner(r)
164164
procSnmp6 = ProcSnmp6{}
165165
)
166166

proc_snmp6_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
// Copyright 2022 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
114
package procfs
215

316
import "testing"

softirqs.go

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright 2022 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package procfs
15+
16+
import (
17+
"bufio"
18+
"bytes"
19+
"fmt"
20+
"io"
21+
"strconv"
22+
"strings"
23+
24+
"github.com/prometheus/procfs/internal/util"
25+
)
26+
27+
// Softirqs represents the softirq statistics.
28+
type Softirqs struct {
29+
Hi []uint64
30+
Timer []uint64
31+
NetTx []uint64
32+
NetRx []uint64
33+
Block []uint64
34+
IRQPoll []uint64
35+
Tasklet []uint64
36+
Sched []uint64
37+
HRTimer []uint64
38+
RCU []uint64
39+
}
40+
41+
func (fs FS) Softirqs() (Softirqs, error) {
42+
fileName := fs.proc.Path("softirqs")
43+
data, err := util.ReadFileNoStat(fileName)
44+
if err != nil {
45+
return Softirqs{}, err
46+
}
47+
48+
reader := bytes.NewReader(data)
49+
50+
return parseSoftirqs(reader)
51+
}
52+
53+
func parseSoftirqs(r io.Reader) (Softirqs, error) {
54+
var (
55+
softirqs = Softirqs{}
56+
scanner = bufio.NewScanner(r)
57+
)
58+
59+
if !scanner.Scan() {
60+
return Softirqs{}, fmt.Errorf("softirqs empty")
61+
}
62+
63+
for scanner.Scan() {
64+
parts := strings.Fields(scanner.Text())
65+
var err error
66+
67+
// require at least one cpu
68+
if len(parts) < 2 {
69+
continue
70+
}
71+
switch {
72+
case parts[0] == "HI:":
73+
perCpu := parts[1:]
74+
softirqs.Hi = make([]uint64, len(perCpu))
75+
for i, count := range perCpu {
76+
if softirqs.Hi[i], err = strconv.ParseUint(count, 10, 64); err != nil {
77+
return Softirqs{}, fmt.Errorf("couldn't parse %q (HI%d): %w", count, i, err)
78+
}
79+
}
80+
case parts[0] == "TIMER:":
81+
perCpu := parts[1:]
82+
softirqs.Timer = make([]uint64, len(perCpu))
83+
for i, count := range perCpu {
84+
if softirqs.Timer[i], err = strconv.ParseUint(count, 10, 64); err != nil {
85+
return Softirqs{}, fmt.Errorf("couldn't parse %q (TIMER%d): %w", count, i, err)
86+
}
87+
}
88+
case parts[0] == "NET_TX:":
89+
perCpu := parts[1:]
90+
softirqs.NetTx = make([]uint64, len(perCpu))
91+
for i, count := range perCpu {
92+
if softirqs.NetTx[i], err = strconv.ParseUint(count, 10, 64); err != nil {
93+
return Softirqs{}, fmt.Errorf("couldn't parse %q (NET_TX%d): %w", count, i, err)
94+
}
95+
}
96+
case parts[0] == "NET_RX:":
97+
perCpu := parts[1:]
98+
softirqs.NetRx = make([]uint64, len(perCpu))
99+
for i, count := range perCpu {
100+
if softirqs.NetRx[i], err = strconv.ParseUint(count, 10, 64); err != nil {
101+
return Softirqs{}, fmt.Errorf("couldn't parse %q (NET_RX%d): %w", count, i, err)
102+
}
103+
}
104+
case parts[0] == "BLOCK:":
105+
perCpu := parts[1:]
106+
softirqs.Block = make([]uint64, len(perCpu))
107+
for i, count := range perCpu {
108+
if softirqs.Block[i], err = strconv.ParseUint(count, 10, 64); err != nil {
109+
return Softirqs{}, fmt.Errorf("couldn't parse %q (BLOCK%d): %w", count, i, err)
110+
}
111+
}
112+
case parts[0] == "IRQ_POLL:":
113+
perCpu := parts[1:]
114+
softirqs.IRQPoll = make([]uint64, len(perCpu))
115+
for i, count := range perCpu {
116+
if softirqs.IRQPoll[i], err = strconv.ParseUint(count, 10, 64); err != nil {
117+
return Softirqs{}, fmt.Errorf("couldn't parse %q (IRQ_POLL%d): %w", count, i, err)
118+
}
119+
}
120+
case parts[0] == "TASKLET:":
121+
perCpu := parts[1:]
122+
softirqs.Tasklet = make([]uint64, len(perCpu))
123+
for i, count := range perCpu {
124+
if softirqs.Tasklet[i], err = strconv.ParseUint(count, 10, 64); err != nil {
125+
return Softirqs{}, fmt.Errorf("couldn't parse %q (TASKLET%d): %w", count, i, err)
126+
}
127+
}
128+
case parts[0] == "SCHED:":
129+
perCpu := parts[1:]
130+
softirqs.Sched = make([]uint64, len(perCpu))
131+
for i, count := range perCpu {
132+
if softirqs.Sched[i], err = strconv.ParseUint(count, 10, 64); err != nil {
133+
return Softirqs{}, fmt.Errorf("couldn't parse %q (SCHED%d): %w", count, i, err)
134+
}
135+
}
136+
case parts[0] == "HRTIMER:":
137+
perCpu := parts[1:]
138+
softirqs.HRTimer = make([]uint64, len(perCpu))
139+
for i, count := range perCpu {
140+
if softirqs.HRTimer[i], err = strconv.ParseUint(count, 10, 64); err != nil {
141+
return Softirqs{}, fmt.Errorf("couldn't parse %q (HRTIMER%d): %w", count, i, err)
142+
}
143+
}
144+
case parts[0] == "RCU:":
145+
perCpu := parts[1:]
146+
softirqs.RCU = make([]uint64, len(perCpu))
147+
for i, count := range perCpu {
148+
if softirqs.RCU[i], err = strconv.ParseUint(count, 10, 64); err != nil {
149+
return Softirqs{}, fmt.Errorf("couldn't parse %q (RCU%d): %w", count, i, err)
150+
}
151+
}
152+
}
153+
}
154+
155+
if err := scanner.Err(); err != nil {
156+
return Softirqs{}, fmt.Errorf("couldn't parse softirqs: %w", err)
157+
}
158+
159+
return softirqs, scanner.Err()
160+
}

softirqs_test.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2022 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package procfs
15+
16+
import "testing"
17+
18+
func TestSoftirqs(t *testing.T) {
19+
s, err := getProcFixtures(t).Softirqs()
20+
if err != nil {
21+
t.Fatal(err)
22+
}
23+
24+
// hi
25+
if want, have := uint64(3), s.Hi[0]; want != have {
26+
t.Errorf("want softirq HI count %d, have %d", want, have)
27+
}
28+
// timer
29+
if want, have := uint64(247490), s.Timer[1]; want != have {
30+
t.Errorf("want softirq TIMER count %d, have %d", want, have)
31+
}
32+
// net_tx
33+
if want, have := uint64(2419), s.NetTx[0]; want != have {
34+
t.Errorf("want softirq NET_TX count %d, have %d", want, have)
35+
}
36+
// net_rx
37+
if want, have := uint64(28694), s.NetRx[1]; want != have {
38+
t.Errorf("want softirq NET_RX count %d, have %d", want, have)
39+
}
40+
// block
41+
if want, have := uint64(262755), s.Block[1]; want != have {
42+
t.Errorf("want softirq BLOCK count %d, have %d", want, have)
43+
}
44+
// irq_poll
45+
if want, have := uint64(0), s.IRQPoll[0]; want != have {
46+
t.Errorf("want softirq IRQ_POLL count %d, have %d", want, have)
47+
}
48+
// tasklet
49+
if want, have := uint64(209), s.Tasklet[0]; want != have {
50+
t.Errorf("want softirq TASKLET count %d, have %d", want, have)
51+
}
52+
// sched
53+
if want, have := uint64(2278692), s.Sched[0]; want != have {
54+
t.Errorf("want softirq SCHED count %d, have %d", want, have)
55+
}
56+
// hrtimer
57+
if want, have := uint64(1281), s.HRTimer[0]; want != have {
58+
t.Errorf("want softirq HRTIMER count %d, have %d", want, have)
59+
}
60+
// rcu
61+
if want, have := uint64(532783), s.RCU[1]; want != have {
62+
t.Errorf("want softirq RCU count %d, have %d", want, have)
63+
}
64+
}

0 commit comments

Comments
 (0)