diff options
Diffstat (limited to 'VNFs/DPPD-PROX/helper-scripts/dpi')
22 files changed, 2501 insertions, 0 deletions
diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/README b/VNFs/DPPD-PROX/helper-scripts/dpi/README new file mode 100644 index 00000000..f1100757 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/README @@ -0,0 +1,41 @@ +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +The scripts in this directory characterize flow a DPI-enabled VNF. The +characeterization is split up into two steps. The first step (dpi1.py) +searches for the traffic profile parameter boundaries. The second step +(dpi2.py) takes as input the output of the first step and searches for +the maximum sustainable throughput of a DPI-enabled VNF. + +To run the first script, use: + + python2.7 ./dpi1.py -t TEST_SYSTEM_DESCRIPTIONS -o OUTPUT1 + +TEST_SYSTEM_DESCRIPTIONS is a comma-separated list of systems where +the syntax of defining each system is shown below: + + user@ip:proxDir:cfgDir + +To run the second script, use: + + python2.7 ./dpi2.py -t TEST_SYSTEM_DESCRIPTIONS \ + -s SYSTEM_UNDER_TEST_DESCRIPTIONS \ + -o OUTPUT2 -d \ + -i OUTPUT1 + +Finally, the results can be processed using the following command: + + python2.7 ./maketable.py -i OUTPUT1 -j OUTPUT2 -o FINAL_TABLE diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/config.py b/VNFs/DPPD-PROX/helper-scripts/dpi/config.py new file mode 100644 index 00000000..ee3f04c6 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/config.py @@ -0,0 +1,178 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +import getopt +import sys +from systemconfig import * + +class Config: + _debug = False; + _test_systems = []; + _output_file_name = None; + _input_file_name = None + _input_file_name2 = None + _max_port_rate = 0.85 + _sut = None + _accuracy = 2; + _threshold = 0.95 + _once = None + _skipTime = 10 + _testLength = 120 + _dpiCoreList = range(1, 5) + _checkConditions = False; + _interCheckDuration = float(1) + + def getInputFileName(self): + return self._input_file_name + + def getInputFileName2(self): + return self._input_file_name2 + + def toString(self): + ret = "" + ret += "Test systems: \n" + for ts in self._test_systems: + ret += ts.toString(); + + if (self._sut is not None): + ret += "SUT: \n" + ret += self._sut.toString(); + + ret += "Output file name: " + str(self._output_file_name) + "\n" + ret += "Max port rate: " + str(self._max_port_rate) + "\n" + ret += "Accuracy: " + str(self._accuracy) + " digits after point" + return ret + + def getErrorTestOne(self): + if (len(self._test_systems) == 0): + return "Missing test systems"; + if (self._output_file_name is None): + return "No output file or input file defined"; + return None + + def getErrorTestTwo(self): + if (self._input_file_name is None): + return "Input file is missing" + if (self._input_file_name == self._output_file_name): + return "Input file and output file are the same" + return self.getErrorTestOne(); + + def getErrorMakeTable(self): + if (self._input_file_name is None): + return "Missing input file" + if (self._input_file_name2 is None): + return "Missing file with performance resuilts" + if (self._output_file_name is None): + return "No output file or input file defined"; + if (self._input_file_name2 == self._input_file_name): + return "Input file used multiple times" + if (self._input_file_name == self._output_file_name): + return "output file is the same as the input file" + if (self._input_file_name2 == self._output_file_name): + return "output file is the same as the input file 2" + + return None + + def usageAndExit(self, argv0): + print "Usage: " + str(argv0) + print "-t Add a test system, syntax: " + SystemConfig.expectedSyntax() + print "-s Add SUT, syntax: " + SystemConfig.expectedSyntax() + print "-o Ouput file name" + print "-a Accuracy, number of digits after point" + print "-i Input file" + print "-j File with performance results" + print "-m Maximum per port rate, by default 0.85 (85%)" + print "-d Enable debugging" + print "-w Fraction of connections to reach, by default is 0.95 (95%)" + print "-h Show help" + print "-q Run a single test iteration, syntax of argument " + print "-b Skip time, by default 10 sec" + print "-l Test length, by default 120 sec" + print "-n Maximum number of DPI cores to test" + print "-k Period between checking conditions, 1 second by default" + print "-c Check conditions during 10 second period after convergence" + print " is msr,conn,ss (i.e. -q 4000,100000,38.91)" + exit(-1); + + def parse(self, programName, args): + try: + opts, args = getopt.getopt(args, "t:s:o:a:i:q:m:dhw:j:b:l:n:k:c") + except getopt.GetoptError as err: + print str(err) + return; + for option, arg in opts: + if(option == "-t"): + for ts in arg.split(","): + syntaxErr = SystemConfig.checkSyntax(ts) + if (syntaxErr != ""): + print syntaxErr + exit(-1); + self._test_systems.append(SystemConfig(ts)); + elif(option == "-s"): + syntaxErr = SystemConfig.checkSyntax(ts) + if (syntaxErr != ""): + print syntaxErr + exit(-1); + self._sut = SystemConfig(arg); + elif(option == "-w"): + self._threshold = float(arg) + elif(option == "-o"): + self._output_file_name = arg; + elif(option == '-a'): + self._accuracy = int(arg); + elif(option == "-i"): + self._input_file_name = arg; + elif(option == "-j"): + self._input_file_name2 = arg; + elif(option == "-q"): + self._once = arg.split(",") + elif(option == "-c"): + self._checkConditions = True; + elif(option == "-m"): + self._max_port_rate = float(arg); + elif(option == "-k"): + self._interCheckDuration = float(arg); + elif(option == "-d"): + self._debug = True + elif(option == '-h'): + self.usageAndExit(programName) + elif(option == '-b'): + self._skipTime = int(arg) + elif(option == '-l'): + self._testLength = int(arg) + elif(option == '-n'): + self._dpiCoreList = self.strToList(arg) + else: + self.usageAndExit(programName); + + def strToList(self, arg): + elements = []; + tokens = arg.split(","); + + for a in tokens: + if (a.count('-') == 0): + elements.append(int(a)) + elif (a.count('-') == 1): + beg = int(a.split('-')[0]); + end = int(a.split('-')[1]); + if (beg > end): + raise Exception("Invalid list input format") + elements += range(beg, end + 1); + else: + raise Exception("Invalid list input format") + return elements; diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/csvreader.py b/VNFs/DPPD-PROX/helper-scripts/dpi/csvreader.py new file mode 100644 index 00000000..b0b650dc --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/csvreader.py @@ -0,0 +1,78 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from decimal import * + +class CsvReaderError: + def __init__(self, msg): + self._msg = msg; + + def __str__(self): + return self._msg; + +class CsvReader: + def __init__(self, fieldTypes = None): + self._file_name = None; + self._fieldTypes = fieldTypes; + + def open(self, file_name): + self._file = open(file_name, 'r'); + self._file_name = file_name; + + def read(self): + line = "#" + while (len(line) != 0 and line[0] == "#"): + line = self._file.readline(); + + if (len(line) != 0): + return self._lineToEntry(line) + else: + return None; + + def _lineToEntry(self, line): + split = line.strip().split(','); + if (self._fieldTypes is None): + return split; + have = len(split) + expected = len(self._fieldTypes) + if (have != expected): + raise CsvReaderError("Invalid number of fields %d != %d" % (have, expected)) + + entry = {}; + for i in range(len(self._fieldTypes)): + curFieldType = self._fieldTypes[i][1] + curFieldName = self._fieldTypes[i][0]; + if (curFieldType == "int"): + entry[curFieldName] = int(split[i]) + elif (curFieldType == "Decimal"): + entry[curFieldName] = Decimal(split[i]) + else: + raise CsvReaderError("Invalid field type %s" % curFieldType); + return entry; + + def readAll(self): + ret = [] + line = self.read(); + while (line != None): + ret.append(line); + line = self.read(); + return ret; + + def close(self): + self._file.close(); + self._file = None; diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/csvwriter.py b/VNFs/DPPD-PROX/helper-scripts/dpi/csvwriter.py new file mode 100644 index 00000000..a5f055e8 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/csvwriter.py @@ -0,0 +1,35 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +class CsvWriter: + def __init__(self): + self._file_name = None; + + def open(self, file_name): + self._file = open(file_name, 'w'); + self._file_name = file_name; + + def write(self, elements): + elements_str = map(lambda x: str(x), elements); + line = ",".join(elements_str); + self._file.write(line + "\n"); + self._file.flush(); + + def close(self): + self._file.close(); + self._file = None; diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/dpi1.py b/VNFs/DPPD-PROX/helper-scripts/dpi/dpi1.py new file mode 100644 index 00000000..ec3e4a03 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/dpi1.py @@ -0,0 +1,243 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from testerset import * +from time import sleep +from time import time +from decimal import * +import copy +from os import system +import socket +from itertools import chain +from math import * +from csvwriter import * +from config import * +from progress import * +from proxmaxssprobe import * + +def runTest(minSetupRate, testParam): + print "Running test with following parameters:" + print testParam.toString(); + + testers = testerSet(config._test_systems, config._max_port_rate, testParam); + + thresh = testParam.getConnections(); + p = Progress(thresh, ["connections", "setup rate", "reTX"], False); + loop_count = 0; + converged = False; + + testers.startForkJoin(); + testers.wait_links_up(); + testers.start_cores(); + + print "Running until convergence (%s connections)" % str(thresh) + while (not converged): + sleep(config._interCheckDuration) + testers.update_stats(); + tot = testers.get_total_connections(); + tot_retx = testers.get_total_retx(); + rates = testers.get_rates(); + curSetupRate = testers.get_setup_rate(); + ierrors = testers.getIerrors(); + + converged = tot >= thresh; + if (not converged): + if (loop_count > 0 and curSetupRate < minSetupRate): + reason = str(curSetupRate) + " < " + str(minSetupRate); + print "Current setup rate is lower than min setup rate: " + reason + testers.killProx(); + return False, []; + if (not testers.conditionsGood()): + print "conditions are bad: " + testers.getReason(); + testers.killProx(); + return False, []; + + if (config._debug): + p.setProgress(tot, [tot, curSetupRate, tot_retx]); + print p.toString(); + loop_count += 1; + print "converged" + + skipTime = config._skipTime + print "Connection threshold reached, waiting for " + str(skipTime) + "s, conditions checked = " + str(config._checkConditions) + while (skipTime > 0): + skipTime -= config._interCheckDuration + sleep(config._interCheckDuration) + testers.update_stats(); + if (config._checkConditions and not testers.conditionsGood()): + print "conditions are bad: " + testers.getReason(); + testers.killProx(); + return False, []; + + testers.tx_rate_meassurement(); + + testLength = config._testLength + print "Waiting final " + str(testLength) + "s" + while (testLength > 0): + testLength -= config._interCheckDuration + sleep(config._interCheckDuration) + testers.update_stats(); + if (not testers.conditionsGood()): + print "conditions are bad: " + testers.getReason(); + testers.killProx(); + return False, []; + + rates = testers.tx_rate_meassurement(); + + testers.killProx(); + return True, rates; + +def find_ss(tot_conn, maxSetupRate, ss_max): + iterationCount = 0; + valid_ss = [] + speed_ss = []; + + # The setup rate must be in [0.2% of total connections, maxSetupRate] + # Also, it must not be hihger than 50% of the total connections + min_setup_rate = tot_conn / 500; + + if (min_setup_rate > maxSetupRate): + print "min setup rate > max setup rate: " + str(min_setup_rate) + " > " + str(maxSetupRate); + return valid_ss, speed_ss; + if (maxSetupRate > tot_conn / 2): + print "maximum setup rate (" + str(maxSetupRate) + ") is more than 50% of " + str(tot_conn) + return valid_ss, speed_ss; + + accuracy = 10**config._accuracy + ss_lo = 1 + ss_hi = int(round(ss_max * accuracy,0)) + + iterationOverride = [ss_hi, ss_lo]; + # Binary search for highest speed scaling + while (ss_lo <= ss_hi): + if (iterationCount < len(iterationOverride)): + ss = iterationOverride[iterationCount] + else: + ss = (ss_lo + ss_hi)/2; + + testParam = TestParameters(maxSetupRate, tot_conn, float(ss)/accuracy); + + success, rates = runTest(min_setup_rate, testParam); + print "success = " + str(success) + ", rates = " + str(rates) + if (success == True): + valid_ss.append(float(ss)/accuracy); + speed_ss.append(sum(rates)/len(rates)) + ss_lo = ss + 1 + else: + ss_hi = ss - 1; + iterationCount += 1 + return valid_ss, speed_ss; + +def get_highest_ss_and_speed(valid_ss, speed_ss): + highest_ss = None; + highest_speed = None; + + for i in range(len(valid_ss)): + if(highest_ss == None or highest_ss < valid_ss[i]): + highest_ss = valid_ss[i]; + highest_speed = speed_ss[i]; + return highest_ss, highest_speed; + +def get_max_ss(): + ts = config._test_systems[0]; + test_system = ProxMaxSSProbe(ts); + max_ss = test_system.getMaxSS(); + + return floor((max_ss * (10**config._accuracy)))/(10**config._accuracy) + +config = Config(); +config.parse(sys.argv[0], sys.argv[1:]) + +err = config.getErrorTestOne(); +if (err is not None): + print "Invalid configuration: " + err; + exit(-1); +else: + print config.toString() + +if (config._once is not None): + maxSetupRate = int(config._once[0]) + minSetupRate = maxSetupRate/500 + connections = int(config._once[1]) + speedScaling = float(config._once[2]) + + testParam = TestParameters(maxSetupRate, connections, speedScaling) + success, rates = runTest(minSetupRate, testParam) + print "success = " + str(success) + ", port rates = " + str(rates) + exit(0); + +msr_list = [] +msr_list += range(4000, 20000, 2000) +msr_list += range(20000, 100000, 20000) +msr_list += range(100000, 300000, 50000) +msr_list += range(300000, 800001, 100000); + +conn_list = [1*10**5, 2*10**5, 4*10**5, 8*10**5, 1*10**6, 2*10**6] + +summary_file = CsvWriter() +summary_file.open(config._output_file_name) + +tot_it = 0; +for tot_conn in conn_list: + for msr in msr_list: + if (msr >= tot_conn/2): + break; + tot_it += 1 + +cnt = -1; +print "Search will include " + str(tot_it) + " parameter combinations" +print "Will search for highest link utilization" + +# If the lowest msr was a for n connections, then the lowest msr +# for n + 1 connections can't be lower than a. +low_sr = msr_list[0]; + +max_ss = get_max_ss() + +high_ss = Decimal(max_ss) + +globalProgress = Progress(tot_it) +globalProgress.setProgress(0); +for tot_conn in conn_list: + had_success = False; + all_ss = [] + for msr in msr_list: + globalProgress.incrProgress(); + + if (msr < low_sr): + print "skipping " + str(msr) + " since it is lower than " + str(low_sr) + continue; + + print globalProgress.toString(); + + valid_ss, speed_ss = find_ss(tot_conn, msr, high_ss) + print "valid ss = " + str(valid_ss) + print "valid speeds = " + str(speed_ss) + + if (len(valid_ss) > 0): + highest_ss, highest_speed = get_highest_ss_and_speed(valid_ss, speed_ss); + summary_file.write([msr, tot_conn, highest_ss, highest_speed]); + + if (not had_success): + low_sr = msr; + + had_success = True; + all_ss = all_ss + valid_ss; + + if (len(all_ss) > 0): + high_ss = max(all_ss); diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/dpi2.py b/VNFs/DPPD-PROX/helper-scripts/dpi/dpi2.py new file mode 100644 index 00000000..65473f61 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/dpi2.py @@ -0,0 +1,229 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from testerset import * +from proxdpisut import * +from statsconsfile import * +from time import sleep +from time import time +from decimal import * +import copy +from os import system +import socket +from itertools import chain +from math import * +from csvwriter import * +from csvreader import * +from config import * +from progress import * +from resultprocessor import * + +def runTest(coreCount, testParam): + print "Running test with following parameters:" + print testParam.toString(); + + + testers = testerSet(config._test_systems, config._max_port_rate, testParam); + + ret = TestResult(testers.getCount()); + thresh = testParam.getConnections() * config._threshold; + converged = False; + + sut = ProxDpiSut(config._sut, coreCount); + + testers.startFork(); + sut.startFork(); + testers.startJoin(); + sut.startJoin(); + testers.wait_links_up(); + sut.startAllCores(); + sut.waitCmdFinished(); + testers.start_cores(); + + ret.addTimeTS(testers.getTsc()); + ret.addTimeSUT(sut.getTsc()); + + print "Running until convergence (%s connections)" % str(thresh) + p = Progress(thresh, ["connections", "setup rate", "reTX"], False); + while (not converged): + sleep(config._interCheckDuration) + testers.update_stats(); + + tot = testers.get_total_connections(); + tot_retx = testers.get_total_retx(); + rates = testers.get_rates(); + cur_setup_rate = testers.get_setup_rate(); + ierrors = testers.getIerrors(); + converged = tot >= thresh; + + if (not converged and not testers.conditionsGood()): + print "conditions are bad: " + testers.getReason(); + sut.forceQuit(); + sut.killProx(); + testers.killProx(); + return None; + + if (sut.getIerrors() != 0): + testers.killProx(); + print "Sending quit" + try: + sut.forceQuit(); + except: + print "Sending quit failed" + sut.killProx(); + return None; + + if (config._debug): + p.setProgress(tot, [tot, cur_setup_rate, tot_retx]); + print p.toString(); + + skipTime = config._skipTime + print "Connection threshold reached, waiting for " + str(skipTime) + "s, conditions checked = " + str(config._checkConditions) + while (skipTime > 0): + skipTime -= config._interCheckDuration + sleep(config._interCheckDuration) + testers.update_stats(); + if (config._checkConditions and not testers.conditionsGood()): + print "conditions are bad: " + testers.getReason(); + sut.forceQuit(); + sut.killProx(); + testers.killProx(); + return False, []; + + ret.addTimeTS(testers.getTsc()); + ret.addTimeSUT(sut.getTsc()); + + testers.tx_rate_meassurement(); + + testLength = config._testLength + print "Waiting final " + str(testLength) + "s" + while (testLength > 0): + testLength -= config._interCheckDuration + testers.update_stats(); + if (not testers.conditionsGood()): + print "conditions are bad: " + testers.getReason(); + sut.forceQuit(); + sut.killProx(); + testers.killProx(); + return None; + + if (sut.getIerrors() != 0): + testers.killProx(); + print "Sending quit" + try: + sut.forceQuit(); + except: + print "Sending quit failed" + sut.killProx(); + return None; + + sleep(config._interCheckDuration) + + rates = testers.tx_rate_meassurement(); + ret.addTimeTS(testers.getTsc()); + ret.addTimeSUT(sut.getTsc()); + + print "Quiting Prox on SUT" + # make sure stats are flushed + sut.quitProx(); + print "Quiting Prox on test system(s)" + testers.quitProx() + + ret.rates = rates + + sutStatsDump = "stats_dump_sut" + tsStatsDumpBaseName = "stats_dump_ts" + + sut.scpStatsDump(sutStatsDump); + tsStatsDump = testers.scpStatsDump(tsStatsDumpBaseName); + + ret.setTSStatsDump(tsStatsDump); + ret.setSUTStatsDump(sutStatsDump); + return ret + +def meassurePerf(coreCount, maxSetupRate, total_connections, ss_hi): + iterationCount = 0; + accuracy = 10**config._accuracy + ss_lo = 1 + ss_hi = int(round(ss_hi * accuracy, 0)) + success = True; + + downrate = float(0) + highest_ss = 0 + iterationOverride = [ss_hi, ss_lo]; + while (ss_lo <= ss_hi): + if (iterationCount < len(iterationOverride)): + ss = iterationOverride[iterationCount] + else: + ss = (ss_lo + ss_hi)/2; + + testParam = TestParameters(maxSetupRate, total_connections, float(ss)/accuracy); + + result = runTest(coreCount, testParam); + + if (result is None): + success = False + else: + rp = ResultProcessor(result) + rp.process(); + success = rp.percentHandled() > 0.99999 + + print "test result = " + str(success) + if (success): + ss_lo = ss + 1; + highest_ss = max(highest_ss, ss); + print result.rates + downrate = sum(result.rates)/len(result.rates) + else: + ss_hi = ss - 1; + iterationCount += 1 + + return downrate, float(highest_ss)/accuracy + +config = Config(); +config.parse(sys.argv[0], sys.argv[1:]) + +err = config.getErrorTestTwo(); +if (err is not None): + print "Invalid configuration: " + err; + exit(-1); +else: + print config.toString() + +infileFields = [] +infileFields += [("msr", "int")] +infileFields += [("conn", "int")] +infileFields += [("ss", "Decimal")] +infileFields += [("bw", "Decimal")] + +infile = CsvReader(infileFields); +infile.open(config.getInputFileName()) +inputs = infile.readAll() +infile.close(); + +summary = CsvWriter(); +summary.open(config._output_file_name); + +print "Will test up SUT config with " + str(config._dpiCoreList) + " DPI cores" + +for a in inputs: + for coreCount in config._dpiCoreList: + downrate, ss = meassurePerf(coreCount, a["msr"], a["conn"], a["ss"]); + summary.write([coreCount, a["msr"], a["conn"], ss, downrate]); + +summary.close() diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/maketable.py b/VNFs/DPPD-PROX/helper-scripts/dpi/maketable.py new file mode 100644 index 00000000..f8b7bdc0 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/maketable.py @@ -0,0 +1,140 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +import sys +from config import * +from csvreader import * +from sets import Set +from csvwriter import * + +class ResultEntry: + def __init__(self): + self.boundary = None; + self.cores = {} + + def setBoundary(self, val): + self.boundary = val; + + def addCoreResult(self, core, val): + self.cores[core] = val + + def getCoreResult(self, core): + if (core in self.cores): + return self.cores[core]; + return None; + + def getBoundary(self): + return self.boundary; + + def getCores(self): + return self.cores + + def getMsr(self): + return self.msr; + +class DictEntry: + def __init__(self, key): + self.dictionary = {} + self.entries = [] + self.key = key; + +config = Config(); +config.parse(sys.argv[0], sys.argv[1:]) + +err = config.getErrorMakeTable(); + +if (err is not None): + print err + exit(-1); + +if (config._debug): + print "Performance data: " + config.getInputFileName2() + print "Boundaries: " + config.getInputFileName() + +allData = {} + +infileFields = [] +infileFields += [("msr", "int")] +infileFields += [("conn", "int")] +infileFields += [("ss", "Decimal")] +infileFields += [("bw", "Decimal")] + +boundariesFile = CsvReader(infileFields) +boundariesFile.open(config.getInputFileName()); +boundaries = boundariesFile.readAll(); + +cores = Set() + +orderedResults = [] +finalResults = {} + +for a in boundaries: + key = a["conn"] + if (key not in finalResults): + newDict = DictEntry(key) + finalResults[key] = newDict + orderedResults.append(newDict) + +for a in boundaries: + table = finalResults[a["conn"]] + key = a["msr"] + value = ResultEntry() + value.msr = a["msr"] + value.conn = a["conn"] + value.boundary = a["bw"] + table.dictionary[key] = value + table.entries.append(value) + +infileFields2 = [] +infileFields2 += [("cores", "int")] +infileFields2 += [("msr", "int")] +infileFields2 += [("conn", "int")] +infileFields2 += [("ss", "Decimal")] +infileFields2 += [("down", "Decimal")] + +resultsFile = CsvReader(infileFields2) +resultsFile.open(config.getInputFileName2()) + +for a in resultsFile.readAll(): + table = finalResults[a["conn"]] + key = a["msr"] + table.dictionary[key].addCoreResult(a["cores"], a["down"]) + cores.add(a["cores"]); + + +outputFile = CsvWriter() + +outputFile.open(config._output_file_name) + +title = ["setup rate", "maximum"] +for e in sorted(cores): + title += [str(e)] + +for a in orderedResults: + outputFile.write(["connections = " + str(a.key)]) + outputFile.write(title) + + for e in a.entries: + line = [str(e.getMsr())] + line += [str(e.getBoundary())] + for c in sorted(cores): + if (e.getCoreResult(c) is not None): + line += [str(e.getCoreResult(c))] + else: + line += [""] + outputFile.write(line) diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/progress.py b/VNFs/DPPD-PROX/helper-scripts/dpi/progress.py new file mode 100644 index 00000000..5e44c678 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/progress.py @@ -0,0 +1,67 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from decimal import * +from time import time + +class Progress: + def __init__(self, limit, fieldNames = [], overallETA = True): + self._fieldNames = fieldNames; + self._limit = limit; + self._progress = 0; + self._prevProgress = 0; + self._prevTime = 0; + self._progressSetCount = 0; + self._time = 0; + self._overallETA = overallETA; + + def setProgress(self, progress, fieldValues = []): + self._fieldValues = fieldValues; + if (self._overallETA == True): + self._progress = progress + self._time = time(); + if (self._progressSetCount == 0): + self._prevProgress = self._progress; + self._prevTime = self._time; + else: + self._prevProgress = self._progress; + self._prevTime = self._time; + self._progress = progress; + self._time = time(); + self._progressSetCount += 1 + + def incrProgress(self): + self.setProgress(self._progress + 1); + + def toString(self): + ret = "" + ret += str(self._getETA()) + " seconds left" + for f,v in zip(self._fieldNames, self._fieldValues): + ret += ", %s=%s" % (str(f),str(v)) + return ret; + + def _getETA(self): + if (self._progressSetCount < 2): + return "N/A" + diff = self._progress - self._prevProgress; + t_diff = Decimal(self._time - self._prevTime); + if (t_diff < 0.001 or diff <= 0): + return "N/A" + rate = Decimal(diff)/t_diff + remaining = Decimal(self._limit - self._progress); + return round(remaining/rate, 2); diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/prox.py b/VNFs/DPPD-PROX/helper-scripts/dpi/prox.py new file mode 100644 index 00000000..60ef7592 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/prox.py @@ -0,0 +1,253 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +import threading +from time import * +from proxsocket import * +from remotesystem import * + +class ProxStarter: + def __init__(self, remoteSystem, cmd): + self._remoteSystem = remoteSystem + self._cmd = cmd + self._thread = None + self._prox = None; + self._result = None; + self._startDuration = None + + def startThreaded(self): + self._start_thread = threading.Thread(target = self._run, args = (self, 1)) + self._start_thread.start(); + + def joinThreaded(self): + self._start_thread.join(); + return self._result; + + def getResult(self): + return self._result; + + def getStartDuration(self): + return self._startDuration; + def getProx(self): + return self._prox; + + def _run(self, a, b): + before = time.time() + self._remoteSystem.run("sudo killall -w -q -9 prox") + + self._result = self._remoteSystem.run(self._cmd); + + sleep(1) + after = time.time() + self._startDuration = after - before; + +class StatsCmd(object): + def __init__(self, prox): + self._cmd = "" + self._parts = [] + self._beforeParts = [] + self._prox = prox; + + def sendRecv(self): + cmd = self.getCmd() + reply = self._prox._send(cmd)._recv() + self.setReply(reply) + + def add(self, stats): + if (len(self._cmd) != 0): + self._cmd += "," + self._cmd += stats + + if (len(self._parts) == 0): + self._beforeParts += [0] + else: + before = self._parts[-1] + self._beforeParts[-1]; + self._beforeParts += [before] + + self._parts += [stats.count(",") + 1]; + + def getCmd(self): + return "stats " + self._cmd; + + def setReply(self, reply): + self._reply = reply.split(","); + + def getResult(self, idx): + start = self._beforeParts[idx]; + end = start + self._parts[idx]; + return self._reply[start:end] + +class Prox(object): + def __init__(self, systemConfig): + self._systemConfig = systemConfig; + self._proxStarter = None + + user = self._systemConfig._user + ip = self._systemConfig._ip + self._remoteSystem = remoteSystem(user, ip); + + self.resetArguments() + + def resetArguments(self): + self._args = [] + + def addArgument(self, arg): + self._args.append(arg); + + def startFork(self): + cmd = self.getCmd(); + self._proxStarter = ProxStarter(self._remoteSystem, cmd) + self._proxStarter.startThreaded(); + + def startJoin(self): + ret = self.startJoinNoConnect(); + self._connectSocket(); + self._querySetup(); + return self._proxStarter.getStartDuration(); + + def startJoinNoConnect(self): + return self._proxStarter.joinThreaded(); + + def getCmd(self): + proxDir = self._systemConfig.getProxDir(); + cfgFile = self._systemConfig.getCfgFile(); + + cmd = "cd " + proxDir + "; " + cmd += "sudo ./build/prox " + cmd += "-f " + cfgFile + + for arg in self._args: + cmd += " " + arg + return cmd + + def getLog(self): + proxDir = self._systemConfig.getProxDir() + cmd = "cat " + proxDir + "/prox.log"; + return self._remoteSystem.run(cmd)["out"]; + + def getIP(self): + return self._systemConfig._ip; + + def getHz(self): + return self._hz; + + def getBeg(self): + return self._beg; + + def getPorts(self): + return self._ports; + + def getIerrors(self): + sc = StatsCmd(self) + sc.add(self._buildIerrorsCmd()); + sc.sendRecv() + return self._parseIerrorsReply(sc.getResult(0)); + + def _parseIerrorsReply(self, rep): + tot_ierrors = 0; + for e in rep: + tot_ierrors += int(e); + return tot_ierrors; + + def _buildIerrorsCmd(self): + cmd = "" + for port in self._ports: + if (len(cmd)): + cmd += "," + cmd += "port(%s).ierrors" % str(port) + return cmd; + + def waitCmdFinished(self): + self._send("stats hz")._recv(); + + def waitAllLinksUp(self): + link_down = True; + while (link_down): + link_down = False; + for port in self._ports: + cmd = "port link state %s" % str(port) + link_state = self._send(cmd)._recv(); + if (link_state == "down"): + link_down = True; + print "Link down on port " + str(port) + ", waiting one second" + break; + sleep(1); + + def startAllCores(self): + self._send("start all"); + + def stopAllCores(self): + self._send("stop all"); + + def forceQuit(self): + self._send("quit_force")._recv(); + + def killProx(self): + self._remoteSystem.run("sudo killall -w -q -9 prox") + + def getTsc(self): + return self._getTsc(); + + def _getTsc(self): + return int(self._send("stats global.tsc")._recv()); + + def scpStatsDump(self, dst): + proxDir = self._systemConfig.getProxDir() + + src = proxDir + "/stats_dump"; + print "Copying " + src + " to " + dst + self._remoteSystem.scp(src, dst); + + def _querySetup(self): + print "Query setup on " + str(self.getIP()) + self._queryHz() + self._queryBeg() + self._queryPorts() + self._querySetup2() + + def _querySetup2(self): + print "running query 2" + pass + + def quitProx(self): + self._send("quit")._recv(); + + def _queryHz(self): + self._hz = int(self._send("stats hz")._recv()); + + def _queryBeg(self): + self._beg = self._getTsc(); + + def _queryPorts(self): + self._ports = [] + port_info_all = self._send("port info all")._recv(); + port_info_list = port_info_all.split(','); + + for port_info in port_info_list: + if (len(port_info) > 0): + self._ports.append(int(port_info.split(":")[0])); + + def _connectSocket(self): + self._proxSocket = ProxSocket(self.getIP()) + + def _send(self, msg): + self._proxSocket.send(msg); + return self + + def _recv(self): + return self._proxSocket.recv(); diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/proxdpisut.py b/VNFs/DPPD-PROX/helper-scripts/dpi/proxdpisut.py new file mode 100644 index 00000000..aae900b0 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/proxdpisut.py @@ -0,0 +1,61 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from prox import * +from remotesystem import * +from time import * +from decimal import * + +class ProxDpiSut(Prox): + def __init__(self, ts, coreCount): + super(ProxDpiSut, self).__init__(ts) + + self._setDefaultArguments(); + self._setDpiCoreCount(coreCount); + + def _setDefaultArguments(self): + self.addArgument("-e"); + self.addArgument("-t"); + self.addArgument("-k"); + self.addArgument("-d"); + self.addArgument("-r 0.01"); + + def _setDpiCoreCount(self, count): + self.addArgument("-q dpi_core_count=" + str(count)) + + def _querySetup2(self): + self._query_cores(); + + def _query_cores(self): + print "querying cores" + self._wk = self._get_core_list("$wk"); + + def _get_core_list(self, var): + ret = [] + result = self._send("echo " + var)._recv(); + for e in result.split(","): + ret += [e]; + return ret; + + def getTsc(self): + cmd = "stats task.core(%s).task(0).tsc" % self._wk[-1] + res = int(self._send(cmd)._recv()); + if (res == 0): + return self._getTsc(); + else: + return res; diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/proxdpitester.py b/VNFs/DPPD-PROX/helper-scripts/dpi/proxdpitester.py new file mode 100644 index 00000000..19b08c92 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/proxdpitester.py @@ -0,0 +1,258 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from prox import * +from remotesystem import * +from time import * +from decimal import * +from timeseriespoint import * + +class TestParameters: + def __init__(self, max_setup_rate, total_connections, ss): + self.max_setup_rate = max_setup_rate; + self.total_connections = total_connections; + self.ss = ss; + + def toString(self): + ret = "" + ret += "\tMaximum setup rate = %d\n" % self.max_setup_rate + ret += "\tTotal number of connections = %d\n" % self.total_connections + ret += "\tSpeed scaling = %s\n" % str(self.ss) + return ret; + + def getPerSystem(self, count): + msr = self.max_setup_rate / count + cnn = self.total_connections / count + return TestParameters(msr, cnn, self.ss); + + def getConnections(self): + return self.total_connections; + +class ProxDpiTester(Prox): + TENGIGABITBYTESPERSECOND = 1250000000 + + def __init__(self, ts, testParam, ID): + super(ProxDpiTester, self).__init__(ts) + + self._sc = None + self._lastTot = None + self._prevTot = None; + self._prevBytesClient = None + self._lastBytesClient = None + self._prevBytesTxMeassurement = None + self._lastBytesTxMeassurement = None + + self._setDefaultArguments(); + self._setMsr(testParam.max_setup_rate) + self._setConnections(testParam.total_connections); + self._setSpeedScaling(testParam.ss); + self._setID(ID); + + def _setDefaultArguments(self): + self.addArgument("-e") + self.addArgument("-t") + self.addArgument("-k") + self.addArgument("-d") + self.addArgument("-r 0.01"); + + def _setMsr(self, msr): + self.addArgument("-q max_setup_rate=" + str(msr)) + + def _setConnections(self, connections): + self.addArgument("-q connections=" + str(connections)) + + def _setID(self, ID): + self.addArgument("-q test_system_id=" + str(ID)) + + def _setSpeedScaling(self, ss): + self.addArgument("-q ss=" + str(ss)) + + def _querySetup2(self): + self._query_client_ports(); + self._query_server_ports(); + self._query_cores(); + + def _query_client_ports(self): + self._client_ports = [] + for i in range(0, len(self._ports), 2): + self._client_ports.append(self._ports[i]); + + def _query_server_ports(self): + self._server_ports = [] + for i in range(1, len(self._ports), 2): + self._server_ports.append(self._ports[i]); + + def _query_cores(self): + self._query_ld(); + self._query_servers(); + self._query_clients(); + + def _query_ld(self): + self._ld = self._get_core_list("$all_ld"); + + def _query_servers(self): + self._servers = self._get_core_list("$all_servers") + + def _query_clients(self): + self._clients = self._get_core_list("$all_clients") + + def _get_core_list(self, var): + ret = [] + result = self._send("echo " + var)._recv(); + for e in result.split(","): + ret += [e]; + return ret; + + def start_all_ld(self): + self._send("start $all_ld"); + + def start_all_workers(self): + self._send("start $all_workers"); + + def stop_all_ld(self): + self._send("stop $all_ld"); + + def stop_all_workers(self): + self._send("stop $all_workers"); + + def update_stats(self): + if (self._sc is None): + self._sc = StatsCmd(self) + self._sc.add(self._buildTotalConnectionsCmd()) + self._sc.add(self._buildReTXCmd()) + self._sc.add(self._buildIerrorsCmd()) + self._sc.add(self._buildBytesPerPortCmd(self._client_ports, "rx")); + + self._sc.sendRecv() + + self._updateTotalConnections(self._sc.getResult(0)) + self._updateReTX(self._sc.getResult(1)) + self._updateIerrors(self._sc.getResult(2)) + self._update_rates_client_ports(self._sc.getResult(3)); + + def _buildTotalConnectionsCmd(self): + cmd = "l4gen(%s).tsc" % str(self._clients[0]) + + for core in self._clients: + if (len(cmd) > 0): + cmd += "," + cmd += "l4gen(%s).created,l4gen(%s).finished" % (str(core), str(core)) + return cmd; + + def _updateTotalConnections(self, rep): + instant = Decimal(int(rep[0]) - self._beg)/self._hz + rep = rep[1:] + tot = 0; + for i in range(0,len(rep), 2): + tot += int(rep[i]) - int(rep[i + 1]); + + prev = self._lastTot; + last = TimeSeriesPoint(tot, instant); + + if (prev == None): + prev = last; + + self._prevTot = prev + self._lastTot = last; + + def _buildReTXCmd(self): + cmd = "" + for core in self._clients + self._servers: + if (len(cmd) > 0): + cmd += "," + cmd += "l4gen(%s).retx" % str(core) + return cmd; + + def _updateReTX(self, rep): + retx = 0; + for i in rep: + retx += int(i); + self._retx = retx; + + def _updateIerrors(self, rep): + self._ierrors = self._parseIerrorsReply(rep) + + def get_total_connections(self): + return self._lastTot.getValue() + + def getCurrentSetupRate(self): + return int(self._lastTot.getRateOfChange(self._prevTot)); + + def get_total_retx(self): + return self._retx + + def get_rates_client_ports(self): + return self._calcLinkUtilization(self._prevBytesClient, self._lastBytesClient); + + def getIerrorsCached(self): + return self._ierrors; + + def _update_rates_client_ports(self, rep): + prevBytes = self._lastBytesClient + lastBytes = self._parseTimeSeries(rep); + + if (prevBytes == None): + prevBytes = lastBytes; + + self._prevBytesClient = prevBytes; + self._lastBytesClient = lastBytes; + + def _getBytesPerPort(self, ports, rxOrTx): + sc = StatsCmd(self); + sc.add(self._buildBytesPerPortCmd(ports, rxOrTx)) + sc.sendRecv(); + + rep = sc.getResult(0); + + return self._parseTimeSeries(rep); + + def _buildBytesPerPortCmd(self, ports, rxOrTx): + cmd = "" + for port in ports: + if (len(cmd) > 0): + cmd += "," + cmd += "port(%s).%s.bytes,port(%s).tsc" % (str(port), rxOrTx, str(port)); + return cmd + + def tx_rate_meassurement(self): + prev = self._lastBytesTxMeassurement + last = self._getBytesPerPort(self._server_ports, "tx"); + + if (prev == None): + prev = last; + + self._prevBytesTxMeassurement = prev + self._lastBytesTxMeassurement = last + + return self._calcLinkUtilization(prev, last); + + def _parseTimeSeries(self, rep): + ret = [] + for i in range(0, len(rep), 2): + val = int(rep[0]) + instant = Decimal(int(rep[1]) - self._beg)/self._hz + ret.append(TimeSeriesPoint(val, instant)); + return ret; + + def _calcLinkUtilization(self, prev, last): + ret = [] + for i in range(0, len(prev)): + bytesPerSecond = last[i].getRateOfChange(prev[i]); + linkFraction = Decimal(bytesPerSecond)/self.TENGIGABITBYTESPERSECOND + ret.append(round(linkFraction,2)); + return ret; diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/proxmaxssprobe.py b/VNFs/DPPD-PROX/helper-scripts/dpi/proxmaxssprobe.py new file mode 100644 index 00000000..27c470c4 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/proxmaxssprobe.py @@ -0,0 +1,34 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from decimal import * +from prox import * + +class ProxMaxSSProbe(Prox): + def __init__(self, ts): + super(ProxMaxSSProbe, self).__init__(ts) + + def getMaxSS(self): + self.addArgument("-q max_ss_and_quit=true"); + self.addArgument("-q test_system_id=0"); + self.startFork(); + ret = self.startJoinNoConnect(); + last_occur = ret["out"].rfind("\n") + 1; + last_line = ret["out"][last_occur:]; + + return Decimal(last_line.split("=")[1]) diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/proxsocket.py b/VNFs/DPPD-PROX/helper-scripts/dpi/proxsocket.py new file mode 100644 index 00000000..fd4cc737 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/proxsocket.py @@ -0,0 +1,54 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +import socket + +class ProxSocket: + def __init__(self, ip): + self._ip = ip; + self._dat = "" + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + sock.connect((self._ip, 8474)) + except: + raise Exception("Failed to connect to prox on " + self._ip) + self._sock = sock; + + def send(self, msg): + self._sock.sendall(msg + "\n"); + return self + + def recv(self): + ret_str = ""; + done = 0; + while done == 0: + if (len(self._dat) == 0): + self._dat = self._sock.recv(256); + if (self._dat == ''): + return ''; + + while(len(self._dat)): + if (self._dat[0] == '\n'): + done = 1 + self._dat = self._dat[1:] + break; + else: + ret_str += self._dat[0]; + self._dat = self._dat[1:] + return ret_str; diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/ratedistribution.py b/VNFs/DPPD-PROX/helper-scripts/dpi/ratedistribution.py new file mode 100644 index 00000000..41d8ad53 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/ratedistribution.py @@ -0,0 +1,69 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +import sys +from decimal import * + +def usage(progName): + print "usage: " + progName + " config [up|down]" + print " The script reads a lua configuration " + print " and outputs a histogram wit 21 buckets." + print " The first 20 buckets contain 70th percentile." + print " The last bucket contains the remaining items." + exit(-1); + +if (len(sys.argv) != 3): + usage(sys.argv[0]) + +if (sys.argv[2] == "down"): + match = "dn_bps" +elif (sys.argv[2] == "up"): + match = "up_bps" +else: + usage(sys.argv[0]) + +values = [] +for line in open(sys.argv[1]).readlines(): + line = line.strip(); + + if line.find(match) != -1: + v = line.split(" = ")[1].strip(",") + values.append(Decimal(v)); + +values = sorted(values) + +treshold = values[int(len(values)*0.7)] + +buckets = [0]*21; + +for v in values: + if (v > treshold): + buckets[20] += 1 + else: + buckets[int(v * 20 / treshold)] += 1 + +stepSize = treshold / 20; + +print "# bucket range, count" +for i in range(len(buckets) - 1): + beg = str(int(i * stepSize)) + end = str(int((i + 1) * stepSize - 1)) + print beg + "-" + end + "," + str(buckets[i]) + +i = len(buckets) - 1 +print beg + "+," + str(buckets[i]) diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/remotesystem.py b/VNFs/DPPD-PROX/helper-scripts/dpi/remotesystem.py new file mode 100644 index 00000000..adbb288c --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/remotesystem.py @@ -0,0 +1,58 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +import os +import time +import socket + +def ssh(user, ip, cmd): + # print cmd; + ssh_options = "" + ssh_options += "-o StrictHostKeyChecking=no " + ssh_options += "-o UserKnownHostsFile=/dev/null " + ssh_options += "-o LogLevel=quiet " + running = os.popen("ssh " + ssh_options + " " + user + "@" + ip + " \"" + cmd + "\""); + ret = {}; + ret['out'] = running.read().strip(); + ret['ret'] = running.close(); + if (ret['ret'] == None): + ret['ret'] = 0; + + return ret; + +def ssh_check_quit(obj, user, ip, cmd): + ret = ssh(user, ip, cmd); + if (ret['ret'] != 0): + obj._err = True; + obj._err_str = ret['out']; + exit(-1); + +class remoteSystem: + def __init__(self, user, ip): + self._ip = ip; + self._user = user; + + def run(self, cmd): + return ssh(self._user, self._ip, cmd); + + def scp(self, src, dst): + running = os.popen("scp " + self._user + "@" + self._ip + ":" + src + " " + dst); + return running.close(); + + def getIP(self): + return self._ip diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/resultprocessor.py b/VNFs/DPPD-PROX/helper-scripts/dpi/resultprocessor.py new file mode 100644 index 00000000..ad196035 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/resultprocessor.py @@ -0,0 +1,210 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from sutstatsconsfile import * +from tsstatsconsfile import * +from csvwriter import * + +class TestResult: + class Times: + def __init__(self): + self.serie = [] + def addTime(self, val): + self.serie.append(val) + def getTime(self, i): + return self.serie[i] + + def __init__(self, testSystemCount): + self.rates = None; + self.tsStatsDump = []; + self.tsTimes = []; + for i in range(testSystemCount): + self.tsStatsDump.append(""); + self.tsTimes.append(TestResult.Times()); + + self.sutStatsDump = None; + self.sutTime = TestResult.Times(); + + def getTSCount(self): + return len(self.tsTimes) + + def setTSStatsDump(self, filePaths): + self.tsStatsDump = filePaths; + + def setSUTStatsDump(self, filePath): + self.sutStatsDump = filePath; + + def getTSStatsDump(self): + return self.tsStatsDump; + + def getSUTStatsDump(self): + return self.sutStatsDump; + + def addTimeTS(self, times): + for i in range(len(times)): + self.tsTimes[i].addTime(times[i]) + + def addTimeSUT(self, time): + self.sutTime.addTime(time); + + +class ResultProcessor: + def __init__(self, testResult): + self._testResults = testResult; + + def process(self): + self._readStatsConsLogs(); + self._mergeTsStats(); + self._calcSetupRate(); + + def percentHandled(self): + converged_tsc = self._testResults.sutTime.getTime(1) - self._testResults.sutTime.getTime(0) + end_tsc = self._testResults.sutTime.getTime(2) - self._testResults.sutTime.getTime(0) + + converged = converged_tsc/Decimal(self._sutHz) + end = end_tsc/Decimal(self._sutHz); + + rx_converged = -1 + tx_converged = -1 + rx_end = -1 + tx_end = -1 + + for entry in self._sutStats: + timeStamp = entry[3] + if (rx_converged == -1): + if (timeStamp > converged): + rx_converged = entry[0] + tx_converged = entry[1] - entry[2] + else: + continue; + else: + if (timeStamp > end): + rx_end = entry[0] + tx_end = entry[1] - entry[2] + break; + return (tx_end - tx_converged)/Decimal(rx_end - rx_converged) + + def toFile(self, fileName): + outFile = CsvWriter(); + + outFile.open(fileName) + + for entry in self._sutStats: + timeStamp = round(entry[3], 3); + rx = entry[0] + tx = entry[1] + drop = entry[2] + + outFile.write([timeStamp, rx, tx, drop, "", ""]) + + for entry in self._tsStats: + timeStamp = round(entry[-1], 3); + connections = entry[0] + setupRate = entry[3] + outFile.write([timeStamp,"","","", connections, setupRate]); + outFile.close(); + + def _readStatsConsLogs(self): + print "Reading SUT stats" + self._sutStats = self._readSutStats(); + print "Reading TS stats" + self._tsAllStats = self._readAllTSStats(); + + def _mergeTsStats(self): + # The first test system is the reference system. The totals + # will be accumulated by repeatedly taking the closest + # available data from other systems + ret = [] + for entry in self._tsAllStats[0]: + ret.append(entry) + + interSampleTime = ret[1][-1] - ret[0][-1]; + + mergedSampleCount = 0; + if (len(self._tsAllStats) == 1): + mergedSampleCount = len(ret) + + for i in range(0, len(self._tsAllStats) - 1): + prev = 0; + for entry in ret: + timeStamp = entry[-1] + found = False; + + for idx in range(prev, len(self._tsAllStats[i])): + diff = abs(self._tsAllStats[i][idx][-1] - timeStamp) + if (diff < interSampleTime): + found = True; + prev = idx; + break; + + if (found): + entry[0] += self._tsAllStats[i][prev][0] + entry[1] += self._tsAllStats[i][prev][1] + mergedSampleCount += 1; + else: + break; + + self._tsStats = ret[0: mergedSampleCount]; + + def _calcSetupRate(self): + for i in range(0, len(self._tsStats)): + prevCreated = 0 + prevTime = 0 + if (i > 0): + prevCreated = self._tsStats[i - 1][1]; + prevTime = self._tsStats[i - 1][-1]; + curCreated = self._tsStats[i][1]; + curTime = self._tsStats[i][-1]; + + setupRate = (curCreated - prevCreated)/(curTime - prevTime) + + self._tsStats[i].append(setupRate); + + + def _readSutStats(self): + ret = [] + fileName = self._testResults.getSUTStatsDump(); + beg = self._testResults.sutTime.getTime(0); + f = SutStatsConsFile(fileName, beg); + entry = f.readNext(); + self._sutHz = f.getHz(); + while (entry is not None): + ret.append(entry); + entry = f.readNext(); + f.close(); + return ret; + + def _readAllTSStats(self): + stats = [] + for i in range(self._testResults.getTSCount()): + fileName = self._testResults.getTSStatsDump()[i] + beg = self._testResults.tsTimes[i].getTime(0) + tsStat = self._readTSStats(fileName, beg) + stats.append(tsStat); + return stats; + + def _readTSStats(self, fileName, beg): + ret = [] + f = TSStatsConsFile(fileName, beg) + + entry = f.readNext() + while (entry is not None): + ret.append(entry); + entry = f.readNext(); + f.close() + return ret; diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/statsconsfile.py b/VNFs/DPPD-PROX/helper-scripts/dpi/statsconsfile.py new file mode 100644 index 00000000..a25c1232 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/statsconsfile.py @@ -0,0 +1,84 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +import os +import struct + +class StatsConsFile: + def __init__(self, file_name, tsc = None): + self._file = open(file_name, "rb"); + try: + data = self._file.read(4*8); + dataUnpacked = struct.unpack("<qqqq", data); + + self._hz = dataUnpacked[0] + if (tsc is None): + self._tsc = dataUnpacked[1] + else: + self._tsc = tsc; + + self._entryCount = dataUnpacked[2] + fieldCount = dataUnpacked[3] + + data = self._file.read(fieldCount); + fmt = "b" * fieldCount; + + dataUnpacked = struct.unpack("<" + fmt, data); + self._entryFmt = "<"; + self._entrySize = 0; + + for e in dataUnpacked: + if (e == 4): + self._entryFmt += "i" + elif (e == 8): + self._entryFmt += "q" + else: + raise Exception("Unknown field format: " + str(e)) + self._entrySize += e + except: + print "except" + self._file.close(); + + def setBeg(self, tsc): + self._tsc = tsc + + def getBeg(self): + return self._tsc; + + def getHz(self): + return self._hz + + def readNext(self): + ret = [] + for i in range(self._entryCount): + entry = self._readNextEntry() + if (entry == None): + return None; + ret.append(entry); + return ret; + + def _readNextEntry(self): + try: + entry = self._file.read(self._entrySize); + entryUnpacked = struct.unpack(self._entryFmt, entry); + return list(entryUnpacked) + except: + return None; + + def close(self): + self._file.close(); diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/sutstatsconsfile.py b/VNFs/DPPD-PROX/helper-scripts/dpi/sutstatsconsfile.py new file mode 100644 index 00000000..82bca9a8 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/sutstatsconsfile.py @@ -0,0 +1,61 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from statsconsfile import * +from decimal import * + +class SutStatsConsFile: + def __init__(self, fileName, offset): + self.offset = offset; + self.statsConsFile = StatsConsFile(fileName) + + def readNext(self): + entry = self._readNextEntry(); + + if (entry is None): + return None; + + while (entry is not None and entry[-1] <= 0): + entry = self._readNextEntry(); + return entry; + + def getHz(self): + return self.statsConsFile.getHz(); + + def _readNextEntry(self): + entry = self.statsConsFile.readNext(); + if (entry is None): + return None; + + rx = 0; + tx = 0; + drop = 0; + last_tsc = 0; + + for i in range(0, len(entry), 2): + rx += entry[i][2] + tx += entry[i][3] + drop += entry[i][4] + last_tsc = entry[i][5] + + last_tsc -= self.offset; + last_tsc = Decimal(last_tsc) / self.statsConsFile.getHz(); + return [rx, tx, drop, last_tsc]; + + def close(self): + self.statsConsFile.close(); diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/systemconfig.py b/VNFs/DPPD-PROX/helper-scripts/dpi/systemconfig.py new file mode 100644 index 00000000..9e35576f --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/systemconfig.py @@ -0,0 +1,73 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +class SystemConfig: + _user = None + _ip = None + _proxDir = None + _cfgFile = None + def __init__(self, user, ip, proxDir, configDir): + self._user = user; + self._ip = ip; + self._proxDir = proxDir; + self._cfgFile = configDir; + def __init__(self, text): + self._user = text.split("@")[0]; + text = text.split("@")[1]; + self._ip = text.split(":")[0]; + self._proxDir = text.split(":")[1]; + self._cfgFile = text.split(":")[2]; + + def getUser(self): + return self._user; + + def getIP(self): + return self._ip; + + def getProxDir(self): + return self._proxDir; + + def getCfgFile(self): + return self._cfgFile; + + @staticmethod + def checkSyntax(text): + split = text.split("@"); + if (len(split) != 2): + return SystemConfig.getSyntaxError(text); + after = split[1].split(":"); + if (len(after) != 3): + return SystemConfig.getSyntaxError(text); + return "" + def toString(self): + ret = ""; + ret += " " + self._user + "@" + self._ip + "\n" + ret += " " + "prox dir: " + self._proxDir + "\n" + ret += " " + "cfg dir: " + self._cfgFile + "\n" + return ret; + + @staticmethod + def getSyntaxError(text): + ret = "Invaild system syntax" + ret += ", got: " + str(text) + ret += ", expected: " + str(SystemConfig.expectedSyntax()) + return ret; + + @staticmethod + def expectedSyntax(): + return "user@ip:proxDir:cfgFile" diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/testerset.py b/VNFs/DPPD-PROX/helper-scripts/dpi/testerset.py new file mode 100644 index 00000000..fe3dce72 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/testerset.py @@ -0,0 +1,176 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from proxdpitester import * + +class testerSet: + def __init__(self, test_systems, maxRate, testParam): + self._test_systems = []; + self._reason = "" + self._maxRate = maxRate + + testParamPerSystem = testParam.getPerSystem(len(test_systems)); + + for i in range(len(test_systems)): + ts = test_systems[i]; + to_add = ProxDpiTester(ts, testParamPerSystem, i); + self.add_test_system(to_add); + + def getCount(self): + return len(self._test_systems); + + def add_test_system(self, test_system): + self._test_systems.append(test_system); + + def startFork(self): + print "Starting test systems:" + for ts in self._test_systems: + print "\t" + str(ts.getIP()) + ts.startFork(); + + def startJoin(self): + for ts in self._test_systems: + elapsed = ts.startJoin(); + if (elapsed == None): + print "Failed to start on " + str(ts.getIP()) + else: + print "Started on " + str(ts.getIP()) + sleep(1); + + def startForkJoin(self): + self.startFork(); + self.startJoin(); + + def update_stats(self): + for ts in self._test_systems: + ts.update_stats(); + + def wait_links_up(self): + for ts in self._test_systems: + ts.waitAllLinksUp(); + sleep(1); + + def start_cores(self): + for ts in self._test_systems: + ts.start_all_ld(); + ts.waitCmdFinished(); + for ts in self._test_systems: + ts.start_all_workers(); + for ts in self._test_systems: + ts.waitCmdFinished(); + + def stop_cores(self): + for ts in self._test_systems: + ts.stop_all_workers(); + ts.stop_all_ld(); + + for ts in self._test_systems: + ts.waitCmdFinished(); + + def getTsc(self): + ret = [] + for ts in self._test_systems: + ret += [ts.getTsc()] + return ret; + + def get_setup_rate(self): + total = 0; + for ts in self._test_systems: + total += ts.getCurrentSetupRate(); + return total + + def get_total_connections(self): + total = 0; + for ts in self._test_systems: + ts_tot_conn = ts.get_total_connections(); + total += ts_tot_conn + + return total; + + def get_total_retx(self): + total = 0; + for ts in self._test_systems: + total += ts.get_total_retx(); + return total; + + def getIerrors(self): + total = 0; + for ts in self._test_systems: + total += ts.getIerrorsCached(); + return total; + + def get_rates(self): + rates = []; + for ts in self._test_systems: + rates += ts.get_rates_client_ports(); + return rates; + + def tx_rate_meassurement(self): + rates = [] + for ts in self._test_systems: + rates += ts.tx_rate_meassurement(); + return rates; + + def scpStatsDump(self, dst): + ret = [] + for i in range(len(self._test_systems)): + dstFileName = dst + str(i); + ret.append(dstFileName); + self._test_systems[i].scpStatsDump(dstFileName) + return ret; + + def conditionsGood(self): + tot_retx = self.get_total_retx(); + rates = self.get_rates(); + ierrors = self.getIerrors(); + + if (tot_retx > 100): + self._reason = "Too many reTX (" + str(tot_retx) + ")" + return False; + if (ierrors > 0): + self._reason = "Too many ierrors (" + str(ierrors) + ")" + return False; + for i in range(0, len(rates)): + if (rates[i] > self._maxRate): + self._setReason(i, rates) + return False; + return True; + + def _setReason(self, port, rates): + portStr = str(port); + rateStr = str(rates[port]) + maxRateStr = str(self._maxRate); + allRatesStr = str(rates); + + fmt = "Rate on port %s = %s > %s, rate on all = %s" + self._reason = fmt % (portStr, rateStr, maxRateStr, allRatesStr) + + def getReason(self): + return self._reason; + + def quitProx(self): + for ts in self._test_systems: + ts.quitProx(); + + def killProx(self): + for ts in self._test_systems: + ts.stop_all_workers(); + for ts in self._test_systems: + ts.stop_all_ld(); + for ts in self._test_systems: + ts.killProx(); diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/timeseriespoint.py b/VNFs/DPPD-PROX/helper-scripts/dpi/timeseriespoint.py new file mode 100644 index 00000000..521a0893 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/timeseriespoint.py @@ -0,0 +1,39 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from decimal import * + +class TimeSeriesPoint: + def __init__(self, value, instant): + self._value = value; + self._instant = instant; + + def getValue(self): + return self._value; + + def getInstant(self): + return self._instant; + + def getRateOfChange(self, other): + diff = self.getValue() - other.getValue(); + t_diff = self.getInstant() - other.getInstant(); + + if (diff == 0 or abs(t_diff) <= 0.00001): + return Decimal(0) + else: + return Decimal(diff)/t_diff diff --git a/VNFs/DPPD-PROX/helper-scripts/dpi/tsstatsconsfile.py b/VNFs/DPPD-PROX/helper-scripts/dpi/tsstatsconsfile.py new file mode 100644 index 00000000..10e48a68 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/dpi/tsstatsconsfile.py @@ -0,0 +1,60 @@ +#!/bin/env python + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +from statsconsfile import * +from decimal import * + +class TSStatsConsFile: + def __init__(self, fileName, offset): + self.offset = offset; + self.statsConsFile = StatsConsFile(fileName) + + def readNext(self): + entry = self._readNextEntry(); + if (entry is None): + return None; + + while (entry is not None and entry[-1] <= 0): + entry = self._readNextEntry(); + + return entry; + + def _readNextEntry(self): + entry = self.statsConsFile.readNext(); + if (entry is None): + return None; + + rx = 0; + tx = 0; + active = 0; + created = 0; + last_tsc = 0; + for i in range(0, len(entry), 2): + active += entry[i][2] + created += entry[i][3] + rx += entry[i][4] + tx += entry[i][5] + last_tsc = entry[i][6] + + last_tsc -= self.offset; + last_tsc = Decimal(last_tsc) / self.statsConsFile.getHz(); + + return [active, created, rx, tx, last_tsc]; + + def close(self): + self.statsConsFile.close(); |