def __init__(self, nrange): """Construct a range from a JSON NumericRange.""" # TODO: Would be nice if this class could treat missing # lower/upper as -/+ infinity. # TODO: Figure out why this can't just point to a NumericRange valid, message = pscheduler.json_validate(nrange, { "type": "object", "properties": { "lower": { "$ref": "#/pScheduler/Numeric" }, "upper": { "$ref": "#/pScheduler/Numeric" } }, "additionalProperties": False, "required": [ "lower", "upper" ] }) if not valid: raise ValueError("Invalid numeric range: %s" % message) lower = nrange['lower'] if type(lower) in [ str, unicode ]: self.lower = pscheduler.si_as_number(lower) else: self.lower = lower self.lower_str = str(lower) upper = nrange['upper'] if type(upper) in [ str, unicode ]: self.upper = pscheduler.si_as_number(upper) else: self.upper = upper self.upper_str = str(upper)
def __init__(self, nrange): """Construct a range from a JSON NumericRange.""" # TODO: Would be nice if this class could treat missing # lower/upper as -/+ infinity. # TODO: Figure out why this can't just point to a NumericRange valid, message = pscheduler.json_validate(nrange, { "type": "object", "properties": { "lower": {"$ref": "#/pScheduler/Numeric"}, "upper": {"$ref": "#/pScheduler/Numeric"} }, "additionalProperties": False, "required": ["lower", "upper"] }) if not valid: raise ValueError("Invalid numeric range: %s" % message) lower = nrange['lower'] if type(lower) in [str, unicode]: self.lower = pscheduler.si_as_number(lower) else: self.lower = lower self.lower_str = str(lower) upper = nrange['upper'] if type(upper) in [str, unicode]: self.upper = pscheduler.si_as_number(upper) else: self.upper = upper self.upper_str = str(upper)
def __contains__(self, number): """See if the range contains the specified number, which can be any Numeric.""" if type(number) == float: test_value = number else: test_value = pscheduler.si_as_number(number) return self.lower <= test_value <= self.upper
def parse_output(lines): results = {} results['succeeded'] = True seen_header = False streams = {} dest_ip = None dest_port = None src_ip = None src_port = None for line in lines: # ignore bogus sessions if re.match('\(nan%\)', line): results["succeeded"] = False results["error"] = "Found NaN result" break if re.match('read failed: Connection refused', line): results["succeeded"] = False results["error"] = "Connection refused" break test = re.match( 'local ([^ ]+) port (\d+) connected with ([^ ]+) port (\d+)', line) if test: dest_ip = test.group(1) dest_port = test.group(2) src_ip = test.group(3) src_port = test.group(4) # Example lines # TCP window size: 244 KByte (WARNING: requested 64.0 MByte) # TCP window size: 19800 Byte (default) test = re.match( 'TCP window size:\s+(\d+(\.\d+)?) (\S)?Byte(.*\(WARNING:\s+requested\s+(\d+(\.\d+)?) (\S)?Byte)?', line) if test: window_size = test.group(1) window_si = test.group(3) request_size = test.group(5) request_si = test.group(7) if window_si: window_size = pscheduler.si_as_number("%s%s" % (window_size, window_si)) if request_size: if request_si: request_size = pscheduler.si_as_number( "%s%s" % (request_size, request_si)) results["requested-tcp-window-size"] = int(request_size) results["tcp-window-size"] = int(window_size) # Example line # [ 3] MSS size 1448 bytes (MTU 1500 bytes, ethernet) test = re.match('.*MSS size (\d+) bytes \(MTU (\d+) bytes', line) if test: results['mss'] = int(test.group(1)) results['mtu'] = int(test.group(2)) stream_id = None interval_start = None throughput_bytes = None si_bytes = None throughput_bits = None si_bits = None jitter = None lost = None sent = None # Example line # [ 3] 16.0-17.0 sec 37355520 Bytes 298844160 bits/sec test = re.match( '\[\s*(\d+|SUM)\s*\]\s+([0-9\.]+)\s*\-\s*([0-9\.]+)\s+sec\s+(\d+(\.\d+)?)\s+(P|T|G|M|K)?Bytes\s+(\d+(\.\d+)?)\s+(P|T|G|M|K)?bits\/sec(\s+([0-9\.]+)\s+ms\s+(\d+)\/\s*(\d+)\s+)?', line) if test: stream_id = test.group(1) interval_start = float(test.group(2)) interval_end = float(test.group(3)) throughput_bytes = float(test.group(4)) si_bytes = test.group(6) throughput_bits = float(test.group(7)) si_bits = test.group(9) # these may or may not be present depending on versions jitter = test.group(11) lost = test.group(12) send = test.group(13) # If the output was in say GBytes convert back to regular Bytes for ease # of things later if si_bytes: throughput_bytes = pscheduler.si_as_number( "%s%s" % (throughput_bytes, si_bytes)) if si_bits: throughput_bits = pscheduler.si_as_number( "%s%s" % (throughput_bits, si_bits)) # if we found a matching line, we can add this info to our streams if stream_id: key = "%s-%s" % (interval_start, interval_end) # TODO: This would appear to not create a summary when the # duration is very short. # there has to be a better way than this... if interval_end - interval_start > 5: key = "summary" if key not in streams: streams[key] = [] streams[key].append({ "jitter": jitter, "lost": lost, "sent": sent, "throughput-bits": throughput_bits, "throughput-bytes": throughput_bytes, "start": interval_start, "end": interval_end, "stream-id": stream_id }) if not streams: results["succeeded"] = False results["error"] = "No results found" return results summary_interval = None intervals = [] for interval in streams: summary_stream = None interval_streams = [] # try to find the SUM if possible for stream in streams[interval]: if stream['stream-id'] == "SUM": summary_stream = stream else: interval_streams.append(stream) # if we couldn't find it, there was probably # just the one line so use that if not summary_stream and len(interval_streams) == 1: summary_stream = interval_streams[0] finalized = {"streams": interval_streams, "summary": summary_stream} if interval == "summary": summary_interval = finalized else: intervals.append(finalized) logger.debug(intervals) # sort according to start interval intervals.sort(key=lambda x: x['summary']['start']) results["intervals"] = intervals results["summary"] = summary_interval return results
def parse_output(lines): results = {} results['succeeded'] = True intervals = [] summary_view = {} current_interval_start = 0 for line in lines: # Example line: # 216.8125 MB / 1.00 sec = 1817.8571 Mbps 45 retrans 206 KB-cwnd test = re.match( '^.* (\d+)\.\d+ sec \=\s*(\d+(\.\d+)?) (\S)bps\s*(\d+) retrans(\s*(\d+)\s*(\S)\S\-cwnd)?', line) if test: spacing = int(test.group(1)) value = test.group(2) si = test.group(4) retrans = int(test.group(5)) cwnd = test.group(7) cwnd_si = test.group(8) value = pscheduler.si_as_number("%s%s" % (value, si)) cwnd = pscheduler.si_as_number("%s%s" % (cwnd, cwnd_si)) data = { "start": current_interval_start, "end": current_interval_start + spacing, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "tcp-window-size": cwnd, "retransmits": retrans } # since it doesn't report 1-2, 3-4, etc we have to keep track of where we are ourselves current_interval_start += spacing # in nuttcp there's only ever one reported and it's the summary so # just double it up intervals.append({"summary": data, "streams": [data]}) # Example UDP line # 25.1572 MB / 1.00 sec = 211.0065 Mbps 62 / 25823 ~drop/pkt 0.24 ~%loss 4.8672 msMaxJitter test = re.match( '^.* (\d+)\.\d+ sec \=\s*(\d+(\.\d+)?) (\S)bps\s*(\d+) / (\d+) ~drop/pkt\s*(\d+\.\d+) ~%loss\s*(\d+\.\d+) msMaxJitter', line) if test: spacing = int(test.group(1)) value = test.group(2) si = test.group(4) lost = int(test.group(5)) sent = int(test.group(6)) loss = test.group(7) jitter = float(test.group(8)) value = pscheduler.si_as_number("%s%s" % (value, si)) data = { "start": current_interval_start, "end": current_interval_start + spacing, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "sent": sent, "lost": lost, "jitter": jitter } # since it doesn't report 1-2, 3-4, etc we have to keep track of where we are ourselves current_interval_start += spacing # in nuttcp there's only ever one reported and it's the summary so # just double it up intervals.append({"summary": data, "streams": [data]}) # Example summary line: # 2197.0657 MB / 10.00 sec = 1842.3790 Mbps 8 %TX 90 %RX 90 retrans 237 KB-cwnd 0.50 msRTT test = re.match( '^.* (\d+)\.\d+ sec =\s*(\d+(\.\d+)?) (\S)bps \d+ %TX \d+ %RX (\d+) retrans(\s*(\d+)\s*(\S)\S\-cwnd)?', line) if test: duration = int(test.group(1)) value = test.group(2) si = test.group(4) retrans = int(test.group(5)) cwnd = test.group(7) cwnd_si = test.group(8) value = pscheduler.si_as_number("%s%s" % (value, si)) cwnd = pscheduler.si_as_number("%s%s" % (cwnd, cwnd_si)) summary_view = { "start": 0, "end": duration, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "tcp-window-size": cwnd, "retransmits": retrans } # Example UDP summary line # 252.0586 MB / 10.00 sec = 211.4462 Mbps 99 %TX 50 %RX 1485 / 259593 drop/pkt 0.57 %loss 37.2012 msMaxJitter test = re.match( '^.* (\d+)\.\d+ sec \=\s*(\d+(\.\d+)?) (\S)bps\s*(\d+) %TX (\d+) %RX (\d+) / (\d+) drop/pkt\s*(\d+\.\d+) %loss\s*(\d+\.\d+) msMaxJitter', line) if test: duration = int(test.group(1)) value = test.group(2) si = test.group(4) lost = int(test.group(7)) sent = int(test.group(8)) loss = test.group(9) jitter = float(test.group(10)) value = pscheduler.si_as_number("%s%s" % (value, si)) summary_view = { "start": 0, "end": duration, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "sent": sent, "lost": lost, "jitter": jitter } results["intervals"] = intervals results["summary"] = {"summary": summary_view, "streams": [summary_view]} return results
def parse_output(lines): results = {} results['succeeded'] = True intervals = [] summary_view = {} current_interval_start = 0 for line in lines: # Example line: # 216.8125 MB / 1.00 sec = 1817.8571 Mbps 45 retrans 206 KB-cwnd test = re.match('^.*(\d+)\.\d+ sec \=\s*(\d+(\.\d+)?) (\S)bps\s*(\d+) retrans(\s*(\d+)\s*(\S)\S\-cwnd)?', line) if test: spacing = int(test.group(1)) value = test.group(2) si = test.group(4) retrans = int(test.group(5)) cwnd = test.group(7) cwnd_si = test.group(8) value = pscheduler.si_as_number("%s%s" % (value, si)) cwnd = pscheduler.si_as_number("%s%s" % (cwnd, cwnd_si)) data = { "start": current_interval_start, "end": current_interval_start + spacing, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "tcp-window-size": cwnd, "retransmits": retrans } # since it doesn't report 1-2, 3-4, etc we have to keep track of where we are ourselves current_interval_start += spacing # in nuttcp there's only ever one reported and it's the summary so # just double it up intervals.append({"summary": data, "streams": [data]}) # Example UDP line # 25.1572 MB / 1.00 sec = 211.0065 Mbps 62 / 25823 ~drop/pkt 0.24 ~%loss 4.8672 msMaxJitter test = re.match('^.*(\d+)\.\d+ sec \=\s*(\d+(\.\d+)?) (\S)bps\s*(\d+) / (\d+) ~drop/pkt\s*(\d+\.\d+) ~%loss\s*(\d+\.\d+) msMaxJitter', line) if test: spacing = int(test.group(1)) value = test.group(2) si = test.group(4) lost = int(test.group(5)) sent = int(test.group(6)) loss = test.group(7) jitter = float(test.group(8)) value = pscheduler.si_as_number("%s%s" % (value, si)) data = { "start": current_interval_start, "end": current_interval_start + spacing, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "sent": sent, "lost": lost, "jitter": jitter } # since it doesn't report 1-2, 3-4, etc we have to keep track of where we are ourselves current_interval_start += spacing # in nuttcp there's only ever one reported and it's the summary so # just double it up intervals.append({"summary": data, "streams": [data]}) # Example summary line: # 2197.0657 MB / 10.00 sec = 1842.3790 Mbps 8 %TX 90 %RX 90 retrans 237 KB-cwnd 0.50 msRTT test = re.match('^.*(\d+)\.\d+ sec = (\d+(\.\d+)?) (\S)bps \d+ %TX \d+ %RX (\d+) retrans(\s*(\d+)\s*(\S)\S\-cwnd)?', line) if test: duration = int(test.group(1)) value = test.group(2) si = test.group(4) retrans = int(test.group(5)) cwnd = test.group(7) cwnd_si = test.group(8) value = pscheduler.si_as_number("%s%s" % (value, si)) cwnd = pscheduler.si_as_number("%s%s" % (cwnd, cwnd_si)) summary_view = { "start": 0, "end": duration, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "tcp-window-size": cwnd, "retransmits": retrans } # Example UDP summary line # 252.0586 MB / 10.00 sec = 211.4462 Mbps 99 %TX 50 %RX 1485 / 259593 drop/pkt 0.57 %loss 37.2012 msMaxJitter test = re.match('^.*(\d+)\.\d+ sec \=\s*(\d+(\.\d+)?) (\S)bps\s*(\d+) %TX (\d+) %RX (\d+) / (\d+) drop/pkt\s*(\d+\.\d+) %loss\s*(\d+\.\d+) msMaxJitter', line) if test: duration = int(test.group(1)) value = test.group(2) si = test.group(4) lost = int(test.group(5)) sent = int(test.group(6)) loss = test.group(7) jitter = float(test.group(8)) value = pscheduler.si_as_number("%s%s" % (value, si)) summary_view = { "start": 0, "end": duration, "stream-id": 1, # nuttcp won't report separate streams as best as I can tell, so just fudge it "throughput-bits": value, "sent": sent, "lost": lost, "jitter": jitter } results["intervals"] = intervals results["summary"] = {"summary": summary_view, "streams": [summary_view]} return results
def parse_output(lines): results = {} results['succeeded'] = True seen_header = False streams = {} dest_ip = None dest_port = None src_ip = None src_port = None for line in lines: # ignore bogus sessions if re.match('\(nan%\)', line): results["succeeded"] = False results["error"] = "Found NaN result"; break; if re.match('read failed: Connection refused', line): results["succeeded"] = False results["error"] = "Connection refused" break test = re.match('local ([^ ]+) port (\d+) connected with ([^ ]+) port (\d+)', line) if test: dest_ip = test.group(1) dest_port = test.group(2) src_ip = test.group(3) src_port = test.group(4) # Example lines # TCP window size: 244 KByte (WARNING: requested 64.0 MByte) # TCP window size: 19800 Byte (default) test = re.match('TCP window size:\s+(\d+(\.\d+)?) (\S)?Byte(.*\(WARNING:\s+requested\s+(\d+(\.\d+)?) (\S)?Byte)?', line) if test: window_size = test.group(1) window_si = test.group(3) request_size = test.group(5) request_si = test.group(7) if window_si: window_size = pscheduler.si_as_number("%s%s" % (window_size, window_si)) if request_size: if request_si: request_size = pscheduler.si_as_number("%s%s" % (request_size, request_si)) results["requested-tcp-window-size"] = int(request_size) results["tcp-window-size"] = int(window_size) # Example line # [ 3] MSS size 1448 bytes (MTU 1500 bytes, ethernet) test = re.match('.*MSS size (\d+) bytes \(MTU (\d+) bytes', line) if test: results['mss'] = int(test.group(1)) results['mtu'] = int(test.group(2)) stream_id = None interval_start = None throughput_bytes = None si_bytes = None throughput_bits = None si_bits = None jitter = None lost = None sent = None # Example line # [ 3] 16.0-17.0 sec 37355520 Bytes 298844160 bits/sec test = re.match('\[\s*(\d+|SUM)\s*\]\s+([0-9\.]+)\s*\-\s*([0-9\.]+)\s+sec\s+(\d+(\.\d+)?)\s+(P|T|G|M|K)?Bytes\s+(\d+(\.\d+)?)\s+(P|T|G|M|K)?bits\/sec(\s+([0-9\.]+)\s+ms\s+(\d+)\/\s*(\d+)\s+)?', line) if test: stream_id = test.group(1) interval_start = float(test.group(2)) interval_end = float(test.group(3)) throughput_bytes = float(test.group(4)) si_bytes = test.group(6) throughput_bits = float(test.group(7)) si_bits = test.group(9) # these may or may not be present depending on versions jitter = test.group(11) lost = test.group(12) send = test.group(13) # If the output was in say GBytes convert back to regular Bytes for ease # of things later if si_bytes: throughput_bytes = pscheduler.si_as_number("%s%s" % (throughput_bytes, si_bytes)) if si_bits: throughput_bits = pscheduler.si_as_number("%s%s" % (throughput_bits, si_bits)) # if we found a matching line, we can add this info to our streams if stream_id: key = "%s-%s" % (interval_start, interval_end) # there has to be a better way than this... if interval_end - interval_start > 5: key = "summary" if not streams.has_key(key): streams[key] = [] streams[key].append({"jitter": jitter, "lost": lost, "sent": sent, "throughput-bits": throughput_bits, "throughput-bytes": throughput_bytes, "start": interval_start, "end": interval_end, "stream-id": stream_id}) if len(streams.keys()) == 0: results["succeeded"] = False results["error"] = "No results found" return results summary_interval = None intervals = [] for interval in streams.keys(): summary_stream = None interval_streams = [] # try to find the SUM if possible for stream in streams[interval]: if stream['stream-id'] == "SUM": summary_stream = stream else: interval_streams.append(stream) # if we couldn't find it, there was probably # just the one line so use that if not summary_stream and len(interval_streams) == 1: summary_stream = interval_streams[0] finalized = { "streams": interval_streams, "summary": summary_stream } if interval == "summary": summary_interval = finalized else: intervals.append(finalized) logger.debug(intervals) # sort according to start interval intervals.sort(key = lambda x: x['summary']['start']) results["intervals"] = intervals results["summary"] = summary_interval return results