summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gtest/trex_stateless_gtest.cpp175
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp24
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp33
-rw-r--r--src/stateless/cp/trex_stateless_port.h2
-rw-r--r--src/stateless/cp/trex_stream.cpp2
-rw-r--r--src/stateless/cp/trex_stream.h12
-rw-r--r--src/stateless/cp/trex_streams_compiler.cpp266
-rw-r--r--src/stateless/cp/trex_streams_compiler.h87
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 &params, 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 &params, 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__ */