Skip to content

Commit 20ecb7a

Browse files
committed
FEC histogram with ability to clear stat
1 parent d7c16c3 commit 20ecb7a

File tree

3 files changed

+88
-8
lines changed

3 files changed

+88
-8
lines changed

doc/Command-Reference.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5656,6 +5656,34 @@ The "fec-stats" subcommand is used to disply the interface fec related statistic
56565656
Ethernet16 U 0 0 0 1.77e-20 0.00e+00 1.37e-13
56575657
```
56585658

5659+
For debugging link related issues where you need to clear the FEC histogram and monitor the link again, use the following command
5660+
5661+
- Example (for all ports):
5662+
```
5663+
root@sonic:~# portstat -fh
5664+
Last cached time was 2025-10-02T16:43:57.934081
5665+
IFACE BIN0 BIN1 BIN2 BIN3 BIN4 BIN5 BIN6 BIN7 BIN8 BIN9 BIN10 BIN11 BIN12 BIN13 BIN14 BIN15
5666+
----------- ------------- ---------- --------- ------ ------ ------ ------ ------ ------ ------ ------- ------- ------- ------- ------- -------
5667+
Ethernet0 4,374,661,575 340 1 0 0 0 0 0 0 0 0 0 0 0 0 0
5668+
Ethernet8 4,374,590,263 8,069 9 0 0 0 0 0 0 0 0 0 0 0 0 0
5669+
Ethernet16 4,374,660,911 3,187 4 0 0 0 0 0 0 0 0 0 0 0 0 0
5670+
Ethernet24 4,374,594,305 57,484 502 0 0 0 0 0 0 0 0 0 0 0 0 0
5671+
Ethernet32 4,374,649,615 116 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5672+
Ethernet40 4,374,650,913 1,212 1 0 0 0 0 0 0 0 0 0 0 0 0 0
5673+
```
5674+
5675+
- Example (for a particular port):
5676+
```
5677+
root@sonic:~# portstat -fh -i Ethernet504
5678+
Last cached time was 2025-10-02T16:43:57.934081
5679+
IFACE BIN0 BIN1 BIN2 BIN3 BIN4 BIN5 BIN6 BIN7 BIN8 BIN9 BIN10 BIN11 BIN12 BIN13 BIN14 BIN15
5680+
----------- ----------- ------ ------ ------ ------ ------ ------ ------ ------ ------ ------- ------- ------- ------- ------- -------
5681+
Ethernet504 624,891,017 13,331 172 0 0 0 0 0 0 0 0 0 0 0 0 0
5682+
root@str-7060x6-c09-u25:~#
5683+
```
5684+
5685+
To clear the FEC histogram use `portstat -c`. NOTE: This will clear all counters.
5686+
56595687
The "trim" subcommand is used to display the interface packet trimming related statistic.
56605688

56615689
- Example:

scripts/portstat

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Examples:
7070
parser.add_argument('-D', '--delete-all', action='store_true', help='Delete all saved stats')
7171
parser.add_argument('-e', '--errors', action='store_true', help='Display interface errors')
7272
parser.add_argument('-f', '--fec-stats', action='store_true', help='Display FEC related statistics')
73+
parser.add_argument('-fh', '--fec_hist', action='store_true', help='Display FEC histogram')
7374
parser.add_argument('-j', '--json', action='store_true', help='Display in JSON format')
7475
parser.add_argument('-r', '--raw', action='store_true', help='Raw stats (unmodified output of netstat)')
7576
parser.add_argument('-R', '--rate', action='store_true', help='Display interface rates')
@@ -89,6 +90,7 @@ Examples:
8990
delete_all_stats = args.delete_all
9091
errors_only = args.errors
9192
fec_stats_only = args.fec_stats
93+
fec_hist_only = args.fec_hist
9294
rates_only = args.rate
9395
use_json = args.json
9496
raw_stats = args.raw
@@ -127,8 +129,10 @@ Examples:
127129

128130
# Now decide what information to display
129131
if raw_stats:
130-
portstat.cnstat_diff_print(cnstat_dict, {}, ratestat_dict, intf_list, use_json, print_all, errors_only,
131-
fec_stats_only, rates_only, trim_stats_only)
132+
portstat.cnstat_diff_print(cnstat_dict, {}, ratestat_dict, intf_list,
133+
use_json, print_all, errors_only,
134+
fec_stats_only, rates_only,
135+
trim_stats_only, fec_hist_only)
132136
sys.exit(0)
133137

134138
if save_fresh_stats:
@@ -147,22 +151,30 @@ Examples:
147151
cnstat_cached_dict = json.load(open(cnstat_fqn_file, 'r'))
148152
if not detail:
149153
print("Last cached time was " + str(cnstat_cached_dict.get('time')))
150-
portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, trim_stats_only, detail, nonzero)
154+
portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, ratestat_dict,
155+
intf_list, use_json, print_all, errors_only,
156+
fec_stats_only, rates_only, trim_stats_only,
157+
fec_hist_only, detail, nonzero)
151158
except IOError as e:
152159
print(e.errno, e)
153160
else:
154161
if tag_name:
155162
print("\nFile '%s' does not exist" % cnstat_fqn_file)
156163
print("Did you run 'portstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name))
157164
else:
158-
portstat.cnstat_diff_print(cnstat_dict, {}, ratestat_dict, intf_list, use_json, print_all, errors_only,
159-
fec_stats_only, rates_only, trim_stats_only, detail, nonzero)
165+
portstat.cnstat_diff_print(cnstat_dict, {}, ratestat_dict, intf_list,
166+
use_json, print_all, errors_only,
167+
fec_stats_only, rates_only, trim_stats_only,
168+
fec_hist_only, detail, nonzero)
160169
else:
161170
#wait for the specified time and then gather the new stats and output the difference.
162171
time.sleep(wait_time_in_seconds)
163172
print("The rates are calculated within %s seconds period" % wait_time_in_seconds)
164173
cnstat_new_dict, ratestat_new_dict = portstat.get_cnstat_dict()
165-
portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, ratestat_new_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, trim_stats_only, detail, nonzero)
174+
portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, ratestat_new_dict,
175+
intf_list, use_json, print_all, errors_only,
176+
fec_stats_only, rates_only, trim_stats_only,
177+
fec_hist_only, detail, nonzero)
166178

167179
if __name__ == "__main__":
168180
main()

utilities_common/portstat.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,18 @@
2929
rx_jbr, rx_frag, rx_usize, rx_ovrrun,\
3030
fec_corr, fec_uncorr, fec_symbol_err,\
3131
wred_grn_drp_pkt, wred_ylw_drp_pkt, wred_red_drp_pkt, wred_tot_drp_pkt,\
32-
trim, trim_sent, trim_drop")
32+
trim, trim_sent, trim_drop, fec_bin0, fec_bin1, fec_bin2, fec_bin3,\
33+
fec_bin4, fec_bin5, fec_bin6, fec_bin7, fec_bin8, fec_bin9, fec_bin10,\
34+
fec_bin11, fec_bin12, fec_bin13, fec_bin14, fec_bin15")
3335
header_all = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'RX_ERR', 'RX_DRP', 'RX_OVR',
3436
'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_UTIL', 'TX_ERR', 'TX_DRP', 'TX_OVR', 'TRIM', 'TRIM_TX', 'TRIM_DRP']
3537
header_std = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_UTIL', 'RX_ERR', 'RX_DRP', 'RX_OVR',
3638
'TX_OK', 'TX_BPS', 'TX_UTIL', 'TX_ERR', 'TX_DRP', 'TX_OVR']
3739
header_errors_only = ['IFACE', 'STATE', 'RX_ERR', 'RX_DRP', 'RX_OVR', 'TX_ERR', 'TX_DRP', 'TX_OVR']
3840
header_fec_only = ['IFACE', 'STATE', 'FEC_CORR', 'FEC_UNCORR', 'FEC_SYMBOL_ERR', 'FEC_PRE_BER',
3941
'FEC_POST_BER', 'FEC_PRE_BER_MAX']
42+
header_fec_hist_only = ['IFACE', 'BIN0', 'BIN1', 'BIN2', 'BIN3', 'BIN4', 'BIN5', 'BIN6', 'BIN7',
43+
'BIN8', 'BIN9', 'BIN10', 'BIN11', 'BIN12', 'BIN13', 'BIN14', 'BIN15']
4044
header_rates_only = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_UTIL']
4145
header_trim_only = ['IFACE', 'STATE', 'TRIM_PKTS', 'TRIM_TX_PKTS', 'TRIM_DRP_PKTS']
4246

@@ -112,6 +116,22 @@
112116
49: ['SAI_PORT_STAT_TRIM_PACKETS'],
113117
50: ['SAI_PORT_STAT_TX_TRIM_PACKETS'],
114118
51: ['SAI_PORT_STAT_DROPPED_TRIM_PACKETS'],
119+
52: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S0'],
120+
53: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S1'],
121+
54: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S2'],
122+
55: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S3'],
123+
56: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S4'],
124+
57: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S5'],
125+
58: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S6'],
126+
59: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S7'],
127+
60: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S8'],
128+
61: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S9'],
129+
62: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S10'],
130+
63: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S11'],
131+
64: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S12'],
132+
65: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S13'],
133+
66: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S14'],
134+
67: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S15'],
115135
}
116136

117137
STATUS_NA = 'N/A'
@@ -550,7 +570,7 @@ def cnstat_intf_diff_print(self, cnstat_new_dict, cnstat_old_dict, intf_list):
550570
def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict,
551571
ratestat_dict, intf_list, use_json,
552572
print_all, errors_only, fec_stats_only,
553-
rates_only, trim_stats_only, detail=False, nonzero=False):
573+
rates_only, trim_stats_only, fec_hist_only, detail=False, nonzero=False):
554574
"""
555575
Print the difference between two cnstat results.
556576
"""
@@ -638,6 +658,26 @@ def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict,
638658
format_fec_ber(rates.fec_pre_ber),
639659
format_fec_ber(rates.fec_post_ber),
640660
format_fec_ber(rates.fec_pre_ber_max)))
661+
elif fec_hist_only:
662+
header = header_fec_hist_only
663+
664+
table.append((key, ns_diff(cntr['fec_bin0'], old_cntr['fec_bin0']),
665+
ns_diff(cntr['fec_bin1'], old_cntr['fec_bin1']),
666+
ns_diff(cntr['fec_bin2'], old_cntr['fec_bin2']),
667+
ns_diff(cntr['fec_bin3'], old_cntr['fec_bin3']),
668+
ns_diff(cntr['fec_bin4'], old_cntr['fec_bin4']),
669+
ns_diff(cntr['fec_bin5'], old_cntr['fec_bin5']),
670+
ns_diff(cntr['fec_bin6'], old_cntr['fec_bin6']),
671+
ns_diff(cntr['fec_bin7'], old_cntr['fec_bin7']),
672+
ns_diff(cntr['fec_bin8'], old_cntr['fec_bin8']),
673+
ns_diff(cntr['fec_bin9'], old_cntr['fec_bin9']),
674+
ns_diff(cntr['fec_bin10'], old_cntr['fec_bin10']),
675+
ns_diff(cntr['fec_bin11'], old_cntr['fec_bin11']),
676+
ns_diff(cntr['fec_bin12'], old_cntr['fec_bin12']),
677+
ns_diff(cntr['fec_bin13'], old_cntr['fec_bin13']),
678+
ns_diff(cntr['fec_bin14'], old_cntr['fec_bin14']),
679+
ns_diff(cntr['fec_bin15'], old_cntr['fec_bin15'])))
680+
641681
elif rates_only:
642682
header = header_rates_only
643683

0 commit comments

Comments
 (0)