summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHanoh Haim <hhaim@cisco.com>2016-05-10 17:27:07 +0300
committerHanoh Haim <hhaim@cisco.com>2016-05-10 17:27:07 +0300
commit996f2451dba01f534420418eaac2856510682757 (patch)
tree016d58d6e97c0fc22d0577f52b44530f5bf670fb
parent4d319010eaeb17cce9af55ef00feb71a6930c931 (diff)
refactor the schduler to be with minimum TSC instructions
-rwxr-xr-xscripts/t-rex-64-debug-gdb2
-rwxr-xr-xsrc/bp_sim.cpp291
-rwxr-xr-xsrc/bp_sim.h70
-rwxr-xr-xsrc/main.cpp1
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp5
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.h2
6 files changed, 370 insertions, 1 deletions
diff --git a/scripts/t-rex-64-debug-gdb b/scripts/t-rex-64-debug-gdb
index 087afb71..723bfe2f 100755
--- a/scripts/t-rex-64-debug-gdb
+++ b/scripts/t-rex-64-debug-gdb
@@ -1,4 +1,4 @@
#! /bin/bash
export LD_LIBRARY_PATH=`pwd`
-gdb --args ./_t-rex-64-debug $@
+/bin/gdb --args ./_t-rex-64-debug $@
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index 687f51fd..76bd6ec7 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -3570,6 +3570,295 @@ void CNodeGenerator::dump_json(std::string & json){
}
+void CNodeGenerator::add_exit_node(CFlowGenListPerThread * thread,
+ dsec_t max_time){
+
+ if ( max_time > 0 ) {
+ CGenNode *exit_node = thread->create_node();
+ exit_node->m_type = CGenNode::EXIT_SCHED;
+ exit_node->m_time = max_time;
+ add_node(exit_node);
+ }
+}
+
+inline bool CNodeGenerator::handle_stl_node(CGenNode * node,
+ CFlowGenListPerThread * thread){
+ uint8_t type=node->m_type;
+
+ if ( likely( type == CGenNode::STATELESS_PKT ) ) {
+ m_p_queue.pop();
+ CGenNodeStateless *node_sl = (CGenNodeStateless *)node;
+ /* if the stream has been deactivated - end */
+ if ( unlikely( node_sl->is_mask_for_free() ) ) {
+ thread->free_node(node);
+ } else {
+ /* count before handle - node might be destroyed */
+ #ifdef TREX_SIM
+ update_stl_stats(node_sl);
+ #endif
+
+ node_sl->handle(thread);
+
+ #ifdef TREX_SIM
+ if (has_limit_reached()) {
+ thread->m_stateless_dp_info.stop_traffic(node_sl->get_port_id(), false, 0);
+ }
+ #endif
+ }
+ return (true);
+ }
+ return(false);
+}
+
+
+inline bool CNodeGenerator::do_work_stl(CGenNode * node,
+ CFlowGenListPerThread * thread,
+ bool always){
+
+ if ( handle_stl_node(node,thread)){
+ return (false);
+ }else{
+ return (handle_slow_messages(node->m_type,node,thread,always));
+ }
+}
+
+inline bool CNodeGenerator::do_work_both(CGenNode * node,
+ CFlowGenListPerThread * thread,
+ dsec_t d_time,
+ bool always
+ ){
+
+ bool exit_scheduler=false;
+ uint8_t type=node->m_type;
+ bool done;
+
+ if ( handle_stl_node (node,thread) ){
+ }else{
+ if ( likely( type == CGenNode::FLOW_PKT ) ) {
+ /* PKT */
+ if ( !(node->is_repeat_flow()) || (always==false)) {
+ flush_one_node_to_file(node);
+ #ifdef _DEBUG
+ update_stats(node);
+ #endif
+ }
+ m_p_queue.pop();
+ if ( node->is_last_in_flow() ) {
+ if ((node->is_repeat_flow()) && (always==false)) {
+ /* Flow is repeated, reschedule it */
+ thread->reschedule_flow( node);
+ }else{
+ /* Flow will not be repeated, so free node */
+ thread->free_last_flow_node( node);
+ }
+ }else{
+ node->update_next_pkt_in_flow();
+ m_p_queue.push(node);
+ }
+ }else{
+ if ((type == CGenNode::FLOW_FIF)) {
+ /* callback to our method */
+ m_p_queue.pop();
+ if ( always == false) {
+ thread->m_cur_time_sec = node->m_time ;
+
+ thread->generate_flows_roundrobin(&done);
+
+ if (!done) {
+ node->m_time +=d_time;
+ m_p_queue.push(node);
+ }else{
+ thread->free_node(node);
+ }
+ }else{
+ thread->free_node(node);
+ }
+
+ }else{
+ exit_scheduler = handle_slow_messages(type,node,thread,always);
+ }
+ }
+ }
+
+ return (exit_scheduler);
+}
+
+
+
+template<int SCH_MODE>
+inline bool CNodeGenerator::do_work(CGenNode * node,
+ CFlowGenListPerThread * thread,
+ dsec_t d_time,
+ bool always
+ ){
+ /* template filter in compile time */
+ if ( SCH_MODE == smSTATELESS ) {
+ return ( do_work_stl(node,thread,always) );
+ }else{
+ /* smSTATEFUL */
+ return ( do_work_both(node,thread,d_time,always) );
+ }
+}
+
+
+inline void CNodeGenerator::do_sleep(dsec_t & cur_time,
+ CFlowGenListPerThread * thread,
+ dsec_t n_time){
+ thread->m_cpu_dp_u.commit1();
+ dsec_t dt;
+
+ /* TBD make this better using calculation, minimum now_sec() */
+ while ( true ) {
+ cur_time = now_sec();
+ dt = cur_time - n_time ;
+
+ if (dt> WAIT_WINDOW_SIZE ) {
+ break;
+ }
+
+ rte_pause();
+ }
+
+ thread->m_cpu_dp_u.start_work1();
+}
+
+
+inline int CNodeGenerator::teardown(CFlowGenListPerThread * thread,
+ bool always,
+ double &old_offset,
+ double offset){
+ /* to do */
+ if ( thread->is_terminated_by_master() ) {
+ return (0);
+ }
+
+ if (!always) {
+ old_offset =offset;
+ }else{
+ // free the left other
+ thread->handler_defer_job_flush();
+ }
+ return (0);
+}
+
+
+
+template<int SCH_MODE>
+inline int CNodeGenerator::flush_file_realtime(dsec_t max_time,
+ dsec_t d_time,
+ bool always,
+ CFlowGenListPerThread * thread,
+ double &old_offset){
+ CGenNode * node;
+ dsec_t offset=0.0;
+ dsec_t cur_time;
+ dsec_t n_time;
+ if (always) {
+ offset=old_offset;
+ }else{
+ add_exit_node(thread,max_time);
+ }
+
+ thread->m_cpu_dp_u.start_work1();
+
+ sch_state_t state = scINIT;
+ node = m_p_queue.top();
+ n_time = node->m_time + offset;
+ cur_time = now_sec();
+
+ while (state!=scTERMINATE) {
+
+ switch (state) {
+ case scINIT:
+ cur_time = now_sec();
+ {
+ dsec_t dt = cur_time - n_time ;
+ if (dt>0) {
+ state=scWORK;
+ if (dt > BURST_OFFSET_DTIME) {
+ offset += dt;
+ }
+ }else{
+ state=scWAIT;
+ }
+ } ;
+ break;
+ case scWORK:
+ do {
+ bool s=do_work<SCH_MODE>(node,thread,d_time,always);
+ if (s) { // can we remove this IF ?
+ state=scTERMINATE;
+ break;
+ }
+ node = m_p_queue.top();
+ n_time = node->m_time + offset;
+
+ if ((n_time-cur_time)>EAT_WINDOW_DTIME) {
+ state=scINIT;
+ break;
+ }
+ } while ( true );
+ break;
+
+ case scWAIT:
+ do_sleep(cur_time,thread,n_time); // estimate loop
+ state=scWORK;
+ break;
+ default:
+ assert(0);
+ } /* switch */
+ }/* while*/
+
+ return (teardown(thread,always,old_offset,offset));
+}
+
+FORCE_NO_INLINE int CNodeGenerator::flush_file_sim(dsec_t max_time,
+ dsec_t d_time,
+ bool always,
+ CFlowGenListPerThread * thread,
+ double &old_offset){
+ CGenNode * node;
+
+ if (!always) {
+ add_exit_node(thread,max_time);
+ }
+
+ while (true) {
+ node = m_p_queue.top();
+
+ bool do_exit;
+ if ( get_is_stateless() ) {
+ do_exit=do_work<smSTATELESS>(node,thread,d_time,always);
+ }else{
+ do_exit=do_work<smSTATEFUL>(node,thread,d_time,always);
+ }
+ if ( do_exit ){
+ break;
+ }
+ }
+ return (teardown(thread,always,old_offset,0));
+}
+
+int CNodeGenerator::flush_file(dsec_t max_time,
+ dsec_t d_time,
+ bool always,
+ CFlowGenListPerThread * thread,
+ double &old_offset){
+ #ifdef TREX_SIM
+ return ( flush_file_sim(max_time, d_time,always,thread,old_offset) );
+ #else
+ if ( get_is_stateless() ) {
+ return ( flush_file_realtime<smSTATELESS>(max_time, d_time,always,thread,old_offset) );
+ }else{
+ return ( flush_file_realtime<smSTATEFUL>(max_time, d_time,always,thread,old_offset) );
+ }
+
+ #endif
+}
+
+
+
+#if 0
int CNodeGenerator::flush_file(dsec_t max_time,
dsec_t d_time,
bool always,
@@ -3748,6 +4037,8 @@ int CNodeGenerator::flush_file(dsec_t max_time,
return (0);
}
+#endif
+
bool
CNodeGenerator::handle_slow_messages(uint8_t type,
CGenNode * node,
diff --git a/src/bp_sim.h b/src/bp_sim.h
index c077b0b9..0a7e8bda 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -64,6 +64,7 @@ limitations under the License.
#undef NAT_TRACE_
#define FORCE_NO_INLINE __attribute__ ((noinline))
+#define FORCE_INLINE __attribute__((always_inline))
/* IP address, last 32-bits of IPv6 remaps IPv4 */
typedef struct {
@@ -1402,6 +1403,9 @@ std::string double_to_human_str(double num,
class CCapFileFlowInfo ;
#define SYNC_TIME_OUT ( 1.0/1000)
+
+//#define SYNC_TIME_OUT ( 2000.0/1000)
+
/* this is a simple struct, do not add constructor and destractor here!
we are optimizing the allocation dealocation !!!
*/
@@ -1956,8 +1960,26 @@ public:
};
+
+
+
class CNodeGenerator {
public:
+
+ typedef enum { scINIT = 0x17,
+ scWORK ,
+ scWAIT ,
+ scTERMINATE
+ } sch_state_t;
+
+ typedef enum { smSTATELESS = 0x17,
+ smSTATEFUL ,
+ } sch_mode_t;
+
+ #define BURST_OFFSET_DTIME (100.0/1000000)
+ #define EAT_WINDOW_DTIME (15.0/1000000)
+ #define WAIT_WINDOW_SIZE (-1.0/1000000)
+
bool Create(CFlowGenListPerThread * parent);
void Delete();
@@ -2018,6 +2040,52 @@ private:
CFlowGenListPerThread * thread,
bool always);
+private:
+ void add_exit_node(CFlowGenListPerThread * thread,
+ dsec_t max_time);
+
+ inline bool handle_stl_node(CGenNode * node,
+ CFlowGenListPerThread * thread);
+
+
+ FORCE_INLINE bool do_work_stl(CGenNode * node,
+ CFlowGenListPerThread * thread,
+ bool always);
+
+ FORCE_INLINE bool do_work_both(CGenNode * node,
+ CFlowGenListPerThread * thread,
+ dsec_t d_time,
+ bool always);
+
+ template<int SCH_MODE>
+ FORCE_INLINE bool do_work(CGenNode * node,
+ CFlowGenListPerThread * thread,
+ dsec_t d_time,
+ bool always);
+
+ FORCE_INLINE void do_sleep(dsec_t & cur_time,
+ CFlowGenListPerThread * thread,
+ dsec_t ntime);
+
+
+ FORCE_INLINE int teardown(CFlowGenListPerThread * thread,
+ bool always,
+ double &old_offset,
+ double offset);
+
+ template<int SCH_MODE>
+ int flush_file_realtime(dsec_t max_time,
+ dsec_t d_time,
+ bool always,
+ CFlowGenListPerThread * thread,
+ double &old_offset);
+
+ int flush_file_sim(dsec_t max_time,
+ dsec_t d_time,
+ bool always,
+ CFlowGenListPerThread * thread,
+ double &old_offset);
+
public:
pqueue_t m_p_queue;
@@ -3512,6 +3580,8 @@ private:
class CFlowGenListPerThread {
public:
+
+
friend class CNodeGenerator;
friend class CPluginCallbackSimple;
friend class CCapFileFlowInfo;
diff --git a/src/main.cpp b/src/main.cpp
index 3c68990c..701a65d2 100755
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -261,6 +261,7 @@ void set_stateless_obj(TrexStateless *obj) {
m_sim_statelss_obj = obj;
}
+
int main(int argc , char * argv[]){
std::unordered_map<std::string, int> params;
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp
index 7e9bec1d..13bf5a5d 100644
--- a/src/stateless/dp/trex_stateless_dp_core.cpp
+++ b/src/stateless/dp/trex_stateless_dp_core.cpp
@@ -904,6 +904,11 @@ TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj,
lp_port->m_active_streams = 0;
lp_port->set_event_id(event_id);
+ /* update cur time */
+ if ( CGlobalInfo::is_realtime() ){
+ m_core->m_cur_time_sec = now_sec() + SCHD_OFFSET_DTIME ;
+ }
+
/* no nodes in the list */
assert(lp_port->m_active_nodes.size()==0);
diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h
index cd61b486..bdf84cfd 100644
--- a/src/stateless/dp/trex_stateless_dp_core.h
+++ b/src/stateless/dp/trex_stateless_dp_core.h
@@ -107,6 +107,8 @@ class TrexStatelessDpCore {
public:
+ #define SCHD_OFFSET_DTIME (10.0/1000000.0)
+
/* states */
enum state_e {
STATE_IDLE,