summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHanoh Haim <hhaim@cisco.com>2016-06-02 10:11:17 +0300
committerHanoh Haim <hhaim@cisco.com>2016-06-02 10:11:17 +0300
commit9543174af7480c1ed46384ee60ae59f01995323d (patch)
treeab8acc63cbaf204b77b0851d1c6f209a52fd336c
parent5d9c9f449b98b43c736cc5908a21babac58c6428 (diff)
parent9f2cbf6d028aed1bc471b27b61c928c82b36ac9a (diff)
Merge readme
-rw-r--r--scripts/stl/flow_stats_latency.py4
-rwxr-xr-xsrc/bp_gtest.cpp18
-rw-r--r--src/main_dpdk.cpp103
-rwxr-xr-xsrc/time_histogram.cpp14
-rwxr-xr-xsrc/time_histogram.h4
5 files changed, 91 insertions, 52 deletions
diff --git a/scripts/stl/flow_stats_latency.py b/scripts/stl/flow_stats_latency.py
index 334406e5..e1541272 100644
--- a/scripts/stl/flow_stats_latency.py
+++ b/scripts/stl/flow_stats_latency.py
@@ -9,11 +9,11 @@ class STLS1(object):
def get_streams (self, direction = 0, **kwargs):
return [STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_64B_no_crc.pcap")), # path relative to pwd
mode = STLTXCont(pps=1000),
- flow_stats = STLFlowLatencyStats(pg_id = 7)),
+ flow_stats = STLFlowLatencyStats(pg_id = 1 + kwargs['port_id'])),
STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_594B_no_crc.pcap")), # path relative to pwd
mode = STLTXCont(pps=5000),
- flow_stats = STLFlowLatencyStats(pg_id = 12))
+ flow_stats = STLFlowLatencyStats(pg_id = 50 + kwargs['port_id']))
]
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 7bb3da0c..86b7821b 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -2657,19 +2657,17 @@ public:
TEST_F(time_histogram, test_average) {
int i;
int j;
- // Latency is calculated by low pass filter, so need to give it time to stabilize
- for (j=0; j < 13; j++) {
- for (i=0; i<100; i++) {
- m_hist.Add(10e-6);
- }
- for (i=0; i<100; i++) {
- m_hist.Add(10e-3);
+ for (j = 0; j < 10; j++) {
+ for (i = 0; i <= 2000; i++) {
+ m_hist.Add(10e-7 * i);
}
m_hist.update();
+ // Latency is calculated using low pass filter, with initial value of 0
+ EXPECT_EQ(m_hist.get_average_latency(), 1000.0 - (1000.0 / (2 << j)));
+ EXPECT_EQ(m_hist.get_count(), 2001 * (j+1));
+ EXPECT_EQ(m_hist.get_high_count(), 2001 * (j+1) - (11 * (j+1)));
+ EXPECT_EQ(m_hist.get_max_latency(), 2000);
}
-
- EXPECT_GT(m_hist.get_average_latency(), 5004);
- EXPECT_LT(m_hist.get_average_latency(), 5005);
m_hist.Dump(stdout);
}
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index ca5664d7..bd3cac64 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -80,7 +80,6 @@ extern "C" {
#define SOCKET0 0
-#define BP_MAX_PKT 32
#define MAX_PKT_BURST 32
#define BP_MAX_CORES 32
@@ -1698,7 +1697,8 @@ public:
}
m_port=0;
}
- uint16_t m_tx_queue_id;
+ uint8_t m_tx_queue_id;
+ uint8_t m_tx_queue_id_lat; // q id for tx of latency pkts
uint16_t m_len;
rte_mbuf_t * m_table[MAX_PKT_BURST];
CPhyEthIF * m_port;
@@ -1710,6 +1710,10 @@ public:
/* per core/gbe queue port for trasmitt */
class CCoreEthIF : public CVirtualIF {
+public:
+ enum {
+ INVALID_Q_ID = 255
+ };
public:
@@ -1717,13 +1721,12 @@ public:
m_mbuf_cache=0;
}
-public:
bool Create(uint8_t core_id,
- uint16_t tx_client_queue_id,
+ uint8_t tx_client_queue_id,
CPhyEthIF * tx_client_port,
-
- uint16_t tx_server_queue_id,
- CPhyEthIF * tx_server_port);
+ uint8_t tx_server_queue_id,
+ CPhyEthIF * tx_server_port,
+ uint8_t tx_q_id_lat);
void Delete();
virtual int open_file(std::string file_name){
@@ -1749,8 +1752,6 @@ public:
virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p);
virtual pkt_dir_t port_id_to_dir(uint8_t port_id);
-
-public:
void GetCoreCounters(CVirtualIFPerSideStats *stats);
void DumpCoreStats(FILE *fd);
void DumpIfStats(FILE *fd);
@@ -1773,8 +1774,9 @@ protected:
int send_pkt(CCorePerPort * lp_port,
rte_mbuf_t *m,
CVirtualIFPerSideStats * lp_stats);
-
-
+ int send_pkt_lat(CCorePerPort * lp_port,
+ rte_mbuf_t *m,
+ CVirtualIFPerSideStats * lp_stats);
protected:
uint8_t m_core_id;
@@ -1795,16 +1797,17 @@ protected:
};
bool CCoreEthIF::Create(uint8_t core_id,
- uint16_t tx_client_queue_id,
+ uint8_t tx_client_queue_id,
CPhyEthIF * tx_client_port,
-
- uint16_t tx_server_queue_id,
- CPhyEthIF * tx_server_port){
+ uint8_t tx_server_queue_id,
+ CPhyEthIF * tx_server_port,
+ uint8_t tx_q_id_lat ) {
m_ports[CLIENT_SIDE].m_tx_queue_id = tx_client_queue_id;
m_ports[CLIENT_SIDE].m_port = tx_client_port;
-
+ m_ports[CLIENT_SIDE].m_tx_queue_id_lat = tx_q_id_lat;
m_ports[SERVER_SIDE].m_tx_queue_id = tx_server_queue_id;
m_ports[SERVER_SIDE].m_port = tx_server_port;
+ m_ports[SERVER_SIDE].m_tx_queue_id_lat = tx_q_id_lat;
m_core_id = core_id;
CMessagingManager * rx_dp=CMsgIns::Ins()->getRxDp();
@@ -1892,16 +1895,17 @@ void CCoreEthIF::DumpCoreStats(FILE *fd){
}
void CCoreEthIF::DumpIfCfgHeader(FILE *fd){
- fprintf (fd," core , c-port, c-queue , s-port, s-queue \n");
+ fprintf (fd," core, c-port, c-queue, s-port, s-queue, lat-queue\n");
fprintf (fd," ------------------------------------------\n");
}
void CCoreEthIF::DumpIfCfg(FILE *fd){
- fprintf (fd," %d, %u , %u , %u , %u \n",m_core_id,
+ fprintf (fd," %d %6u %6u %6u %6u %6u \n",m_core_id,
m_ports[CLIENT_SIDE].m_port->get_port_id(),
m_ports[CLIENT_SIDE].m_tx_queue_id,
m_ports[SERVER_SIDE].m_port->get_port_id(),
- m_ports[SERVER_SIDE].m_tx_queue_id
+ m_ports[SERVER_SIDE].m_tx_queue_id,
+ m_ports[SERVER_SIDE].m_tx_queue_id_lat
);
}
@@ -1933,17 +1937,14 @@ int CCoreEthIF::send_burst(CCorePerPort * lp_port,
#ifdef DELAY_IF_NEEDED
while ( unlikely( ret<len ) ){
rte_delay_us(1);
- //rte_pause();
- //rte_pause();
lp_stats->m_tx_queue_full += 1;
uint16_t ret1=lp_port->m_port->tx_burst(lp_port->m_tx_queue_id,
&lp_port->m_table[ret],
len-ret);
ret+=ret1;
}
-#endif
-
- /* CPU has burst of packets , more that TX can send need to drop them !!*/
+#else
+ /* CPU has burst of packets larger than TX can send. Need to drop packets */
if ( unlikely(ret < len) ) {
lp_stats->m_tx_drop += (len-ret);
uint16_t i;
@@ -1952,6 +1953,7 @@ int CCoreEthIF::send_burst(CCorePerPort * lp_port,
rte_pktmbuf_free(m);
}
}
+#endif
return (0);
}
@@ -1975,7 +1977,20 @@ int CCoreEthIF::send_pkt(CCorePerPort * lp_port,
return (0);
}
+int CCoreEthIF::send_pkt_lat(CCorePerPort *lp_port, rte_mbuf_t *m, CVirtualIFPerSideStats *lp_stats) {
+ // We allow sending only from first core of each port. This is serious internal bug otherwise.
+ assert(lp_port->m_tx_queue_id_lat != INVALID_Q_ID);
+
+ int ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id_lat, &m, 1);
+
+ while ( unlikely( ret != 1 ) ){
+ rte_delay_us(1);
+ lp_stats->m_tx_queue_full += 1;
+ ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id_lat, &m, 1);
+ }
+ return ret;
+}
void CCoreEthIF::send_one_pkt(pkt_dir_t dir,
rte_mbuf_t *m){
@@ -2021,7 +2036,6 @@ int CCoreEthIFStateless::send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * no
struct flow_stat_payload_header *fsp_head = NULL;
if (hw_id >= MAX_FLOW_STATS) {
- flush_tx_queue();
// payload rule hw_ids are in the range right above ip id rules
uint16_t hw_id_payload = hw_id - MAX_FLOW_STATS;
if (hw_id_payload > max_stat_hw_id_seen_payload) {
@@ -2055,8 +2069,7 @@ int CCoreEthIFStateless::send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * no
if (hw_id >= MAX_FLOW_STATS) {
fsp_head->time_stamp = os_get_hr_tick_64();
- send_pkt(lp_port, mi, lp_stats);
- flush_tx_queue();
+ send_pkt_lat(lp_port, mi, lp_stats);
} else {
send_pkt(lp_port, mi, lp_stats);
}
@@ -2093,7 +2106,8 @@ int CCoreEthIFStateless::send_node(CGenNode * no) {
}
if (unlikely(node_sl->is_stat_needed())) {
- return send_node_flow_stat(m, node_sl, lp_port, lp_stats, (node_sl->get_cache_mbuf() || node_sl->is_cache_mbuf_array())? true:false);
+ return send_node_flow_stat(m, node_sl, lp_port, lp_stats,
+ (node_sl->get_cache_mbuf() || node_sl->is_cache_mbuf_array())? true:false);
} else {
send_pkt(lp_port,m,lp_stats);
}
@@ -2118,7 +2132,7 @@ int CCoreEthIFStateless::send_pcap_node(CGenNodePCAP *pcap_node) {
/**
* slow path code goes here
- *
+ *
*/
int CCoreEthIFStateless::handle_slow_path_node(CGenNode * no) {
@@ -3164,6 +3178,13 @@ int CGlobalTRex::ixgbe_start(void){
*/
int port_offset=0;
+ uint8_t lat_q_id;
+
+ if ( get_vm_one_queue_enable() ) {
+ lat_q_id = 0;
+ } else {
+ lat_q_id = get_cores_tx() / get_base_num_cores();
+ }
for (i=0; i<get_cores_tx(); i++) {
int j=(i+1);
int queue_id=((j-1)/get_base_num_cores() ); /* for the first min core queue 0 , then queue 1 etc */
@@ -3176,11 +3197,13 @@ int CGlobalTRex::ixgbe_start(void){
queue_id,
&m_ports[port_offset], /* 0,2*/
queue_id,
- &m_ports[port_offset+1] /*1,3*/
- );
+ &m_ports[port_offset+1], /*1,3*/
+ lat_q_id);
port_offset+=2;
if (port_offset == m_max_ports) {
port_offset = 0;
+ // We want to allow sending latency packets only from first core handling a port
+ lat_q_id = CCoreEthIF::INVALID_Q_ID;
}
}
@@ -3923,7 +3946,7 @@ CGlobalTRex::handle_fast_path() {
check_for_dp_messages();
// update CPU%
m_fl.UpdateFast();
-
+
if (get_is_stateless()) {
m_rx_sl.update_cpu_util();
}else{
@@ -3933,7 +3956,7 @@ CGlobalTRex::handle_fast_path() {
if ( is_all_cores_finished() ) {
return false;
}
-
+
return true;
}
@@ -3966,8 +3989,8 @@ int CGlobalTRex::run_in_master() {
}
slow_path_counter = 0;
}
-
-
+
+
cp_lock.unlock();
delay(FASTPATH_DELAY_MS);
slow_path_counter += FASTPATH_DELAY_MS;
@@ -4281,6 +4304,16 @@ bool CCoreEthIF::process_rx_pkt(pkt_dir_t dir,
// In stateless RX, we only care about flow stat packets
if ((parser.getIpId() & 0xff00) == IP_ID_RESERVE_BASE) {
send = true;
+ if (parser.getIpId() == FLOW_STAT_PAYLOAD_IP_ID) {
+ // e1000 on ESXI appends 4 bytes to the packet.
+ // This is a best effort hack to get our latency info which we put at the end of the packet
+ uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*);
+ struct flow_stat_payload_header *fsp_head = (struct flow_stat_payload_header *)
+ (p + m->pkt_len - sizeof(struct flow_stat_payload_header));
+ if (fsp_head->magic != FLOW_STAT_PAYLOAD_MAGIC) {
+ rte_pktmbuf_trim(m, 4);
+ }
+ }
}
} else {
CLatencyPktMode *c_l_pkt_mode = g_trex.m_mg.c_l_pkt_mode;
diff --git a/src/time_histogram.cpp b/src/time_histogram.cpp
index dd15c4be..8a92cb6f 100755
--- a/src/time_histogram.cpp
+++ b/src/time_histogram.cpp
@@ -30,6 +30,8 @@ void CTimeHistogram::Reset() {
m_period_data[0].reset();
m_period_data[1].reset();
m_period = 0;
+ m_total_cnt = 0;
+ m_total_cnt_high = 0;
m_max_dt = 0;
m_average = 0;
memset(&m_max_ar[0],0,sizeof(m_max_ar));
@@ -57,6 +59,9 @@ bool CTimeHistogram::Add(dsec_t dt) {
CTimeHistogramPerPeriodData &period_elem = m_period_data[m_period];
period_elem.inc_cnt();
+ period_elem.update_sum(dt);
+
+ // values smaller then certain threshold do not get into the histogram
if (dt < m_min_delta) {
return false;
}
@@ -87,8 +92,6 @@ bool CTimeHistogram::Add(dsec_t dt) {
}
}
- period_elem.update_sum(dt);
-
return true;
}
@@ -113,6 +116,8 @@ void CTimeHistogram::update() {
m_win_cnt = 0;
}
update_average(period_elem);
+ m_total_cnt += period_elem.get_cnt();
+ m_total_cnt_high += period_elem.get_high_cnt();
}
void CTimeHistogram::update_average(CTimeHistogramPerPeriodData &period_elem) {
@@ -181,7 +186,6 @@ void CTimeHistogram::Dump(FILE *fd) {
*/
void CTimeHistogram::dump_json(std::string name,std::string & json ) {
- CTimeHistogramPerPeriodData &period_elem = m_period_data[get_read_period_index()];
char buff[200];
if (name != "")
sprintf(buff,"\"%s\":{",name.c_str());
@@ -191,8 +195,8 @@ void CTimeHistogram::dump_json(std::string name,std::string & json ) {
json += add_json("min_usec", get_usec(m_min_delta));
json += add_json("max_usec", get_usec(m_max_dt));
- json += add_json("high_cnt", period_elem.get_high_cnt());
- json += add_json("cnt", period_elem.get_cnt());
+ json += add_json("high_cnt", m_total_cnt_high);
+ json += add_json("cnt", m_total_cnt);
json+=add_json("s_avg", get_average_latency());
int i;
int j;
diff --git a/src/time_histogram.h b/src/time_histogram.h
index 9bdf2c93..da70e677 100755
--- a/src/time_histogram.h
+++ b/src/time_histogram.h
@@ -85,6 +85,8 @@ public:
return period_elem.get_max_usec();
}
void dump_json(std::string name,std::string & json );
+ uint64_t get_count() {return m_total_cnt;}
+ uint64_t get_high_count() {return m_total_cnt_high;}
private:
uint32_t get_usec(dsec_t d);
@@ -103,6 +105,8 @@ private:
// Each period we switch between the two
CTimeHistogramPerPeriodData m_period_data[2];
uint8_t m_period; // 0 or 1 according to m_period_data element we currently use
+ uint64_t m_total_cnt;
+ uint64_t m_total_cnt_high;
dsec_t m_max_dt; // Total maximum latency
dsec_t m_average; /* moving average */
uint32_t m_win_cnt;