diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gtest/trex_stateless_gtest.cpp | 175 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 24 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.cpp | 33 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.h | 2 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream.cpp | 2 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream.h | 12 | ||||
-rw-r--r-- | src/stateless/cp/trex_streams_compiler.cpp | 266 | ||||
-rw-r--r-- | src/stateless/cp/trex_streams_compiler.h | 87 |
8 files changed, 590 insertions, 11 deletions
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 8640e7db..5b298023 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -1668,5 +1668,180 @@ TEST_F(basic_stl, dp_stop_event) { } +TEST_F(basic_stl, graph_generator1) { + std::vector<TrexStream *> streams; + TrexStreamsGraph graph; + TrexStream *stream; + + /* stream 1 */ + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 1); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->m_isg_usec = 42; + stream->set_pps(10); + stream->set_single_burst(43281); + stream->m_pkt.len = 512; + + stream->m_next_stream_id = 2; + + + streams.push_back(stream); + + /* stream 2 */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 2); + stream->m_enabled = true; + stream->m_self_start = false; + + stream->set_pps(20); + stream->set_multi_burst(4918, 13, 7); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + /* stream 3 */ + stream = new TrexStream(TrexStream::stCONTINUOUS, 0, 3); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->m_isg_usec = 50; + stream->set_pps(30); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 1512; + + streams.push_back(stream); + + + const TrexStreamsGraphObj &obj = graph.generate(streams); + EXPECT_EQ(obj.get_max_bps(), 405120); + EXPECT_EQ(obj.get_max_pps(), 50); + + for (auto stream : streams) { + delete stream; + } +} + + +TEST_F(basic_stl, graph_generator2) { + std::vector<TrexStream *> streams; + TrexStreamsGraph graph; + TrexStream *stream; + + /* add some multi burst streams */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 1); + stream->m_enabled = true; + stream->m_self_start = true; + + + stream->set_pps(1000); + + /* a burst of 2000 packets with a delay of 1 second */ + stream->m_isg_usec = 0; + stream->set_multi_burst(1000, 500, 1000 * 1000); + stream->m_pkt.len = 64; + + stream->m_next_stream_id = -1; + + streams.push_back(stream); + + /* another multi burst stream but with a shorter burst ( less 2 ms ) and + higher ibg (2 ms) , one milli for each side + */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 2); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->set_pps(1000); + stream->m_isg_usec = 1000 * 1000 + 1000; + stream->set_multi_burst(1000 - 2, 1000, 1000 * 1000 + 2000); + stream->m_pkt.len = 128; + + stream->m_next_stream_id = -1; + + streams.push_back(stream); + + const TrexStreamsGraphObj &obj = graph.generate(streams); + EXPECT_EQ(obj.get_max_pps(), 1000.0); + + EXPECT_EQ(obj.get_max_bps(), (1000 * (128 + 4) * 8)); + + + for (auto stream : streams) { + delete stream; + } +} + +/* stress test */ +#if 0 +TEST_F(basic_stl, graph_generator2) { + std::vector<TrexStream *> streams; + TrexStreamsGraph graph; + TrexStream *stream; + + /* add some multi burst streams */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 1); + stream->m_enabled = true; + stream->m_self_start = true; + stream->m_isg_usec = 100; + + stream->set_pps(20); + stream->set_multi_burst(4918, 321312, 15); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 2); + stream->m_enabled = true; + stream->m_self_start = true; + stream->m_isg_usec = 59281; + + stream->set_pps(30); + stream->set_multi_burst(4918, 51040, 27); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 3); + stream->m_enabled = true; + stream->m_self_start = true; + stream->m_isg_usec = 59281492; + + stream->set_pps(40); + stream->set_multi_burst(4918, 412312, 2917); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + + /* stream 3 */ + stream = new TrexStream(TrexStream::stCONTINUOUS, 0, 4); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->m_isg_usec = 50; + stream->set_pps(30); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 1512; + + streams.push_back(stream); + + + const TrexStreamsGraphObj &obj = graph.generate(streams); + printf("event_count is: %lu, max BPS: %f, max PPS: %f\n", obj.get_events().size(), obj.get_max_bps(), obj.get_max_pps()); + +// for (const TrexStreamsGraphObj::rate_event_st &ev : obj.get_events()) { +// printf("time: %f, diff bps: %f, diff pps: %f\n", ev.time, ev.diff_bps, ev.diff_pps); +// } + + for (auto stream : streams) { + delete stream; + } +} + +#endif /********************************************* Itay Tests End *************************************/ diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index cdd13ed6..d22fda7d 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -463,7 +463,6 @@ trex_rpc_cmd_rc_e TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_byte(params, "port_id", result); - double mul = parse_double(params, "mul", result); double duration = parse_double(params, "duration", result); if (port_id >= get_stateless_obj()->get_port_count()) { @@ -474,8 +473,29 @@ TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + + const Json::Value &mul = parse_object(params, "mul", result); + std::string mul_type = parse_string(mul, "type", result); + + /* dispatch according to type of multiplier */ + try { - port->start_traffic(mul, duration); + if (mul_type == "raw") { + + double m = parse_double(mul, "factor", result); + port->start_traffic(m, duration); + + } else if (mul_type == "max_bps") { + + double max_bps = parse_double(mul, "max", result); + port->start_traffic_max_bps(max_bps, duration); + + } else if (mul_type == "max_pps") { + + double max_pps = parse_double(mul, "max", result); + port->start_traffic_max_pps(max_pps, duration); + } + } catch (const TrexRpcException &ex) { generate_execute_err(result, ex.what()); } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 40392e68..be1bea12 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -111,9 +111,12 @@ TrexStatelessPort::start_traffic(double mul, double duration) { vector<TrexStream *> streams; get_object_list(streams); + /* split it per core */ + double per_core_mul = mul / m_cores_id_list.size(); + /* compiler it */ TrexStreamsCompiler compiler; - TrexStreamsCompiledObj *compiled_obj = new TrexStreamsCompiledObj(m_port_id, mul); + TrexStreamsCompiledObj *compiled_obj = new TrexStreamsCompiledObj(m_port_id, per_core_mul); bool rc = compiler.compile(streams, *compiled_obj); if (!rc) { @@ -136,6 +139,34 @@ TrexStatelessPort::start_traffic(double mul, double duration) { } +void +TrexStatelessPort::start_traffic_max_bps(double max_bps, double duration) { + /* fetch all the streams from the table */ + vector<TrexStream *> streams; + get_object_list(streams); + + TrexStreamsGraph graph; + const TrexStreamsGraphObj &obj = graph.generate(streams); + double m = (max_bps / obj.get_max_bps()); + + /* call the main function */ + start_traffic(m, duration); +} + +void +TrexStatelessPort::start_traffic_max_pps(double max_pps, double duration) { + /* fetch all the streams from the table */ + vector<TrexStream *> streams; + get_object_list(streams); + + TrexStreamsGraph graph; + const TrexStreamsGraphObj &obj = graph.generate(streams); + double m = (max_pps / obj.get_max_pps()); + + /* call the main function */ + start_traffic(m, duration); +} + /** * stop traffic on port * diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 006ec97c..6adb5fef 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -77,6 +77,8 @@ public: * throws TrexException in case of an error */ void start_traffic(double mul, double duration = -1); + void start_traffic_max_bps(double max_bps, double duration = -1); + void start_traffic_max_pps(double max_pps, double duration = -1); /** * stop traffic diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp index 5203b2a2..cad603e2 100644 --- a/src/stateless/cp/trex_stream.cpp +++ b/src/stateless/cp/trex_stream.cpp @@ -21,6 +21,7 @@ limitations under the License. #include <trex_stream.h> #include <cstddef> #include <string.h> +#include <assert.h> /************************************** * stream @@ -129,6 +130,7 @@ TrexStream::get_stream_json() { return m_stream_json; } + /************************************** * stream table *************************************/ diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index 0634829e..3e48d7e4 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -90,7 +90,7 @@ public: m_next_stream_id = next_stream_id; } - double get_pps() { + double get_pps() const { return m_pps; } @@ -150,6 +150,16 @@ public: return (dp); } + + double get_burst_length_usec() const { + return ( (m_burst_total_pkts / m_pps) * 1000 * 1000); + } + + double get_bps() const { + /* packet length + 4 CRC bytes to bits and multiplied by PPS */ + return (m_pps * (m_pkt.len + 4) * 8); + } + void Dump(FILE *fd); public: /* basic */ diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 302863ae..b28989be 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -34,19 +34,25 @@ limitations under the License. */ class GraphNode { public: - GraphNode(TrexStream *stream, GraphNode *next) : m_stream(stream), m_next(next) { - marked = false; + GraphNode(const TrexStream *stream, GraphNode *next) : m_stream(stream), m_next(next) { + m_marked = false; m_compressed_stream_id=-1; + } uint32_t get_stream_id() const { return m_stream->m_stream_id; } + uint32_t get_next_stream_id() const { + return m_stream->m_next_stream_id; + + } + const TrexStream *m_stream; GraphNode *m_next; std::vector<const GraphNode *> m_parents; - bool marked; + bool m_marked; int m_compressed_stream_id; }; @@ -97,13 +103,13 @@ public: void clear_marks() { for (auto node : m_nodes) { - node.second->marked = false; + node.second->m_marked = false; } } void get_unmarked(std::vector <GraphNode *> &unmarked) { for (auto node : m_nodes) { - if (!node.second->marked) { + if (!node.second->m_marked) { unmarked.push_back(node.second); } } @@ -132,6 +138,7 @@ private: GraphNode m_dead_end; }; + /************************************** * stream compiled object *************************************/ @@ -317,11 +324,11 @@ TrexStreamsCompiler::check_for_unreachable_streams(GraphNodeMap *nodes) { /* pull one */ GraphNode *node = next_nodes.back(); next_nodes.pop_back(); - if (node->marked) { + if (node->m_marked) { continue; } - node->marked = true; + node->m_marked = true; if (node->m_next != NULL) { next_nodes.push_back(node->m_next); @@ -427,9 +434,254 @@ TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams, my_stream_id, my_next_stream_id ); + } obj.m_all_continues =all_continues; return true; } +/************************************** + * streams graph + *************************************/ + +/** + * for each stream we create the right rate events (up/down) + * + * @author imarom (24-Nov-15) + * + * @param offset_usec + * @param stream + */ +void +TrexStreamsGraph::add_rate_events_for_stream(double &offset_usec, const TrexStream *stream) { + + switch (stream->get_type()) { + + case TrexStream::stCONTINUOUS: + add_rate_events_for_stream_cont(offset_usec, stream); + return; + + case TrexStream::stSINGLE_BURST: + add_rate_events_for_stream_single_burst(offset_usec, stream); + return; + + case TrexStream::stMULTI_BURST: + add_rate_events_for_stream_multi_burst(offset_usec, stream); + return; + } +} + +/** + * continous stream + * + */ +void +TrexStreamsGraph::add_rate_events_for_stream_cont(double &offset_usec, const TrexStream *stream) { + + TrexStreamsGraphObj::rate_event_st start_event; + + /* for debug purposes */ + start_event.stream_id = stream->m_stream_id; + + start_event.time = offset_usec + stream->m_isg_usec; + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + m_graph_obj.add_rate_event(start_event); + + /* no more events after this stream */ + offset_usec = -1; +} + +/** + * single burst stream + * + */ +void +TrexStreamsGraph::add_rate_events_for_stream_single_burst(double &offset_usec, const TrexStream *stream) { + TrexStreamsGraphObj::rate_event_st start_event; + TrexStreamsGraphObj::rate_event_st stop_event; + + + /* for debug purposes */ + start_event.stream_id = stream->m_stream_id; + stop_event.stream_id = stream->m_stream_id; + + /* start event */ + start_event.time = offset_usec + stream->m_isg_usec; + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + m_graph_obj.add_rate_event(start_event); + + /* stop event */ + stop_event.time = start_event.time + stream->get_burst_length_usec(); + stop_event.diff_pps = -(start_event.diff_pps); + stop_event.diff_bps = -(start_event.diff_bps); + m_graph_obj.add_rate_event(stop_event); + + /* next stream starts from here */ + offset_usec = stop_event.time; + +} + +/** + * multi burst stream + * + */ +void +TrexStreamsGraph::add_rate_events_for_stream_multi_burst(double &offset_usec, const TrexStream *stream) { + TrexStreamsGraphObj::rate_event_st start_event; + TrexStreamsGraphObj::rate_event_st stop_event; + + /* first the delay is the inter stream gap */ + double delay = stream->m_isg_usec; + + /* for debug purposes */ + + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + start_event.stream_id = stream->m_stream_id; + + stop_event.diff_pps = -(start_event.diff_pps); + stop_event.diff_bps = -(start_event.diff_bps); + stop_event.stream_id = stream->m_stream_id; + + /* for each burst create up/down events */ + for (int i = 0; i < stream->m_num_bursts; i++) { + + start_event.time = offset_usec + delay; + m_graph_obj.add_rate_event(start_event); + + stop_event.time = start_event.time + stream->get_burst_length_usec(); + m_graph_obj.add_rate_event(stop_event); + + /* after the first burst, the delay is inter burst gap */ + delay = stream->m_ibg_usec; + + offset_usec = stop_event.time; + } +} + +/** + * for a single root we can until done or a loop detected + * + * @author imarom (24-Nov-15) + * + * @param root_stream_id + */ +void +TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) { + + std::unordered_map<uint32_t, bool> loop_hash; + std::stringstream ss; + + uint32_t stream_id = root_stream_id; + double offset = 0; + + while (true) { + const TrexStream *stream; + + /* fetch the stream from the hash - if it is not present, report an error */ + try { + stream = m_streams_hash.at(stream_id); + } catch (const std::out_of_range &e) { + ss << "stream id " << stream_id << " does not exists"; + throw TrexException(ss.str()); + } + + /* add the node to the hash for loop detection */ + loop_hash[stream_id] = true; + + /* create the right rate events for the stream */ + add_rate_events_for_stream(offset, stream); + + /* do we have a next stream ? */ + if (stream->m_next_stream_id == -1) { + break; + } + + /* loop detection */ + auto search = loop_hash.find(stream->m_next_stream_id); + if (search != loop_hash.end()) { + break; + } + + /* handle the next one */ + stream_id = stream->m_next_stream_id; + } +} + +/** + * for a vector of streams generate a graph of BW + * see graph object for more details + * + */ +const TrexStreamsGraphObj & +TrexStreamsGraph::generate(const std::vector<TrexStream *> &streams) { + std::vector <uint32_t> root_streams; + + /* before anything we create a hash streams ID + and grab the root nodes + */ + for (TrexStream *stream : streams) { + + /* skip non enabled streams */ + if (!stream->m_enabled) { + continue; + } + + /* for fast search we populate all the streams in a hash */ + m_streams_hash[stream->m_stream_id] = stream; + + /* hold all the self start nodes in a vector */ + if (stream->m_self_start) { + root_streams.push_back(stream->m_stream_id); + } + } + + /* for each node - scan until done or loop */ + for (uint32_t root_id : root_streams) { + generate_graph_for_one_root(root_id); + } + + + m_graph_obj.generate(); + + return m_graph_obj; +} + +/************************************** + * streams graph object + *************************************/ +void +TrexStreamsGraphObj::find_max_rate() { + double max_rate_pps = 0; + double current_rate_pps = 0; + + double max_rate_bps = 0; + double current_rate_bps = 0; + + /* now we simply walk the list and hold the max */ + for (auto &ev : m_rate_events) { + + current_rate_pps += ev.diff_pps; + current_rate_bps += ev.diff_bps; + + max_rate_pps = std::max(max_rate_pps, current_rate_pps); + max_rate_bps = std::max(max_rate_bps, current_rate_bps); + } + + m_max_pps = max_rate_pps; + m_max_bps = max_rate_bps; +} + +static +bool event_compare (const TrexStreamsGraphObj::rate_event_st &first, const TrexStreamsGraphObj::rate_event_st &second) { + return (first.time < second.time); +} + +void +TrexStreamsGraphObj::generate() { + m_rate_events.sort(event_compare); + find_max_rate(); +} diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 17ca3c74..70a31c5e 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -23,7 +23,9 @@ limitations under the License. #include <stdint.h> #include <vector> +#include <list> #include <string> +#include <unordered_map> class TrexStreamsCompiler; class TrexStream; @@ -114,6 +116,91 @@ private: void err(const std::string &err); std::vector<std::string> m_warnings; + +}; + +class TrexStreamsGraph; + +/************************************** + * streams graph object + * + * holds the step graph for bandwidth + *************************************/ +class TrexStreamsGraphObj { + friend class TrexStreamsGraph; + +public: + + /** + * rate event is defined by those: + * time - the time of the event on the timeline + * diff - what is the nature of the change ? + * + * @author imarom (23-Nov-15) + */ + struct rate_event_st { + double time; + double diff_pps; + double diff_bps; + uint32_t stream_id; + }; + + double get_max_pps() const { + return m_max_pps; + } + + double get_max_bps() const { + return m_max_bps; + } + + const std::list<rate_event_st> & get_events() const { + return m_rate_events; + } + +private: + + void add_rate_event(const rate_event_st &ev) { + m_rate_events.push_back(ev); + } + + void generate(); + void find_max_rate(); + + double m_max_pps; + double m_max_bps; + + /* list of rate events */ + std::list<rate_event_st> m_rate_events; +}; + +/** + * graph creator + * + * @author imarom (23-Nov-15) + */ +class TrexStreamsGraph { +public: + + /** + * generate a sequence graph for streams + * + */ + const TrexStreamsGraphObj & generate(const std::vector<TrexStream *> &streams); + +private: + + void generate_graph_for_one_root(uint32_t root_stream_id); + + void add_rate_events_for_stream(double &offset, const TrexStream *stream); + void add_rate_events_for_stream_cont(double &offset_usec, const TrexStream *stream); + void add_rate_events_for_stream_single_burst(double &offset_usec, const TrexStream *stream); + void add_rate_events_for_stream_multi_burst(double &offset_usec, const TrexStream *stream); + + /* for fast processing of streams */ + std::unordered_map<uint32_t, const TrexStream *> m_streams_hash; + + /* main object to hold the graph - returned to the user */ + TrexStreamsGraphObj m_graph_obj; }; #endif /* __TREX_STREAMS_COMPILER_H__ */ |