scripts: Add logic to normalize for negative latency.

This commit is contained in:
Ben Greear
2020-03-10 16:26:56 -07:00
parent 8505273a2e
commit 529ec8780f
3 changed files with 120 additions and 29 deletions

View File

@@ -137,13 +137,53 @@ sub normalize_bucket_hdr {
return $rv; return $rv;
} }
# Normalize lat1, taking peer latency (lat2) into account for negative latency and such.
sub normalize_latency {
my $self = shift;
my $lat1 = shift;
my $lat2 = shift;
#print "lat1 -:$lat1:-\n";
#print "lat2 -:$lat2:-\n";
my $min1 = 0;
my $min2 = 0;
# Looks like this: 5 -:5:- 6 [ 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] (1)
if ($lat1 =~ /(\S+)\s+-:(\S+):-\s+(\S+)\s+\[\s+(.*)\s+\]\s+\((\S+)\)/) {
$min1 = $1;
}
if ($lat2 =~ /(\S+)\s+-:(\S+):-\s+(\S+)\s+\[\s+(.*)\s+\]\s+\((\S+)\)/) {
$min2 = $1;
}
# For instance, min1 is -5, min2 is 25, rt-latency is 20.
# Adjust lat1 by (25 - -5) / 2
# For instance, min1 is 25, min2 is -5, rt-latency is 20.
# Adjust lat1 by (-5 -25) / 2
#print "min1: $min1 min2: $min2 half: " . int(($min2 - $min1) / 2) . "\n";
# So, the above seems nice, but often we have a small negative value due to
# clock drift in one direction, and large latency in the other (due to real one-way latency)
# So, we will just adjust enough to make the smallest value positive.
my $adjust = 0;
if ($min1 < 0) {
$adjust = -$min1;
}
elsif ($min2 < 0) {
$adjust = -$min2;
}
return $self->normalize_bucket($lat1, $adjust);
}
sub normalize_bucket { sub normalize_bucket {
my $self = shift; my $self = shift;
my $line = shift; my $line = shift;
my $adjust = shift;
#print "line -:$line:-\n"; #print "line -:$line:-\n";
# Looks like this: 5 -:5:- 6 [ 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] (1) # Looks like this: 5 -:5:- 6 [ 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] (1)
if ($line =~ /(\d+)\s+-:(\d+):-\s+(\d+)\s+\[\s+(.*)\s+\]\s+\((\d+)\)/) { if ($line =~ /(\S+)\s+-:(\S+):-\s+(\S+)\s+\[\s+(.*)\s+\]\s+\((\S+)\)/) {
my $min = $1; my $min = $1;
my $avg = $2; my $avg = $2;
my $max = $3; my $max = $3;
@@ -156,7 +196,7 @@ sub normalize_bucket {
my @bkts = split(/\s+/, $bks); my @bkts = split(/\s+/, $bks);
@bkts = (@bkts, "0"); @bkts = (@bkts, "0");
my $i; my $i;
my $rv = "$min $max $avg "; my $rv = ($min + $adjust) . " " . ($max + $adjust) . " " . ($avg + $adjust) . " ";
#print "bkts len: " . @bkts . "\n"; #print "bkts len: " . @bkts . "\n";
my @nbkts = (0) x (@bkts); my @nbkts = (0) x (@bkts);
for ($i = 0; $i<@bkts; $i++) { for ($i = 0; $i<@bkts; $i++) {
@@ -170,6 +210,10 @@ sub normalize_bucket {
$minv += $min; $minv += $min;
$maxv += $min; $maxv += $min;
# And adjust based on round-trip time to deal with clock lag
$minv += $adjust;
$maxv += $adjust;
# And now find the normalized bucket this fits in # And now find the normalized bucket this fits in
#print "maxv: $maxv\n"; #print "maxv: $maxv\n";
my $z; my $z;

View File

@@ -58,6 +58,8 @@ our $use_csums = "NO"; # Use LANforge checksums in payload?
our $ttl = 32; our $ttl = 32;
our $report_timer = 5000; our $report_timer = 5000;
our $tos = ""; our $tos = "";
our $lat1 = "";
our $lat2 = "";
our $arm_pps = ""; our $arm_pps = "";
our $arm_cpu_id = "NA"; our $arm_cpu_id = "NA";
# For cross connects # For cross connects
@@ -136,6 +138,8 @@ $0 [ --action {
Example: Example:
$0 --action set_endp --endp_name udp1-A --speed 154000 $0 --action set_endp --endp_name udp1-A --speed 154000
$0 --action normalize_latency --lat1 "latency-buckets info for endpA" --lat2 "latency-buckets-info for endpB"
$0 --action create_endp --endp_name mcast_xmit_1 --speed 154000 \\ $0 --action create_endp --endp_name mcast_xmit_1 --speed 154000 \\
--endp_type mc_udp --mcast_addr 224.9.9.8 --mcast_port 9998 \\ --endp_type mc_udp --mcast_addr 224.9.9.8 --mcast_port 9998 \\
--rcv_mcast NO --port_name eth1 \\ --rcv_mcast NO --port_name eth1 \\
@@ -233,6 +237,8 @@ GetOptions
'use_max_speeds=s' => \$::use_max_speeds, 'use_max_speeds=s' => \$::use_max_speeds,
'test_mgr=s' => \$::test_mgr, 'test_mgr=s' => \$::test_mgr,
'tos=s' => \$::tos, 'tos=s' => \$::tos,
'lat1=s' => \$::lat1,
'lat2=s' => \$::lat2,
) || die("$::usage"); ) || die("$::usage");
@@ -287,7 +293,7 @@ if ($::do_cmd ne "NA") {
$::action = "do_cmd"; $::action = "do_cmd";
} }
our @valid_actions = qw( our @valid_actions = qw(
create_arm create_cx create_endp create_arm create_cx create_endp normalize_latency
delete_cx delete_cxe delete_endp do_cmd delete_cx delete_cxe delete_endp do_cmd
list_cx list_endp list_ports list_cx list_endp list_ports
set_endp show_cx show_endp show_port start_endp stop_endp set_endp show_cx show_endp show_port start_endp stop_endp
@@ -321,10 +327,14 @@ if (!defined $::stats_from_file || ("" eq $::stats_from_file)) {
$::utils->connect($lfmgr_host, $lfmgr_port); $::utils->connect($lfmgr_host, $lfmgr_port);
} }
if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm,list_endp")) { if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm,list_endp,normalize_latency")) {
$::max_speed = $::speed if ($::max_speed eq "-1"); $::max_speed = $::speed if ($::max_speed eq "-1");
if ($::action eq "list_endp") { if ($::action eq "normalize_latency") {
my $val = $::utils->normalize_latency($::lat1, $::lat2);
print("Normalized-Latency: $val\n");
}
elsif ($::action eq "list_endp") {
$::utils->cli_rcv_silent(0); $::utils->cli_rcv_silent(0);
$::quiet = "no"; $::quiet = "no";
my @lines = split(/\r?\n/, $::utils->doAsyncCmd("nc_show_endpoints all")); my @lines = split(/\r?\n/, $::utils->doAsyncCmd("nc_show_endpoints all"));
@@ -408,7 +418,6 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
#print "val -:$val:-\n"; #print "val -:$val:-\n";
$option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17); $option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17);
$option_map{"Latency"} = $val; $option_map{"Latency"} = $val;
$option_map{"Latency-Normalized"} = $::utils->normalize_bucket($val);
} }
} }
elsif ($end_val =~ /Pkt-Gaps/) { elsif ($end_val =~ /Pkt-Gaps/) {
@@ -416,7 +425,6 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
my $val = $1; my $val = $1;
$option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17); $option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17);
$option_map{"Pkt-Gaps"} = $val; $option_map{"Pkt-Gaps"} = $val;
$option_map{"Pkt-Gaps-Normalized"} = $::utils->normalize_bucket($val);
} }
} }
elsif ($end_val =~ /RX-Silence/) { elsif ($end_val =~ /RX-Silence/) {
@@ -424,7 +432,6 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
my $val = $1; my $val = $1;
$option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17); $option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17);
$option_map{"RX-Silence"} = $val; $option_map{"RX-Silence"} = $val;
$option_map{"RX-Silence-Normalized"} = $::utils->normalize_bucket($val);
} }
} }
elsif ($end_val =~ /Cx Detected/) { elsif ($end_val =~ /Cx Detected/) {
@@ -456,7 +463,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
else { else {
$value = 0 + $parts[0]; $value = 0 + $parts[0];
} }
#print "\n B end_val[$end_val] option[$option] now ".$value."\n"; print "\n B end_val[$end_val] option[$option] now ".$value."\n";
$option_map{ $end_val } = $value; $option_map{ $end_val } = $value;
# For backwards compat with older logic # For backwards compat with older logic

View File

@@ -173,24 +173,29 @@ def main():
green_left.set_border(1) green_left.set_border(1)
worksheet.set_row(0, 45) # Set height worksheet.set_row(0, 45) # Set height
worksheet.set_column(0, 0, 10) # Set width
bucket_hdrs = "0-0 1-1 2-3 4-7 8-15 16-31 32-63 64-127 128-255 256-511 512-1023 1024-2047 2048-4095 4096-8191 8192-16383 16384-32767 32768-65535".split() bucket_hdrs = "0-0 1-1 2-3 4-7 8-15 16-31 32-63 64-127 128-255 256-511 512-1023 1024-2047 2048-4095 4096-8191 8192-16383 16384-32767 32768-65535".split()
col = 0 col = 0
row = 0 row = 0
worksheet.set_column(0, 35, 13) # Set width to 14 for all columns by default
worksheet.write(row, col, 'CX-Name', dblue_bold); col += 1 worksheet.write(row, col, 'CX-Name', dblue_bold); col += 1
worksheet.write(row, col, 'Station', dblue_bold); col += 1 worksheet.set_column(col, col, 15)
worksheet.write(row, col, 'Endp-Name', dblue_bold); col += 1
worksheet.set_column(col, col, 12)
worksheet.write(row, col, 'Port', dblue_bold); col += 1
worksheet.write(row, col, 'Protocol', dblue_bold); col += 1 worksheet.write(row, col, 'Protocol', dblue_bold); col += 1
worksheet.write(row, col, 'ToS', dblue_bold); col += 1 worksheet.write(row, col, 'ToS', dblue_bold); col += 1
worksheet.set_column(col, col, 20)
worksheet.write(row, col, 'AP BSSID', dblue_bold); col += 1 worksheet.write(row, col, 'AP BSSID', dblue_bold); col += 1
worksheet.write(row, col, 'Bandwidth', dblue_bold); col += 1 worksheet.write(row, col, 'Band\nwidth', dblue_bold); col += 1
worksheet.write(row, col, 'Mode', dblue_bold); col += 1 worksheet.write(row, col, 'Mode', dblue_bold); col += 1
worksheet.write(row, col, 'Last MCS\nRx', dblue_bold); col += 1 worksheet.write(row, col, 'Last MCS\nRx', dblue_bold); col += 1
worksheet.write(row, col, 'Combined\nRSSI', dpeach_bold); col += 1 worksheet.write(row, col, 'Combined\nRSSI', dpeach_bold); col += 1
worksheet.write(row, col, 'Endpoint\nOffered\nLoad', dblue_bold); col += 1 worksheet.write(row, col, 'Endpoint\nOffered\nLoad', dblue_bold); col += 1
worksheet.write(row, col, 'Endpoint\n\Rx\nThroughput', dblue_bold); col += 1 worksheet.write(row, col, 'Endpoint\nRx\nThroughput', dblue_bold); col += 1
worksheet.write(row, col, 'Cx\nOffered\nLoad', dblue_bold); col += 1 worksheet.write(row, col, 'Cx\nOffered\nLoad', dblue_bold); col += 1
worksheet.write(row, col, 'Cx\n\Rx\nThroughput', dblue_bold); col += 1 worksheet.write(row, col, 'Cx\nRx\nThroughput', dblue_bold); col += 1
worksheet.write(row, col, 'Avg\nLatency', dblue_bold); col += 1 worksheet.write(row, col, 'Avg\nLatency', dblue_bold); col += 1
worksheet.write(row, col, 'Min\nLatency', dblue_bold); col += 1 worksheet.write(row, col, 'Min\nLatency', dblue_bold); col += 1
worksheet.write(row, col, 'Max\nLatency', dblue_bold); col += 1 worksheet.write(row, col, 'Max\nLatency', dblue_bold); col += 1
@@ -376,11 +381,11 @@ def main():
results = [""] * 7 results = [""] * 7
endp_stats = subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--endp_vals", "tx_bps,rx_bps,Tx Bytes,Rx Bytes,Tx Pkts,Rx Pkts,Latency", endp_stats = subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--endp_vals", "tx_bps,rx_bps,Tx Bytes,Rx Bytes,Tx Pkts,Rx Pkts,Latency",
"--endp_name", ena], capture_output=True); "--endp_name", ename], capture_output=True);
pss = endp_stats.stdout.decode('utf-8', 'ignore'); pss = endp_stats.stdout.decode('utf-8', 'ignore');
for line in pss.splitlines(): for line in pss.splitlines():
print("probe-line: %s"%(line)) print("probe-line, endp: %s: %s"%(ename, line))
m = re.search('Rx Bytes:\s+(\d+)', line) m = re.search('Rx Bytes:\s+(\d+)', line)
if (m != None): if (m != None):
results[1] = int(m.group(1)) results[1] = int(m.group(1))
@@ -412,7 +417,7 @@ def main():
if (m != None): if (m != None):
results[5] = m.group(1) results[5] = m.group(1)
m = re.search('Latency-Normalized:\s+(.*)', line) m = re.search('Latency:\s+(.*)', line)
if (m != None): if (m != None):
results[6] = m.group(1) results[6] = m.group(1)
@@ -421,30 +426,65 @@ def main():
else: else:
resultsB = results.copy() resultsB = results.copy()
# Now that we know both latencies, we can normalize them.
endp_statsA = subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--action", "normalize_latency",
"--lat1", resultsA[6], "--lat2", resultsB[6]], capture_output=True);
pssA = endp_statsA.stdout.decode('utf-8', 'ignore');
endp_statsB = subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--action", "normalize_latency",
"--lat1", resultsB[6], "--lat2", resultsA[6]], capture_output=True);
pssB = endp_statsB.stdout.decode('utf-8', 'ignore');
print("latA: %s"%resultsA[6])
print("latB: %s"%resultsB[6])
print("pssA: %s"%pssA)
print("pssB: %s"%pssB)
for line in pssA.splitlines():
m = re.search('Normalized-Latency:\s+(.*)', line)
if (m != None):
resultsA[6] = m.group(1);
for line in pssB.splitlines():
m = re.search('Normalized-Latency:\s+(.*)', line)
if (m != None):
resultsB[6] = m.group(1);
for ename in enames: for ename in enames:
col = 0 col = 0
if (ena == ename): if (ena == ename):
results = resultsA results = resultsA.copy()
else: else:
results = resultsB results = resultsB.copy()
lat_cols = results[6].split() # min, max, avg, columns.... lat_cols = results[6].split() # min, max, avg, columns....
worksheet.write(row, col, cxn, center_blue); col += 1 worksheet.write(row, col, cxn, center_blue); col += 1
worksheet.write(row, col, ename, center_blue); col += 1 worksheet.write(row, col, ename, center_blue); col += 1
if ename == ena:
worksheet.write(row, col, "%s.%s"%(sta_resource, sta_name), center_blue); col += 1 worksheet.write(row, col, "%s.%s"%(sta_resource, sta_name), center_blue); col += 1
else:
worksheet.write(row, col, "%s.%s"%(u_resource, u_name), center_blue); col += 1
worksheet.write(row, col, proto, center_blue); col += 1 worksheet.write(row, col, proto, center_blue); col += 1
worksheet.write(row, col, tos, center_blue); col += 1 worksheet.write(row, col, tos, center_blue); col += 1
if ename == ena:
worksheet.write(row, col, _ap, center_blue); col += 1 worksheet.write(row, col, _ap, center_blue); col += 1
worksheet.write(row, col, _bw, center_blue); col += 1 worksheet.write(row, col, _bw, center_blue); col += 1
worksheet.write(row, col, _mode, center_blue); col += 1 worksheet.write(row, col, _mode, center_blue); col += 1
worksheet.write(row, col, _rxrate, center_blue); col += 1 worksheet.write(row, col, _rxrate, center_blue); col += 1
worksheet.write(row, col, _signal, center_blue); col += 1 worksheet.write(row, col, _signal, center_blue); col += 1
worksheet.write(row, col, results[2], center_blue); col += 1 else:
worksheet.write(row, col, results[3], center_tan); col += 1 # Upstream is likely wired, don't print station info
worksheet.write(row, col, "%s"%(int(resultsA[2]) + int(resultsB[2])), center_blue); col += 1 worksheet.write(row, col, "", center_blue); col += 1
worksheet.write(row, col, "%s"%(int(resultsA[3]) + int(resultsB[3])), center_tan); col += 1 worksheet.write(row, col, "", center_blue); col += 1
worksheet.write(row, col, "", center_blue); col += 1
worksheet.write(row, col, "", center_blue); col += 1
worksheet.write(row, col, "", center_blue); col += 1
worksheet.write(row, col, float(results[2]) / 1000000, center_blue); col += 1
worksheet.write(row, col, float(results[3]) / 1000000, center_tan); col += 1
worksheet.write(row, col, "%s"%((float(resultsA[2]) + float(resultsB[2])) / 1000000), center_blue); col += 1
worksheet.write(row, col, "%s"%((float(resultsA[3]) + float(resultsB[3])) / 1000000), center_tan); col += 1
worksheet.write(row, col, lat_cols[2], center_tan); col += 1 worksheet.write(row, col, lat_cols[2], center_tan); col += 1
worksheet.write(row, col, lat_cols[0], center_tan); col += 1 worksheet.write(row, col, lat_cols[0], center_tan); col += 1
worksheet.write(row, col, lat_cols[1], center_tan); col += 1 worksheet.write(row, col, lat_cols[1], center_tan); col += 1