summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlga Denisova <denisova.olga.k@yandex.ru>2025-04-15 19:35:27 +0300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-04-24 11:27:06 +0100
commitf68e3e49d4f55e7c451450ffa3e33eb111ec5249 (patch)
treea397c3a1d3a1b06f8f4bce01258ea1f3d8e8cabb
parenta0c83d90690763991d6445305e74a3994f1e47e8 (diff)
downloadpoky-f68e3e49d4f55e7c451450ffa3e33eb111ec5249.tar.gz
pybootchartgui: visualize /proc/net/dev network stats in graphs
This patch adds support for parsing and visualizing network interface statistics from /proc/net/dev in pybootchartgui. It introduces a new NetSample class to hold per-interface metrics, including received/transmitted bytes and their deltas over time. The data is drawn using line and box charts in draw.py and helps to monitor network usage during the boot process for each interface individually. (From OE-Core rev: 9e640022c83a627bd05c23b66b658bd644b2f0d7) Signed-off-by: denisova-ok <denisova.olga.k@yandex.ru> Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--scripts/pybootchartgui/pybootchartgui/draw.py48
-rw-r--r--scripts/pybootchartgui/pybootchartgui/parsing.py18
-rw-r--r--scripts/pybootchartgui/pybootchartgui/samples.py10
3 files changed, 76 insertions, 0 deletions
diff --git a/scripts/pybootchartgui/pybootchartgui/draw.py b/scripts/pybootchartgui/pybootchartgui/draw.py
index c6e67833ab..16739a0fa1 100644
--- a/scripts/pybootchartgui/pybootchartgui/draw.py
+++ b/scripts/pybootchartgui/pybootchartgui/draw.py
@@ -69,6 +69,11 @@ CPU_COLOR = (0.40, 0.55, 0.70, 1.0)
69IO_COLOR = (0.76, 0.48, 0.48, 0.5) 69IO_COLOR = (0.76, 0.48, 0.48, 0.5)
70# Disk throughput color. 70# Disk throughput color.
71DISK_TPUT_COLOR = (0.20, 0.71, 0.20, 1.0) 71DISK_TPUT_COLOR = (0.20, 0.71, 0.20, 1.0)
72
73BYTES_RECEIVED_COLOR = (0.0, 0.0, 1.0, 1.0)
74BYTES_TRANSMITTED_COLOR = (1.0, 0.0, 0.0, 1.0)
75BYTES_RECEIVE_DIFF_COLOR = (0.0, 0.0, 1.0, 0.3)
76BYTES_TRANSMIT_DIFF_COLOR = (1.0, 0.0, 0.0, 0.3)
72# CPU load chart color. 77# CPU load chart color.
73FILE_OPEN_COLOR = (0.20, 0.71, 0.71, 1.0) 78FILE_OPEN_COLOR = (0.20, 0.71, 0.71, 1.0)
74# Mem cached color 79# Mem cached color
@@ -437,6 +442,49 @@ def render_charts(ctx, options, clip, trace, curr_y, w, h, sec_w):
437 442
438 curr_y = curr_y + 30 + bar_h 443 curr_y = curr_y + 30 + bar_h
439 444
445 if trace.net_stats:
446 for iface, samples in trace.net_stats.items():
447 max_received_sample = max(samples, key=lambda s: s.received_bytes)
448 max_transmitted_sample = max(samples, key=lambda s: s.transmitted_bytes)
449 max_receive_diff_sample = max(samples, key=lambda s: s.receive_diff)
450 max_transmit_diff_sample = max(samples, key=lambda s: s.transmit_diff)
451
452 draw_text(ctx, "Iface: %s" % (iface), TEXT_COLOR, off_x, curr_y+20)
453 draw_legend_line(ctx, "Bytes received (max %d)" % (max_received_sample.received_bytes),
454 BYTES_RECEIVED_COLOR, off_x+150, curr_y+20, leg_s)
455 draw_legend_line(ctx, "Bytes transmitted (max %d)" % (max_transmitted_sample.transmitted_bytes),
456 BYTES_TRANSMITTED_COLOR, off_x+400, curr_y+20, leg_s)
457 draw_legend_box(ctx, "Bytes receive diff (max %d)" % (max_receive_diff_sample.receive_diff),
458 BYTES_RECEIVE_DIFF_COLOR, off_x+650, curr_y+20, leg_s)
459 draw_legend_box(ctx, "Bytes transmit diff (max %d)" % (max_transmit_diff_sample.transmit_diff),
460 BYTES_TRANSMIT_DIFF_COLOR, off_x+900, curr_y+20, leg_s)
461
462
463 chart_rect = (off_x, curr_y + 30, w, bar_h)
464 if clip_visible(clip, chart_rect):
465 draw_box_ticks(ctx, chart_rect, sec_w)
466 draw_annotations(ctx, proc_tree, trace.times, chart_rect)
467
468 if clip_visible (clip, chart_rect):
469 draw_chart (ctx, BYTES_RECEIVED_COLOR, False, chart_rect, \
470 [(sample.time, sample.received_bytes) for sample in samples], \
471 proc_tree, None)
472
473 draw_chart (ctx, BYTES_TRANSMITTED_COLOR, False, chart_rect, \
474 [(sample.time, sample.transmitted_bytes) for sample in samples], \
475 proc_tree, None)
476
477 if clip_visible (clip, chart_rect):
478 draw_chart (ctx, BYTES_RECEIVE_DIFF_COLOR, True, chart_rect, \
479 [(sample.time, sample.receive_diff) for sample in samples], \
480 proc_tree, None)
481
482 draw_chart (ctx, BYTES_TRANSMIT_DIFF_COLOR, True, chart_rect, \
483 [(sample.time, sample.transmit_diff) for sample in samples], \
484 proc_tree, None)
485
486 curr_y = curr_y + 30 + bar_h
487
440 # render CPU pressure chart 488 # render CPU pressure chart
441 if trace.cpu_pressure: 489 if trace.cpu_pressure:
442 max_sample_avg = max (trace.cpu_pressure, key = lambda s: s.avg10) 490 max_sample_avg = max (trace.cpu_pressure, key = lambda s: s.avg10)
diff --git a/scripts/pybootchartgui/pybootchartgui/parsing.py b/scripts/pybootchartgui/pybootchartgui/parsing.py
index 144a16c723..72a54c6ba5 100644
--- a/scripts/pybootchartgui/pybootchartgui/parsing.py
+++ b/scripts/pybootchartgui/pybootchartgui/parsing.py
@@ -48,6 +48,7 @@ class Trace:
48 self.filename = None 48 self.filename = None
49 self.parent_map = None 49 self.parent_map = None
50 self.mem_stats = [] 50 self.mem_stats = []
51 self.net_stats = []
51 self.monitor_disk = None 52 self.monitor_disk = None
52 self.cpu_pressure = [] 53 self.cpu_pressure = []
53 self.io_pressure = [] 54 self.io_pressure = []
@@ -557,6 +558,21 @@ def _parse_monitor_disk_log(file):
557 558
558 return disk_stats 559 return disk_stats
559 560
561
562def _parse_reduced_net_log(file):
563 net_stats = {}
564 for time, lines in _parse_timed_blocks(file):
565
566 for line in lines:
567 parts = line.split()
568 iface = parts[0][:-1]
569 if iface not in net_stats:
570 net_stats[iface] = [NetSample(time, iface, int(parts[1]), int(parts[2]), int(parts[3]), int(parts[4]))]
571 else:
572 net_stats[iface].append(NetSample(time, iface, int(parts[1]), int(parts[2]), int(parts[3]), int(parts[4])))
573 return net_stats
574
575
560def _parse_pressure_logs(file, filename): 576def _parse_pressure_logs(file, filename):
561 """ 577 """
562 Parse file for "some" pressure with 'avg10', 'avg60' 'avg300' and delta total values 578 Parse file for "some" pressure with 'avg10', 'avg60' 'avg300' and delta total values
@@ -767,6 +783,8 @@ def _do_parse(writer, state, filename, file):
767 state.cmdline = _parse_cmdline_log(writer, file) 783 state.cmdline = _parse_cmdline_log(writer, file)
768 elif name == "monitor_disk.log": 784 elif name == "monitor_disk.log":
769 state.monitor_disk = _parse_monitor_disk_log(file) 785 state.monitor_disk = _parse_monitor_disk_log(file)
786 elif name == "reduced_proc_net.log":
787 state.net_stats = _parse_reduced_net_log(file)
770 #pressure logs are in a subdirectory 788 #pressure logs are in a subdirectory
771 elif name == "cpu.log": 789 elif name == "cpu.log":
772 state.cpu_pressure = _parse_pressure_logs(file, name) 790 state.cpu_pressure = _parse_pressure_logs(file, name)
diff --git a/scripts/pybootchartgui/pybootchartgui/samples.py b/scripts/pybootchartgui/pybootchartgui/samples.py
index a70d8a5a28..7c92d2ce6a 100644
--- a/scripts/pybootchartgui/pybootchartgui/samples.py
+++ b/scripts/pybootchartgui/pybootchartgui/samples.py
@@ -37,6 +37,16 @@ class CPUSample:
37 return str(self.time) + "\t" + str(self.user) + "\t" + \ 37 return str(self.time) + "\t" + str(self.user) + "\t" + \
38 str(self.sys) + "\t" + str(self.io) + "\t" + str (self.swap) 38 str(self.sys) + "\t" + str(self.io) + "\t" + str (self.swap)
39 39
40
41class NetSample:
42 def __init__(self, time, iface, received_bytes, transmitted_bytes, receive_diff, transmit_diff):
43 self.time = time
44 self.iface = iface
45 self.received_bytes = received_bytes
46 self.transmitted_bytes = transmitted_bytes
47 self.receive_diff = receive_diff
48 self.transmit_diff = transmit_diff
49
40class CPUPressureSample: 50class CPUPressureSample:
41 def __init__(self, time, avg10, avg60, avg300, deltaTotal): 51 def __init__(self, time, avg10, avg60, avg300, deltaTotal):
42 self.time = time 52 self.time = time