Skip to content

Commit 46eb31a

Browse files
prgeormihirpat1
authored andcommitted
FEC histogram with ability to clear stat (sonic-net#4075)
1 parent 661ac61 commit 46eb31a

File tree

3 files changed

+76
-6
lines changed

3 files changed

+76
-6
lines changed

doc/Command-Reference.md

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

5271+
For debugging link related issues where you need to clear the FEC histogram and monitor the link again, use the following command
5272+
5273+
- Example (for all ports):
5274+
```
5275+
root@sonic:~# portstat -fh
5276+
Last cached time was 2025-10-02T16:43:57.934081
5277+
IFACE BIN0 BIN1 BIN2 BIN3 BIN4 BIN5 BIN6 BIN7 BIN8 BIN9 BIN10 BIN11 BIN12 BIN13 BIN14 BIN15
5278+
----------- ------------- ---------- --------- ------ ------ ------ ------ ------ ------ ------ ------- ------- ------- ------- ------- -------
5279+
Ethernet0 4,374,661,575 340 1 0 0 0 0 0 0 0 0 0 0 0 0 0
5280+
Ethernet8 4,374,590,263 8,069 9 0 0 0 0 0 0 0 0 0 0 0 0 0
5281+
Ethernet16 4,374,660,911 3,187 4 0 0 0 0 0 0 0 0 0 0 0 0 0
5282+
Ethernet24 4,374,594,305 57,484 502 0 0 0 0 0 0 0 0 0 0 0 0 0
5283+
Ethernet32 4,374,649,615 116 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5284+
Ethernet40 4,374,650,913 1,212 1 0 0 0 0 0 0 0 0 0 0 0 0 0
5285+
```
5286+
5287+
- Example (for a particular port):
5288+
```
5289+
root@sonic:~# portstat -fh -i Ethernet504
5290+
Last cached time was 2025-10-02T16:43:57.934081
5291+
IFACE BIN0 BIN1 BIN2 BIN3 BIN4 BIN5 BIN6 BIN7 BIN8 BIN9 BIN10 BIN11 BIN12 BIN13 BIN14 BIN15
5292+
----------- ----------- ------ ------ ------ ------ ------ ------ ------ ------ ------ ------- ------- ------- ------- ------- -------
5293+
Ethernet504 624,891,017 13,331 172 0 0 0 0 0 0 0 0 0 0 0 0 0
5294+
root@str-7060x6-c09-u25:~#
5295+
```
5296+
5297+
To clear the FEC histogram use `portstat -c`. NOTE: This will clear all counters.
5298+
52715299
The "trim" subcommand is used to display the interface packet trimming related statistic.
52725300

52735301
- Example:

scripts/portstat

Lines changed: 6 additions & 4 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')
@@ -88,6 +89,7 @@ Examples:
8889
delete_all_stats = args.delete_all
8990
errors_only = args.errors
9091
fec_stats_only = args.fec_stats
92+
fec_hist_only = args.fec_hist
9193
rates_only = args.rate
9294
use_json = args.json
9395
raw_stats = args.raw
@@ -125,7 +127,7 @@ Examples:
125127

126128
# Now decide what information to display
127129
if raw_stats:
128-
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, trim_stats_only)
130+
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, trim_stats_only, fec_hist_only)
129131
sys.exit(0)
130132

131133
if save_fresh_stats:
@@ -144,21 +146,21 @@ Examples:
144146
cnstat_cached_dict = json.load(open(cnstat_fqn_file, 'r'))
145147
if not detail:
146148
print("Last cached time was " + str(cnstat_cached_dict.get('time')))
147-
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)
149+
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, fec_hist_only, detail)
148150
except IOError as e:
149151
print(e.errno, e)
150152
else:
151153
if tag_name:
152154
print("\nFile '%s' does not exist" % cnstat_fqn_file)
153155
print("Did you run 'portstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name))
154156
else:
155-
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, trim_stats_only, detail)
157+
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, trim_stats_only, fec_hist_only, detail)
156158
else:
157159
#wait for the specified time and then gather the new stats and output the difference.
158160
time.sleep(wait_time_in_seconds)
159161
print("The rates are calculated within %s seconds period" % wait_time_in_seconds)
160162
cnstat_new_dict, ratestat_new_dict = portstat.get_cnstat_dict()
161-
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)
163+
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, fec_hist_only, detail)
162164

163165
if __name__ == "__main__":
164166
main()

utilities_common/portstat.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +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")
32+
trim, 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']
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', 'FEC_POST_BER']
41+
42+
header_fec_hist_only = ['IFACE', 'BIN0', 'BIN1', 'BIN2', 'BIN3', 'BIN4', 'BIN5', 'BIN6', 'BIN7',
43+
'BIN8', 'BIN9', 'BIN10', 'BIN11', 'BIN12', 'BIN13', 'BIN14', 'BIN15']
3944
header_rates_only = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_UTIL']
4045
header_trim_only = ['IFACE', 'STATE', 'TRIM_PKTS']
4146

@@ -109,6 +114,22 @@
109114
47: ['SAI_PORT_STAT_RED_WRED_DROPPED_PACKETS'],
110115
48: ['SAI_PORT_STAT_WRED_DROPPED_PACKETS'],
111116
49: ['SAI_PORT_STAT_TRIM_PACKETS'],
117+
52: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S0'],
118+
53: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S1'],
119+
54: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S2'],
120+
55: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S3'],
121+
56: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S4'],
122+
57: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S5'],
123+
58: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S6'],
124+
59: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S7'],
125+
60: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S8'],
126+
61: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S9'],
127+
62: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S10'],
128+
63: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S11'],
129+
64: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S12'],
130+
65: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S13'],
131+
66: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S14'],
132+
67: ['SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S15'],
112133
}
113134

114135
STATUS_NA = 'N/A'
@@ -619,7 +640,7 @@ def cnstat_intf_diff_print(self, cnstat_new_dict, cnstat_old_dict, intf_list):
619640
def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict,
620641
ratestat_dict, intf_list, use_json,
621642
print_all, errors_only, fec_stats_only,
622-
rates_only, trim_stats_only, detail=False):
643+
rates_only, trim_stats_only, fec_hist_only, detail=False):
623644
"""
624645
Print the difference between two cnstat results.
625646
"""
@@ -715,6 +736,25 @@ def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict,
715736
format_number_with_comma(cntr['fec_corr']),
716737
format_number_with_comma(cntr['fec_uncorr']),
717738
format_number_with_comma(cntr['fec_symbol_err'])))
739+
elif fec_hist_only:
740+
header = header_fec_hist_only
741+
742+
table.append((key, ns_diff(cntr['fec_bin0'], old_cntr['fec_bin0']),
743+
ns_diff(cntr['fec_bin1'], old_cntr['fec_bin1']),
744+
ns_diff(cntr['fec_bin2'], old_cntr['fec_bin2']),
745+
ns_diff(cntr['fec_bin3'], old_cntr['fec_bin3']),
746+
ns_diff(cntr['fec_bin4'], old_cntr['fec_bin4']),
747+
ns_diff(cntr['fec_bin5'], old_cntr['fec_bin5']),
748+
ns_diff(cntr['fec_bin6'], old_cntr['fec_bin6']),
749+
ns_diff(cntr['fec_bin7'], old_cntr['fec_bin7']),
750+
ns_diff(cntr['fec_bin8'], old_cntr['fec_bin8']),
751+
ns_diff(cntr['fec_bin9'], old_cntr['fec_bin9']),
752+
ns_diff(cntr['fec_bin10'], old_cntr['fec_bin10']),
753+
ns_diff(cntr['fec_bin11'], old_cntr['fec_bin11']),
754+
ns_diff(cntr['fec_bin12'], old_cntr['fec_bin12']),
755+
ns_diff(cntr['fec_bin13'], old_cntr['fec_bin13']),
756+
ns_diff(cntr['fec_bin14'], old_cntr['fec_bin14']),
757+
ns_diff(cntr['fec_bin15'], old_cntr['fec_bin15'])))
718758

719759
elif rates_only:
720760
header = header_rates_only

0 commit comments

Comments
 (0)