summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xscripts/automation/trex_control_plane/client/trex_stateless_client.py106
-rwxr-xr-xscripts/automation/trex_control_plane/common/text_opts.py33
-rwxr-xr-xscripts/automation/trex_control_plane/console/parsing_opts.py9
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp1
-rw-r--r--src/stateless/cp/trex_streams_compiler.cpp9
-rw-r--r--src/stateless/cp/trex_streams_compiler.h19
6 files changed, 147 insertions, 30 deletions
diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
index 9b421acb..ca2ad0bb 100755
--- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
@@ -81,6 +81,22 @@ def RC_ERR (err):
LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled'])
+########## utlity ############
+def mult_to_factor (mult, max_bps, max_pps, line_util):
+ if mult['type'] == 'raw':
+ return mult['value']
+
+ if mult['type'] == 'bps':
+ return mult['value'] / max_bps
+
+ if mult['type'] == 'pps':
+ return mult['value'] / max_pps
+
+ if mult['type'] == 'percentage':
+ return mult['value'] / line_util
+
+
+
# describes a stream DB
class CStreamsDB(object):
@@ -438,6 +454,44 @@ class Port(object):
def get_profile (self):
return self.profile
+
+ def print_profile (self, mult, duration):
+ if not self.get_profile():
+ return
+
+ rate = self.get_profile()['rate']
+ graph = self.get_profile()['graph']
+
+ print format_text("Profile Map Per Port\n", 'underline', 'bold')
+
+ factor = mult_to_factor(mult, rate['max_bps'], rate['max_pps'], rate['max_line_util'])
+
+ print "Profile max BPS (base / req): {:^12} / {:^12}".format(format_num(rate['max_bps'], suffix = "bps"),
+ format_num(rate['max_bps'] * factor, suffix = "bps"))
+
+ print "Profile max PPS (base / req): {:^12} / {:^12}".format(format_num(rate['max_pps'], suffix = "pps"),
+ format_num(rate['max_pps'] * factor, suffix = "pps"),)
+
+ print "Profile line util. (base / req): {:^12} / {:^12}".format(format_percentage(rate['max_line_util'] * 100),
+ format_percentage(rate['max_line_util'] * factor * 100))
+
+
+ # duration
+ exp_time_base_sec = graph['expected_duration'] / (1000 * 1000)
+ exp_time_factor_sec = exp_time_base_sec / factor
+
+ # user configured a duration
+ if duration > 0:
+ if exp_time_factor_sec > 0:
+ exp_time_factor_sec = min(exp_time_factor_sec, duration)
+ else:
+ exp_time_factor_sec = duration
+
+
+ print "Duration (base / req): {:^12} / {:^12}".format(format_time(exp_time_base_sec),
+ format_time(exp_time_factor_sec))
+ print "\n"
+
################# events handler ######################
def async_event_port_stopped (self):
self.state = self.STATE_STREAMS
@@ -549,13 +603,8 @@ class CTRexStatelessClient(object):
return ret
delta = time.time() - time1
+ print format_time(delta) + "\n"
- for unit in ['sec','ms','usec']:
-
- if delta > 1.0:
- print '{:,.2f} [{:}]\n'.format(delta, unit)
- break
- delta *= 1000.0
return ret
return wrap
@@ -1018,7 +1067,7 @@ class CTRexStatelessClient(object):
# start cmd
- def cmd_start (self, port_id_list, stream_list, mult, force, duration):
+ def cmd_start (self, port_id_list, stream_list, mult, force, duration, dry):
active_ports = list(set(self.get_active_ports()).intersection(port_id_list))
@@ -1044,11 +1093,23 @@ class CTRexStatelessClient(object):
if rc.bad():
return rc
- # finally, start the traffic
- rc = self.start_traffic(mult, duration, port_id_list)
- rc.annotate("Starting traffic on port(s) {0}:".format(port_id_list))
+ # when not on dry - start the traffic , otherwise validate only
+ if not dry:
+ rc = self.start_traffic(mult, duration, port_id_list)
+ rc.annotate("Starting traffic on port(s) {0}:".format(port_id_list))
- return rc
+ return rc
+ else:
+ rc = self.validate(port_id_list)
+ rc.annotate("Validating traffic profile on port(s) {0}:".format(port_id_list))
+
+ if rc.bad():
+ return rc
+
+ # show a profile on one port for illustration
+ self.ports[port_id_list[0]].print_profile(mult, duration)
+
+ return rc
@@ -1070,7 +1131,8 @@ class CTRexStatelessClient(object):
parsing_opts.FORCE,
parsing_opts.STREAM_FROM_PATH_OR_FILE,
parsing_opts.DURATION,
- parsing_opts.MULTIPLIER_STRICT)
+ parsing_opts.MULTIPLIER_STRICT,
+ parsing_opts.DRY_RUN)
opts = parser.parse_args(line.split())
@@ -1078,6 +1140,9 @@ class CTRexStatelessClient(object):
return RC_ERR("bad command line paramters")
+ if opts.dry:
+ print format_text("\n*** DRY RUN ***", 'bold')
+
if opts.db:
stream_list = self.stream_db.get_stream_pack(opts.db)
rc = RC(stream_list != None)
@@ -1099,7 +1164,7 @@ class CTRexStatelessClient(object):
# if total was set - divide it between the ports
opts.mult['value'] = opts.mult['value'] / len(opts.ports)
- return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration)
+ return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration, opts.dry)
@timing
def cmd_stop_line (self, line):
@@ -1185,20 +1250,6 @@ class CTRexStatelessClient(object):
return RC_ERR("bad command line paramters")
rc = self.cmd_validate(opts.ports)
- if rc.bad():
- return rc
-
- # for each port - print the profile
- port_id_list = self.__ports(opts.ports)
- for port_id in port_id_list:
- port = self.ports[port_id]
- rate = port.get_profile()['rate']
- print format_text("Port {0}:\n".format(port_id), 'underline', 'bold')
- print "Profile max BPS (m = 1): {:>15}".format(format_num(rate['max_bps'], suffix = "bps"))
- print "Profile max PPS (m = 1): {:>15}".format(format_num(rate['max_pps'], suffix = "pps"))
- print "Profile line util. (m = 1): {:>15}".format(format_percentage(rate['max_line_util'] * 100))
- print "\n"
-
return rc
@@ -1277,6 +1328,7 @@ class CTRexStatelessClient(object):
return True
+
#################################
# ------ private classes ------ #
class CCommLink(object):
diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py
index 69c76674..5a86149c 100755
--- a/scripts/automation/trex_control_plane/common/text_opts.py
+++ b/scripts/automation/trex_control_plane/common/text_opts.py
@@ -27,6 +27,39 @@ def format_num (size, suffix = ""):
return "NaN"
+def format_time (t_sec):
+ if t_sec < 0:
+ return "infinite"
+
+ if t_sec < 1:
+ # low numbers
+ for unit in ['ms', 'usec', 'ns']:
+ t_sec *= 1000.0
+ if t_sec >= 1.0:
+ return '{:,.2f} [{:}]'.format(t_sec, unit)
+
+ return "NaN"
+
+ else:
+ # seconds
+ if t_sec < 60.0:
+ return '{:,.2f} [{:}]'.format(t_sec, 'sec')
+
+ # minutes
+ t_sec /= 60.0
+ if t_sec < 60.0:
+ return '{:,.2f} [{:}]'.format(t_sec, 'minutes')
+
+ # hours
+ t_sec /= 60.0
+ if t_sec < 24.0:
+ return '{:,.2f} [{:}]'.format(t_sec, 'hours')
+
+ # days
+ t_sec /= 24.0
+ return '{:,.2f} [{:}]'.format(t_sec, 'days')
+
+
def format_percentage (size):
return "%0.2f %%" % (size)
diff --git a/scripts/automation/trex_control_plane/console/parsing_opts.py b/scripts/automation/trex_control_plane/console/parsing_opts.py
index d7bf583a..57ff06e0 100755
--- a/scripts/automation/trex_control_plane/console/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/console/parsing_opts.py
@@ -20,7 +20,8 @@ SERVER_IP = 8
STREAM_FROM_PATH_OR_FILE = 9
DURATION = 10
FORCE = 11
-TOTAL = 12
+DRY_RUN = 12
+TOTAL = 13
# list of ArgumentGroup types
MUTEX = 1
@@ -198,6 +199,12 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
{'metavar': 'SERVER',
'help': "server IP"}),
+ DRY_RUN: ArgumentPack(['-n', '--dry'],
+ {'action': 'store_true',
+ 'dest': 'dry',
+ 'default': False,
+ 'help': "Dry run - no traffic will be injected"}),
+
# advanced options
PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST,
ALL_PORTS],
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index 1e8328dc..fa3d96b2 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -619,6 +619,7 @@ TrexRpcCmdValidate::_run(const Json::Value &params, Json::Value &result) {
result["result"]["rate"]["max_pps"] = graph->get_max_pps();
result["result"]["rate"]["max_line_util"] = graph->get_max_bps() / port->get_port_speed_bps();
+ result["result"]["graph"]["expected_duration"] = graph->get_duration();
result["result"]["graph"]["events_count"] = (int)graph->get_events().size();
result["result"]["graph"]["events"] = Json::arrayValue;
diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp
index d83e4ab6..478e09f8 100644
--- a/src/stateless/cp/trex_streams_compiler.cpp
+++ b/src/stateless/cp/trex_streams_compiler.cpp
@@ -536,6 +536,9 @@ TrexStreamsGraph::add_rate_events_for_stream_cont(double &offset_usec, const Tre
/* no more events after this stream */
offset_usec = -1;
+
+ /* also mark we have an inifite time */
+ m_graph_obj->m_expected_duration = -1;
}
/**
@@ -648,6 +651,7 @@ TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) {
/* loop detection */
auto search = loop_hash.find(stream->m_next_stream_id);
if (search != loop_hash.end()) {
+ m_graph_obj->on_loop_detection();
break;
}
@@ -720,6 +724,11 @@ TrexStreamsGraphObj::find_max_rate() {
max_rate_bps = std::max(max_rate_bps, current_rate_bps);
}
+ /* if not mark as inifite - get the last event time */
+ if (m_expected_duration != -1) {
+ m_expected_duration = m_rate_events.back().time;
+ }
+
m_max_pps = max_rate_pps;
m_max_bps = max_rate_bps;
}
diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h
index e193a749..7fe2dbf2 100644
--- a/src/stateless/cp/trex_streams_compiler.h
+++ b/src/stateless/cp/trex_streams_compiler.h
@@ -133,6 +133,12 @@ class TrexStreamsGraphObj {
public:
+ TrexStreamsGraphObj() {
+ m_max_pps = 0;
+ m_max_bps = 0;
+ m_expected_duration = 0;
+ }
+
/**
* rate event is defined by those:
* time - the time of the event on the timeline
@@ -155,6 +161,10 @@ public:
return m_max_bps;
}
+ int get_duration() const {
+ return m_expected_duration;
+ }
+
const std::list<rate_event_st> & get_events() const {
return m_rate_events;
}
@@ -162,6 +172,10 @@ public:
private:
+ void on_loop_detection() {
+ m_expected_duration = -1;
+ }
+
void add_rate_event(const rate_event_st &ev) {
m_rate_events.push_back(ev);
}
@@ -169,8 +183,9 @@ private:
void generate();
void find_max_rate();
- double m_max_pps;
- double m_max_bps;
+ double m_max_pps;
+ double m_max_bps;
+ int m_expected_duration;
/* list of rate events */
std::list<rate_event_st> m_rate_events;