Skip to content

Commit 114953a

Browse files
Network top layout (#49)
* Fixed: output layout for network-top looks well. * Fixed: tests for softnet-stat-top. * Changed: new __sub__() returns SoftnetStat object. * Added: __eq__() function, comparing each field in SoftnetStat objects.
1 parent 39521e7 commit 114953a

File tree

5 files changed

+107
-18
lines changed

5 files changed

+107
-18
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,5 @@ mac_run: env
4848
network-top --random \
4949
--softirqs-file=./tests/softirqs/i7/softirqs1 \
5050
--softnet-stat-file=./tests/softnet_stat/softnet_stat1 \
51-
--interrupts-file=./tests/interrupts/multinic_multiqueue_4cpu/interrupts_short \
51+
--interrupts-file=./tests/interrupts/singlequeue_8cpu/interrupts_short \
5252
--devices=eth1,eth2,eth3

netutils_linux/network_top.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,62 @@ def tick(self):
3333
_top.tick()
3434
self.eval()
3535

36+
def __repr_dev(self):
37+
top = self.tops.get('link-rate')
38+
repr_source = top.diff if top.options.delta_mode else top.current
39+
output = ["# network devices\n"]
40+
for dev in top.options.devices:
41+
output.append("{0:<14} {1}".format(dev, top.__repr_dev__(dev)))
42+
return "\n".join(output)
43+
44+
def __repr_irq(self):
45+
top = self.tops.get('irqtop')
46+
repr_source = top.diff if top.options.delta_mode else top.current
47+
if not top.diff_total:
48+
return ""
49+
# output_lines = ["\t".join(str(x) for x in ['Total:'] + map(str, top.diff_total))]
50+
output_lines = list()
51+
for line in repr_source:
52+
if line[0] == 'CPU0':
53+
line.insert(0, ' ')
54+
elif top.skip_zero_line(line):
55+
continue
56+
output_lines.append("\t".join(map(str, line)))
57+
return "\n".join(["# /proc/interrupts\n"] + output_lines)
58+
59+
def __repr_cpu(self):
60+
irqtop = self.tops.get('irqtop')
61+
softirq_top = self.tops.get('softirq_top')
62+
softnet_stat_top = self.tops.get('softnet_stat_top')
63+
64+
# all these evaluations are better to put in softirqs.parse()
65+
softirq_repr_source = softirq_top.diff if softirq_top.options.delta_mode else softirq_top.current
66+
active_cpu_count = softirq_top.__active_cpu_count__(softirq_top.current)
67+
softirq_output = softirq_repr_source.get('NET_RX')[:active_cpu_count]
68+
softnet_stat_top_output = softnet_stat_top.diff if softnet_stat_top.options.delta_mode else softnet_stat_top.current
69+
70+
network_output = zip(irqtop.diff_total, softirq_output, softnet_stat_top_output)
71+
fields = ["CPU", "Interrupts", "NET RX", "total", "dropped", "time_squeeze", "cpu_collision", "received_rps"]
72+
header = "# Load per cpu:\n\n{0:6} {1:>12} {2:>12} {3:>12} {4:>8} {5:>12} {6:>13} {7:>12}".format(*fields)
73+
output = [header] + [
74+
"CPU{0:3}: {1:>12} {2:>12} {3:>12} {4:>8} {5:>12} {6:>13} {7:>12}".format(softnet_stat.cpu, irq, softirq,
75+
softnet_stat.total,
76+
softnet_stat.dropped,
77+
softnet_stat.time_squeeze,
78+
softnet_stat.cpu_collision,
79+
softnet_stat.received_rps)
80+
for irq, softirq, softnet_stat in network_output
81+
]
82+
return "\n".join(output)
83+
3684
def __repr__(self):
37-
return "\n".join(str(_top) for top_name, _top in self.tops.iteritems())
85+
# return "\n".join(str(_top) for top_name, _top in self.tops.iteritems())
86+
return "\n\n".join([
87+
self.header,
88+
self.__repr_irq(),
89+
self.__repr_cpu(),
90+
self.__repr_dev(),
91+
])
3892

3993
def parse_options(self):
4094
parser = OptionParser()

netutils_linux/softnet_stat.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,51 @@
44

55

66
class SoftnetStat:
7-
def __init__(self, row, cpu, random=False):
7+
cpu = None
8+
total = None
9+
dropped = None
10+
time_squeeze = None
11+
cpu_collision = None
12+
received_rps = None
13+
14+
def __init__(self, random=False):
15+
self.random = random
16+
17+
def parse_string(self, row, cpu):
818
row = [int('0x' + x, 16) for x in row.strip().split()]
919
self.total, self.dropped, self.time_squeeze = row[0:3]
1020
self.cpu_collision = row[6]
1121
self.received_rps = row[7]
1222
self.cpu = cpu
13-
self.random = random
23+
return self
24+
25+
def parse_list(self, data):
26+
self.cpu, self.total, self.dropped, self.time_squeeze, self.cpu_collision, self.received_rps = data
27+
return self
1428

1529
def __repr__(self):
1630
return "CPU: {0:2} total: {1:11} dropped: {2} time_squeeze: {3:4} cpu_collision: {4} received_rps: {5}" \
1731
.format(self.cpu, self.total, self.dropped, self.time_squeeze, self.cpu_collision, self.received_rps)
1832

1933
def __sub__(self, other):
20-
template = "CPU: {0:2} total: {1:8} dropped: {2} time_squeeze: {3} cpu_collision: {4} received_rps: {5}"
21-
if self.random:
22-
return template.format(self.cpu, randint(1, 100000), randint(0, 1), randint(0, 10), 0, randint(0, 5))
23-
return template \
24-
.format(self.cpu,
25-
self.total - other.total,
26-
self.dropped - other.dropped,
27-
self.time_squeeze - other.time_squeeze,
28-
self.cpu_collision - other.cpu_collision,
29-
self.received_rps - other.received_rps)
34+
return SoftnetStat().parse_list([
35+
self.cpu,
36+
randint(1, 100000) if self.random else self.total - other.total,
37+
randint(0, 1) if self.random else self.dropped - other.dropped,
38+
randint(0, 10) if self.random else self.time_squeeze - other.time_squeeze,
39+
0 if self.random else self.cpu_collision - other.cpu_collision,
40+
randint(0, 5) if self.random else self.received_rps - other.received_rps
41+
])
42+
43+
def __eq__(self, other):
44+
return all([
45+
self.cpu == other.cpu,
46+
self.total == other.total,
47+
self.dropped == other.dropped,
48+
self.time_squeeze == other.time_squeeze,
49+
self.cpu_collision == other.cpu_collision,
50+
self.received_rps == other.received_rps,
51+
])
3052

3153

3254
class SoftnetStatTop(BaseTop):
@@ -41,9 +63,10 @@ def __init__(self):
4163
def parse(self):
4264
with open(self.options.softnet_stat_file) as softnet_stat:
4365
data = softnet_stat.read().strip().split('\n')
44-
return [SoftnetStat(row, cpu, self.options.random) for cpu, row in enumerate(data)]
66+
return [SoftnetStat(self.options.random).parse_string(row, cpu) for cpu, row in enumerate(data)]
4567

4668
def eval(self):
69+
print self.current
4770
self.diff = [data - self.previous[cpu] for cpu, data in enumerate(self.current)]
4871

4972
def __repr__(self):
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
2+
0: 133 0 0 0 0 0 0 0 IR-IO-APIC-edge timer
3+
17: 825698509 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi eth0
4+
18: 888213 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi eth1
5+
26: 5922 0 0 0 0 0 0 0 IR-HPET_MSI-edge hpet2
6+
34: 362262054 0 0 0 0 0 0 0 IR-PCI-MSI-edge ahci
7+
35: 301 0 0 0 0 0 0 0 IR-PCI-MSI-edge snd_hda_intel
8+
LOC: 1524101041 1201179305 1064310873 976437815 1527876073 1057933934 1005872914 926783958 Local timer interrupts
9+
RES: 27928951 23470011 22810864 23039338 29556969 24381694 22775135 21870396 Rescheduling interrupts
10+
CAL: 35167682 25159679 16355174 11470742 30081046 19313300 12014676 8780072 Function call interrupts
11+
TLB: 11033015 13526546 12035501 10882796 13228285 19068022 16802525 13950467 TLB shootdowns

tests/softnet_stat_test.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ class SoftnetStatTests(unittest.TestCase):
2828
"""
2929

3030
def test_delta(self):
31-
__first = [SoftnetStat(row, cpu) for cpu, row in enumerate(self.first.strip().split('\n'))]
32-
__second = [SoftnetStat(row, cpu) for cpu, row in enumerate(self.second.strip().split('\n'))]
31+
__first = [SoftnetStat().parse_string(row, cpu) for cpu, row in enumerate(self.first.strip().split('\n'))]
32+
__second = [SoftnetStat().parse_string(row, cpu) for cpu, row in enumerate(self.second.strip().split('\n'))]
3333
delta = __second[0] - __first[0]
34-
expected = 'CPU: 0 total: 11936 dropped: 0 time_squeeze: 0 cpu_collision: 0 received_rps: 0'
34+
data = [0, 11936, 0, 0, 0, 0]
35+
expected = SoftnetStat().parse_list(data)
3536
self.assertEqual(delta, expected)
3637

3738

0 commit comments

Comments
 (0)