From bb483587479fbf579a53b272749f8bb69711a24d Mon Sep 17 00:00:00 2001 From: Dmytro Podgornyi Date: Mon, 2 Dec 2019 07:30:12 +0000 Subject: [PATCH 1/2] issue: 1897191 Implement extra TCP statistics VMA doesn't provide enough information to investigate TCP bottlenecks. Collect more counters and metrics for a TCP connection and integrate them into vma_stats. This statistics will help to see internals and describe TCP behavior. Signed-off-by: Dmytro Podgornyi --- configure.ac | 14 ++++++ src/stats/stats_data_reader.h | 3 ++ src/stats/stats_printer.cpp | 55 +++++++++++++++++---- src/stats/stats_publisher.cpp | 44 +++++++++++++++-- src/stats/stats_reader.cpp | 92 ++++++++++++++++++++++++++--------- src/vma/lwip/stats.h | 45 +++++++++++++++++ src/vma/lwip/tcp.c | 36 +++++++++++++- src/vma/lwip/tcp.h | 5 ++ src/vma/lwip/tcp_in.c | 14 +++++- src/vma/lwip/tcp_out.c | 23 ++++++++- src/vma/sock/sockinfo_tcp.cpp | 11 +++++ src/vma/util/vma_stats.h | 11 +++++ 12 files changed, 312 insertions(+), 41 deletions(-) diff --git a/configure.ac b/configure.ac index 1df73e287..f7288d818 100644 --- a/configure.ac +++ b/configure.ac @@ -263,6 +263,20 @@ if test ${revision:-0} -ne 0 ; then CXXFLAGS="-DVMA_SVN_REVISION=$revision $CXXFLAGS" fi +# Extra TCP statistics +# +AC_ARG_ENABLE([extra-stats], + AC_HELP_STRING([--enable-extra-stats], + [Enable extra TCP statistics (default=no)])) +AC_MSG_CHECKING( + [for extra TCP statistics support]) +if test "x$enable_extra_stats" = xyes; then + AC_DEFINE_UNQUOTED([DEFINED_EXTRA_STATS], [1], [Define to 1 to provide extra TCP statistics]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + # OFED configuration. # AC_MSG_CHECKING([for OFED path]) diff --git a/src/stats/stats_data_reader.h b/src/stats/stats_data_reader.h index 6f72fede9..f007413bf 100644 --- a/src/stats/stats_data_reader.h +++ b/src/stats/stats_data_reader.h @@ -52,9 +52,12 @@ class stats_data_reader : public timer_handler void handle_timer_expired(void *ctx); void register_to_timer(); void add_data_reader(void* local_addr, void* shm_addr, int size); + void* find_data_reader(void* local_addr); void* pop_data_reader(void* local_addr); private: + void* find_data_reader_unlocked(void* local_addr); + void* m_timer_handler; stats_read_map_t m_data_map; lock_spin m_lock_data_map; diff --git a/src/stats/stats_printer.cpp b/src/stats/stats_printer.cpp index ac0baa73c..e2c5f7bfd 100644 --- a/src/stats/stats_printer.cpp +++ b/src/stats/stats_printer.cpp @@ -79,7 +79,7 @@ void print_full_stats(socket_stats_t* p_si_stats, mc_grp_info_t* p_mc_grp_info, if (!filename) return; - bool b_any_activiy = false; + bool b_any_activity = false; char post_fix[3] = ""; if (user_params.print_details_mode == e_deltas) @@ -143,44 +143,44 @@ void print_full_stats(socket_stats_t* p_si_stats, mc_grp_info_t* p_mc_grp_info, if (p_si_stats->counters.n_tx_sent_byte_count || p_si_stats->counters.n_tx_sent_pkt_count || p_si_stats->counters.n_tx_drops || p_si_stats->counters.n_tx_errors) { fprintf(filename, "Tx Offload: %u / %u / %u / %u [kilobytes/packets/drops/errors]%s\n", p_si_stats->counters.n_tx_sent_byte_count/BYTES_TRAFFIC_UNIT,p_si_stats->counters.n_tx_sent_pkt_count, p_si_stats->counters.n_tx_drops, p_si_stats->counters.n_tx_errors, post_fix); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->counters.n_tx_os_bytes || p_si_stats->counters.n_tx_os_packets || p_si_stats->counters.n_tx_os_eagain || p_si_stats->counters.n_tx_os_errors) { fprintf(filename, "Tx OS info: %u / %u / %u / %u [kilobytes/packets/eagains/errors]%s\n", p_si_stats->counters.n_tx_os_bytes/BYTES_TRAFFIC_UNIT, p_si_stats->counters.n_tx_os_packets, p_si_stats->counters.n_tx_os_eagain, p_si_stats->counters.n_tx_os_errors, post_fix); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->counters.n_tx_dummy) { fprintf(filename, "Tx Dummy messages : %d\n", p_si_stats->counters.n_tx_dummy); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->counters.n_rx_bytes || p_si_stats->counters.n_rx_packets || p_si_stats->counters.n_rx_eagain || p_si_stats->counters.n_rx_errors) { fprintf(filename, "Rx Offload: %u / %u / %u / %u [kilobytes/packets/eagains/errors]%s\n", p_si_stats->counters.n_rx_bytes/BYTES_TRAFFIC_UNIT, p_si_stats->counters.n_rx_packets, p_si_stats->counters.n_rx_eagain, p_si_stats->counters.n_rx_errors, post_fix); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->counters.n_rx_os_bytes || p_si_stats->counters.n_rx_os_packets || p_si_stats->counters.n_rx_os_eagain || p_si_stats->counters.n_rx_os_errors) { fprintf(filename, "Rx OS info: %u / %u / %u / %u [kilobytes/packets/eagains/errors]%s\n", p_si_stats->counters.n_rx_os_bytes/BYTES_TRAFFIC_UNIT, p_si_stats->counters.n_rx_os_packets, p_si_stats->counters.n_rx_os_eagain, p_si_stats->counters.n_rx_os_errors, post_fix); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->counters.n_rx_packets || p_si_stats->n_rx_ready_pkt_count) { fprintf(filename, "Rx byte: cur %u / max %u / dropped%s %u / limit %u\n", p_si_stats->n_rx_ready_byte_count, p_si_stats->counters.n_rx_ready_byte_max, post_fix,p_si_stats->counters.n_rx_ready_byte_drop, p_si_stats->n_rx_ready_byte_limit); fprintf(filename, "Rx pkt : cur %u / max %u / dropped%s %u\n", p_si_stats->n_rx_ready_pkt_count, p_si_stats->counters.n_rx_ready_pkt_max, post_fix,p_si_stats->counters.n_rx_ready_pkt_drop); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->n_rx_zcopy_pkt_count) { fprintf(filename, "Rx zero copy buffers: cur %u\n", p_si_stats->n_rx_zcopy_pkt_count); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->counters.n_rx_poll_miss || p_si_stats->counters.n_rx_poll_hit) { double rx_poll_hit = (double)p_si_stats->counters.n_rx_poll_hit; double rx_poll_hit_percentage = (rx_poll_hit / (rx_poll_hit + (double)p_si_stats->counters.n_rx_poll_miss)) * 100; fprintf(filename, "Rx poll: %u / %u (%2.2f%%) [miss/hit]\n", p_si_stats->counters.n_rx_poll_miss, p_si_stats->counters.n_rx_poll_hit, rx_poll_hit_percentage); - b_any_activiy = true; + b_any_activity = true; } if (p_si_stats->counters.n_rx_migrations || p_si_stats->counters.n_tx_migrations) @@ -193,9 +193,44 @@ void print_full_stats(socket_stats_t* p_si_stats, mc_grp_info_t* p_mc_grp_info, fprintf(filename, "Retransmissions: %u\n", p_si_stats->counters.n_tx_retransmits); } - if (b_any_activiy == false) { + if (b_any_activity == false) { fprintf(filename, "Rx and Tx where not active\n"); } + +#ifdef DEFINED_EXTRA_STATS + if (p_si_stats->socket_type == SOCK_STREAM && b_any_activity) { + fprintf(filename, "TCP n_rto: %u\n", p_si_stats->tcp_stats.n_rto); + fprintf(filename, "TCP n_rtx_fast: %u\n", p_si_stats->tcp_stats.n_rtx_fast); + fprintf(filename, "TCP n_rtx_rto: %u\n", p_si_stats->tcp_stats.n_rtx_rto); + fprintf(filename, "TCP n_rtx_ss: %u\n", p_si_stats->tcp_stats.n_rtx_ss); + fprintf(filename, "TCP n_rtx_spurious: %u\n", p_si_stats->tcp_stats.n_rtx_spurious); + fprintf(filename, "TCP n_recovered_fast: %u\n", p_si_stats->tcp_stats.n_recovered_fast); + fprintf(filename, "TCP n_dupacks: %u\n", p_si_stats->tcp_stats.n_dupacks); + fprintf(filename, "TCP n_ofo: %u\n", p_si_stats->tcp_stats.n_ofo); + fprintf(filename, "TCP n_underruns: %u\n", p_si_stats->tcp_stats.n_underruns); + fprintf(filename, "TCP n_blocked_cwnd: %u\n", p_si_stats->tcp_stats.n_blocked_cwnd); + fprintf(filename, "TCP n_blocked_rwnd: %u\n", p_si_stats->tcp_stats.n_blocked_rwnd); + fprintf(filename, "TCP n_blocked_sndbuf: %u\n", p_si_stats->tcp_stats.n_blocked_sndbuf); + fprintf(filename, "TCP n_updates_rtt: %u\n", p_si_stats->tcp_stats.n_updates_rtt); + fprintf(filename, "TCP n_rst: %u\n", p_si_stats->tcp_stats.n_rst); + fprintf(filename, "TCP --------------------------------\n"); + fprintf(filename, "TCP n_rx_ignored: %u\n", p_si_stats->tcp_stats.n_rx_ignored); + fprintf(filename, "TCP n_dropped: %u\n", p_si_stats->tcp_stats.n_dropped); + fprintf(filename, "TCP n_memerr_pbuf: %u\n", p_si_stats->tcp_stats.n_memerr_pbuf); + fprintf(filename, "TCP n_memerr_seg: %u\n", p_si_stats->tcp_stats.n_memerr_seg); + fprintf(filename, "TCP --------------------------------\n"); + fprintf(filename, "TCP n_mss: %u\n", p_si_stats->tcp_stats.n_mss); + fprintf(filename, "TCP n_rto_timer(ms): %u\n", p_si_stats->tcp_stats.n_rto_timer); + fprintf(filename, "TCP n_snd_wnd: %u\n", p_si_stats->tcp_stats.n_snd_wnd); + fprintf(filename, "TCP n_cwnd: %u\n", p_si_stats->tcp_stats.n_cwnd); + fprintf(filename, "TCP n_ssthresh: %u\n", p_si_stats->tcp_stats.n_ssthresh); + fprintf(filename, "TCP n_snd_nxt: %u\n", p_si_stats->tcp_stats.n_snd_nxt); + fprintf(filename, "TCP n_lastack: %u\n", p_si_stats->tcp_stats.n_lastack); + fprintf(filename, "TCP n_unsent_q: %u\n", p_si_stats->tcp_stats.n_unsent_q); + fprintf(filename, "TCP n_unacked_q: %u\n", p_si_stats->tcp_stats.n_unacked_q); + fprintf(filename, "TCP n_ooseq_q: %u\n", p_si_stats->tcp_stats.n_ooseq_q); + } +#endif /* DEFINED_EXTRA_STATS */ } // Print statistics headers for all sockets - used in case view mode is e_netstat_like diff --git a/src/stats/stats_publisher.cpp b/src/stats/stats_publisher.cpp index 372d24d4b..f910cdd71 100644 --- a/src/stats/stats_publisher.cpp +++ b/src/stats/stats_publisher.cpp @@ -138,13 +138,30 @@ void stats_data_reader::add_data_reader(void* local_addr, void* shm_addr, int si m_lock_data_map.unlock(); } +void* stats_data_reader::find_data_reader_unlocked(void* local_addr) +{ + stats_read_map_t::iterator iter = m_data_map.find(local_addr); + if (iter != m_data_map.end()) {//found + return SHM_DATA_ADDRESS; + } + return NULL; +} + +void* stats_data_reader::find_data_reader(void* local_addr) +{ + void* rv; + m_lock_data_map.lock(); + rv = find_data_reader_unlocked(local_addr); + m_lock_data_map.unlock(); + return rv; +} + void* stats_data_reader::pop_data_reader(void* local_addr) { - void* rv = NULL; + void* rv; m_lock_data_map.lock(); - stats_read_map_t::iterator iter = m_data_map.find(local_addr); - if (iter != m_data_map.end()) {//found - rv = SHM_DATA_ADDRESS; + rv = find_data_reader_unlocked(local_addr); + if (rv) { m_data_map.erase(local_addr); } m_lock_data_map.unlock(); @@ -381,6 +398,25 @@ void vma_stats_instance_remove_socket_block(socket_stats_t* local_addr) g_lock_skt_inst_arr.unlock(); } +#ifdef DEFINED_EXTRA_STATS +void vma_stats_instance_add_tcp(socket_tcp_stats_t* tcp_stats_addr, socket_stats_t* stats_addr) +{ + socket_stats_t* p_skt_stats; + + p_skt_stats = (socket_stats_t*)g_p_stats_data_reader->find_data_reader(stats_addr); + if (p_skt_stats) { + g_p_stats_data_reader->add_data_reader(tcp_stats_addr, + &p_skt_stats->tcp_stats, + sizeof(socket_tcp_stats_t)); + } +} + +void vma_stats_instance_del_tcp(socket_tcp_stats_t* tcp_stats_addr) +{ + (void)g_p_stats_data_reader->pop_data_reader(tcp_stats_addr); +} +#endif /* DEFINED_EXTRA_STATS */ + void vma_stats_mc_group_add(in_addr_t mc_grp, socket_stats_t* p_socket_stats) { int empty_entry = -1; diff --git a/src/stats/stats_reader.cpp b/src/stats/stats_reader.cpp index 3091ed850..e118579d2 100644 --- a/src/stats/stats_reader.cpp +++ b/src/stats/stats_reader.cpp @@ -174,31 +174,36 @@ void usage(const char *argv0) void update_delta_stat(socket_stats_t* p_curr_stat, socket_stats_t* p_prev_stat) { int delay = INTERVAL; - p_prev_stat->counters.n_tx_sent_byte_count = (p_curr_stat->counters.n_tx_sent_byte_count - p_prev_stat->counters.n_tx_sent_byte_count) / delay; - p_prev_stat->counters.n_tx_sent_pkt_count = (p_curr_stat->counters.n_tx_sent_pkt_count - p_prev_stat->counters.n_tx_sent_pkt_count) / delay; - p_prev_stat->counters.n_tx_drops = (p_curr_stat->counters.n_tx_drops - p_prev_stat->counters.n_tx_drops) / delay; - p_prev_stat->counters.n_tx_errors = (p_curr_stat->counters.n_tx_errors - p_prev_stat->counters.n_tx_errors) / delay; - p_prev_stat->counters.n_tx_dummy = (p_curr_stat->counters.n_tx_dummy - p_prev_stat->counters.n_tx_dummy) / delay; - p_prev_stat->counters.n_tx_os_bytes = (p_curr_stat->counters.n_tx_os_bytes - p_prev_stat->counters.n_tx_os_bytes) / delay; - p_prev_stat->counters.n_tx_os_packets = (p_curr_stat->counters.n_tx_os_packets - p_prev_stat->counters.n_tx_os_packets) / delay; - p_prev_stat->counters.n_tx_os_eagain = (p_curr_stat->counters.n_tx_os_eagain - p_prev_stat->counters.n_tx_os_eagain) / delay; - p_prev_stat->counters.n_tx_os_errors = (p_curr_stat->counters.n_tx_os_errors - p_prev_stat->counters.n_tx_os_errors) / delay; - p_prev_stat->counters.n_rx_bytes = (p_curr_stat->counters.n_rx_bytes - p_prev_stat->counters.n_rx_bytes) / delay; - p_prev_stat->counters.n_rx_packets = (p_curr_stat->counters.n_rx_packets - p_prev_stat->counters.n_rx_packets) / delay; - p_prev_stat->counters.n_rx_eagain = (p_curr_stat->counters.n_rx_eagain - p_prev_stat->counters.n_rx_eagain) / delay; - p_prev_stat->counters.n_rx_errors = (p_curr_stat->counters.n_rx_errors - p_prev_stat->counters.n_rx_errors) / delay; - p_prev_stat->counters.n_rx_os_bytes = (p_curr_stat->counters.n_rx_os_bytes - p_prev_stat->counters.n_rx_os_bytes) / delay; - p_prev_stat->counters.n_rx_os_packets = (p_curr_stat->counters.n_rx_os_packets - p_prev_stat->counters.n_rx_os_packets) / delay; - p_prev_stat->counters.n_rx_os_eagain = (p_curr_stat->counters.n_rx_os_eagain - p_prev_stat->counters.n_rx_os_eagain) / delay; - p_prev_stat->counters.n_rx_os_errors = (p_curr_stat->counters.n_rx_os_errors - p_prev_stat->counters.n_rx_os_errors) / delay; - p_prev_stat->counters.n_rx_poll_miss = (p_curr_stat->counters.n_rx_poll_miss - p_prev_stat->counters.n_rx_poll_miss) / delay; - p_prev_stat->counters.n_rx_poll_hit = (p_curr_stat->counters.n_rx_poll_hit - p_prev_stat->counters.n_rx_poll_hit) / delay; + +#define STAT_DELTA(field) p_prev_stat->field = (p_curr_stat->field - p_prev_stat->field) / delay +#define STAT_COUNTERS_DELTA(field) STAT_DELTA(counters.field) +#define STAT_TCP_DELTA(field) STAT_DELTA(tcp_stats.field) + + STAT_COUNTERS_DELTA(n_tx_sent_byte_count); + STAT_COUNTERS_DELTA(n_tx_sent_pkt_count); + STAT_COUNTERS_DELTA(n_tx_drops); + STAT_COUNTERS_DELTA(n_tx_errors); + STAT_COUNTERS_DELTA(n_tx_dummy); + STAT_COUNTERS_DELTA(n_tx_os_bytes); + STAT_COUNTERS_DELTA(n_tx_os_packets); + STAT_COUNTERS_DELTA(n_tx_os_eagain); + STAT_COUNTERS_DELTA(n_tx_os_errors); + STAT_COUNTERS_DELTA(n_rx_bytes); + STAT_COUNTERS_DELTA(n_rx_packets); + STAT_COUNTERS_DELTA(n_rx_eagain); + STAT_COUNTERS_DELTA(n_rx_errors); + STAT_COUNTERS_DELTA(n_rx_os_bytes); + STAT_COUNTERS_DELTA(n_rx_os_packets); + STAT_COUNTERS_DELTA(n_rx_os_eagain); + STAT_COUNTERS_DELTA(n_rx_os_errors); + STAT_COUNTERS_DELTA(n_rx_poll_miss); + STAT_COUNTERS_DELTA(n_rx_poll_hit); p_prev_stat->n_rx_ready_byte_count = p_curr_stat->n_rx_ready_byte_count; p_prev_stat->n_tx_ready_byte_count = p_curr_stat->n_tx_ready_byte_count; p_prev_stat->n_rx_ready_byte_limit = p_curr_stat->n_rx_ready_byte_limit; p_prev_stat->counters.n_rx_ready_byte_max = p_curr_stat->counters.n_rx_ready_byte_max; - p_prev_stat->counters.n_rx_ready_byte_drop = (p_curr_stat->counters.n_rx_ready_byte_drop - p_prev_stat->counters.n_rx_ready_byte_drop) / delay; - p_prev_stat->counters.n_rx_ready_pkt_drop = (p_curr_stat->counters.n_rx_ready_pkt_drop - p_prev_stat->counters.n_rx_ready_pkt_drop) / delay; + STAT_COUNTERS_DELTA(n_rx_ready_byte_drop); + STAT_COUNTERS_DELTA(n_rx_ready_pkt_drop); p_prev_stat->n_rx_ready_pkt_count = p_curr_stat->n_rx_ready_pkt_count; p_prev_stat->counters.n_rx_ready_pkt_max = p_curr_stat->counters.n_rx_ready_pkt_max; p_prev_stat->n_rx_zcopy_pkt_count = p_curr_stat->n_rx_zcopy_pkt_count; @@ -206,9 +211,48 @@ void update_delta_stat(socket_stats_t* p_curr_stat, socket_stats_t* p_prev_stat) p_prev_stat->threadid_last_rx = p_curr_stat->threadid_last_rx; p_prev_stat->threadid_last_tx = p_curr_stat->threadid_last_tx; - p_prev_stat->counters.n_rx_migrations = (p_curr_stat->counters.n_rx_migrations - p_prev_stat->counters.n_rx_migrations) / delay; - p_prev_stat->counters.n_tx_migrations = (p_curr_stat->counters.n_tx_migrations - p_prev_stat->counters.n_tx_migrations) / delay; - p_prev_stat->counters.n_tx_retransmits = (p_curr_stat->counters.n_tx_retransmits - p_prev_stat->counters.n_tx_retransmits) / delay; + STAT_COUNTERS_DELTA(n_rx_migrations); + STAT_COUNTERS_DELTA(n_tx_migrations); + STAT_COUNTERS_DELTA(n_tx_retransmits); + +#ifdef DEFINED_EXTRA_STATS + if (p_curr_stat->socket_type == SOCK_STREAM) { + STAT_TCP_DELTA(n_rto); + STAT_TCP_DELTA(n_rtx_fast); + STAT_TCP_DELTA(n_rtx_rto); + STAT_TCP_DELTA(n_rtx_ss); + STAT_TCP_DELTA(n_rtx_spurious); + STAT_TCP_DELTA(n_recovered_fast); + STAT_TCP_DELTA(n_dupacks); + STAT_TCP_DELTA(n_ofo); + STAT_TCP_DELTA(n_underruns); + STAT_TCP_DELTA(n_blocked_cwnd); + STAT_TCP_DELTA(n_blocked_rwnd); + STAT_TCP_DELTA(n_blocked_sndbuf); + STAT_TCP_DELTA(n_updates_rtt); + STAT_TCP_DELTA(n_rst); + + STAT_TCP_DELTA(n_rx_ignored); + STAT_TCP_DELTA(n_dropped); + STAT_TCP_DELTA(n_memerr_pbuf); + STAT_TCP_DELTA(n_memerr_seg); + + p_prev_stat->tcp_stats.n_mss = p_curr_stat->tcp_stats.n_mss; + p_prev_stat->tcp_stats.n_rto_timer = p_curr_stat->tcp_stats.n_rto_timer; + p_prev_stat->tcp_stats.n_snd_wnd = p_curr_stat->tcp_stats.n_snd_wnd; + p_prev_stat->tcp_stats.n_cwnd = p_curr_stat->tcp_stats.n_cwnd; + p_prev_stat->tcp_stats.n_ssthresh = p_curr_stat->tcp_stats.n_ssthresh; + p_prev_stat->tcp_stats.n_snd_nxt = p_curr_stat->tcp_stats.n_snd_nxt; + p_prev_stat->tcp_stats.n_lastack = p_curr_stat->tcp_stats.n_lastack; + p_prev_stat->tcp_stats.n_unsent_q = p_curr_stat->tcp_stats.n_unsent_q; + p_prev_stat->tcp_stats.n_unacked_q = p_curr_stat->tcp_stats.n_unacked_q; + p_prev_stat->tcp_stats.n_ooseq_q = p_curr_stat->tcp_stats.n_ooseq_q; + } +#endif /* DEFINED_EXTRA_STATS */ + +#undef STAT_TCP_DELTA +#undef STAT_COUNTERS_DELTA +#undef STAT_DELTA } void update_delta_iomux_stat(iomux_func_stats_t* p_curr_stats, iomux_func_stats_t* p_prev_stats) diff --git a/src/vma/lwip/stats.h b/src/vma/lwip/stats.h index 662899165..b2584b3c5 100644 --- a/src/vma/lwip/stats.h +++ b/src/vma/lwip/stats.h @@ -110,6 +110,51 @@ void stats_display_proto(struct stats_proto *proto, char *name); #define stats_display_proto(proto, name) #endif /* LWIP_STATS_DISPLAY */ +#ifdef DEFINED_EXTRA_STATS + +struct socket_tcp_stats { + u32_t n_rto; /* number of RTO */ + u32_t n_rtx_fast; /* fast retransmits */ + u32_t n_rtx_rto; /* retransmits caused by RTO */ + u32_t n_rtx_ss; /* retransmits in slow start phase */ + u32_t n_rtx_spurious; /* number of segments removed from unsent queue */ + u32_t n_recovered_fast; /* recovered after fast retransmit without RTO */ + u32_t n_dupacks; /* duplicate ACKs */ + u32_t n_ofo; /* out of order segments */ + u32_t n_underruns; /* underruns (no segments to send) */ + u32_t n_blocked_cwnd; /* sending blocked by cwnd */ + u32_t n_blocked_rwnd; /* sending blocked by rwnd */ + u32_t n_blocked_sndbuf; /* sending blocked by snd_buf */ + u32_t n_updates_rtt; /* RTT measurements */ + u32_t n_rst; /* RST segments */ + + u32_t n_rx_ignored; /* ignored incoming segments */ + u32_t n_dropped; /* dropped segments due to an error */ + u32_t n_memerr_pbuf; /* pbuf allocation errors */ + u32_t n_memerr_seg; /* segment allocation errors */ + + u32_t n_mss; + u32_t n_rto_timer; + u32_t n_snd_wnd; + u32_t n_cwnd; + u32_t n_ssthresh; + u32_t n_snd_nxt; + u32_t n_lastack; + u32_t n_unsent_q; + u32_t n_unacked_q; + u32_t n_ooseq_q; +}; + +typedef struct socket_tcp_stats socket_tcp_stats_t; + +#define EXTRA_STATS_INC(x) ++x + +#else /* DEFINED_EXTRA_STATS */ +#define EXTRA_STATS_INC(x) do {} while (0) +#endif /* DEFINED_EXTRA_STATS */ + +#define PCB_STATS_INC(x) EXTRA_STATS_INC(pcb->stats.x) + #ifdef __cplusplus } #endif diff --git a/src/vma/lwip/tcp.c b/src/vma/lwip/tcp.c index 72b873056..be3b4af10 100644 --- a/src/vma/lwip/tcp.c +++ b/src/vma/lwip/tcp.c @@ -108,6 +108,35 @@ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; /** Only used for temporary storage. */ struct tcp_pcb *tcp_tmp_pcb; +#ifdef DEFINED_EXTRA_STATS +static void copy_tcp_metrics(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + u32_t n; + + pcb->stats.n_mss = pcb->mss; + pcb->stats.n_rto_timer = pcb->rto * slow_tmr_interval; + pcb->stats.n_snd_wnd = pcb->snd_wnd; + pcb->stats.n_cwnd = pcb->cwnd; + pcb->stats.n_ssthresh = pcb->ssthresh; + pcb->stats.n_snd_nxt = pcb->snd_nxt; + pcb->stats.n_lastack = pcb->lastack; + + for (seg = pcb->unsent, n = 0; seg != NULL; seg = seg->next, ++n); + pcb->stats.n_unsent_q = n; + for (seg = pcb->unacked, n = 0; seg != NULL; seg = seg->next, ++n); + pcb->stats.n_unacked_q = n; + for (seg = pcb->ooseq, n = 0; seg != NULL; seg = seg->next, ++n); + pcb->stats.n_ooseq_q = n; +} +#else /* DEFINED_EXTRA_STATS */ +static void copy_tcp_metrics(struct tcp_pcb *pcb) +{ + /* Do nothing is extra statistics is off. */ + (void)pcb; +} +#endif /* DEFINED_EXTRA_STATS */ + /** * * @param v value to set @@ -132,6 +161,8 @@ tcp_tmr(struct tcp_pcb* pcb) tcp_tmr() is called. */ tcp_slowtmr(pcb); } + + copy_tcp_metrics(pcb); } /** @@ -1087,7 +1118,10 @@ tcp_tx_pbuf_alloc(struct tcp_pcb * pcb, u16_t length, pbuf_type type) // pbuf_alloc is not valid, we should allocate a new pbuf. p = external_tcp_tx_pbuf_alloc(pcb); - if (!p) return NULL; + if (!p) { + PCB_STATS_INC(n_memerr_pbuf); + return NULL; + } p->next = NULL; p->type = type; diff --git a/src/vma/lwip/tcp.h b/src/vma/lwip/tcp.h index 22d8bb79a..2a7fabf0a 100644 --- a/src/vma/lwip/tcp.h +++ b/src/vma/lwip/tcp.h @@ -40,6 +40,7 @@ #include "vma/lwip/pbuf.h" #include "vma/lwip/ip.h" +#include "vma/lwip/stats.h" #ifdef __cplusplus extern "C" { @@ -298,6 +299,10 @@ struct tcp_pcb { #define TF_NAGLEMEMERR ((u16_t)0x0080U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ #define TF_WND_SCALE ((u16_t)0x0100U) /* Window Scale option enabled */ +#ifdef DEFINED_EXTRA_STATS + socket_tcp_stats_t stats; +#endif /* DEFINED_EXTRA_STATS */ + /* the rest of the fields are in host byte order as we have to do some math with them */ /* receiver variables */ diff --git a/src/vma/lwip/tcp_in.c b/src/vma/lwip/tcp_in.c index 4a93c7715..b48209495 100644 --- a/src/vma/lwip/tcp_in.c +++ b/src/vma/lwip/tcp_in.c @@ -120,6 +120,7 @@ L3_level_tcp_input(struct pbuf *p, struct tcp_pcb* pcb) LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", (u16_t)p->tot_len)); TCP_STATS_INC(tcp.lenerr); TCP_STATS_INC(tcp.drop); + PCB_STATS_INC(n_dropped); pbuf_free(p); return; } @@ -132,6 +133,7 @@ L3_level_tcp_input(struct pbuf *p, struct tcp_pcb* pcb) LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); TCP_STATS_INC(tcp.lenerr); TCP_STATS_INC(tcp.drop); + PCB_STATS_INC(n_dropped); pbuf_free(p); return; } @@ -187,7 +189,8 @@ L3_level_tcp_input(struct pbuf *p, struct tcp_pcb* pcb) /* if err == ERR_ABRT, 'pcb' is already deallocated */ /* drop incoming packets, because pcb is "full" */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); - TCP_STATS_INC(tcp.drop);; + TCP_STATS_INC(tcp.drop); + PCB_STATS_INC(n_dropped); pbuf_free(p); return; } @@ -314,6 +317,7 @@ L3_level_tcp_input(struct pbuf *p, struct tcp_pcb* pcb) if (!(TCPH_FLAGS(in_data.tcphdr) & TCP_RST)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); + PCB_STATS_INC(n_dropped); tcp_rst(in_data.ackno, in_data.seqno + in_data.tcplen, in_data.tcphdr->dest, in_data.tcphdr->src, pcb); } @@ -956,6 +960,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) /* Clause 5 */ if (pcb->lastack == in_data->ackno) { found_dupack = 1; + PCB_STATS_INC(n_dupacks); if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) ++pcb->dupacks; if (pcb->dupacks > 3) { @@ -1098,6 +1103,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) pcb->polltmr = 0; } else { /* Out of sequence ACK, didn't really ack anything */ + PCB_STATS_INC(n_rx_ignored); pcb->acked = 0; tcp_send_empty_ack(pcb); } @@ -1130,6 +1136,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) } pcb->snd_queuelen -= pbuf_clen(next->p); tcp_tx_seg_free(pcb, next); + PCB_STATS_INC(n_rtx_spurious); LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u32_t)pcb->snd_queuelen)); if (pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_receive: valid queue length", @@ -1165,6 +1172,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) pcb->sv += m; pcb->rto = (pcb->sa >> 3) + pcb->sv; + PCB_STATS_INC(n_updates_rtt); LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", pcb->rto, pcb->rto * slow_tmr_interval)); @@ -1268,6 +1276,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) /* the whole segment is < rcv_nxt */ /* must be a duplicate of a packet that has already been correctly handled */ + PCB_STATS_INC(n_rx_ignored); LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", in_data->seqno)); tcp_ack_now(pcb); } @@ -1440,6 +1449,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) } else { /* We get here if the incoming segment is out-of-sequence. */ + PCB_STATS_INC(n_ofo); tcp_send_empty_ack(pcb); #if TCP_QUEUE_OOSEQ /* We queue the segment on the ->ooseq queue. */ @@ -1575,6 +1585,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) } } else { /* The incoming segment is not withing the window. */ + PCB_STATS_INC(n_rx_ignored); tcp_send_empty_ack(pcb); } } else { @@ -1583,6 +1594,7 @@ tcp_receive(struct tcp_pcb *pcb, tcp_in_data* in_data) /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ if(!TCP_SEQ_BETWEEN(in_data->seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ + PCB_STATS_INC(n_rx_ignored); tcp_ack_now(pcb); } } diff --git a/src/vma/lwip/tcp_out.c b/src/vma/lwip/tcp_out.c index 5ef12c757..7c4052572 100644 --- a/src/vma/lwip/tcp_out.c +++ b/src/vma/lwip/tcp_out.c @@ -217,6 +217,7 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, if ((seg = external_tcp_seg_alloc(pcb)) == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n")); tcp_tx_pbuf_free(pcb, p); + PCB_STATS_INC(n_memerr_seg); return NULL; } @@ -257,6 +258,7 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n")); TCP_STATS_INC(tcp.err); tcp_tx_seg_free(pcb, seg); + PCB_STATS_INC(n_memerr_seg); return NULL; } seg->tcphdr = (struct tcp_hdr *)seg->p->payload; @@ -1447,6 +1449,15 @@ tcp_output(struct tcp_pcb *pcb) ", wnd %"U32_F"\n",pcb->snd_wnd, pcb->cwnd, wnd )); seg = pcb->unsent; + if (seg == NULL) + PCB_STATS_INC(n_underruns); + else if (seg->seqno - pcb->lastack + seg->len > wnd) { + if (wnd == pcb->snd_wnd) + PCB_STATS_INC(n_blocked_rwnd); + else + PCB_STATS_INC(n_blocked_cwnd); + } + /* If the TF_ACK_NOW flag is set and no data will be sent (either * because the ->unsent queue is empty or because the window does * not allow it), construct an empty ACK segment and send it. @@ -1794,6 +1805,7 @@ tcp_rst(u32_t seqno, u32_t ackno, u16_t local_port, u16_t remote_port, struct tc tcphdr->urgp = 0; TCP_STATS_INC(tcp.xmit); + PCB_STATS_INC(n_rst); /* Send output with hardcoded TTL since we have no access to the pcb */ #if LWIP_TSO if(pcb) pcb->ip_output(p, pcb, 0); @@ -1822,7 +1834,14 @@ tcp_rexmit_rto(struct tcp_pcb *pcb) } /* Move all unacked segments to the head of the unsent queue */ - for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); + for (seg = pcb->unacked; seg->next != NULL; seg = seg->next) { + /* + * If some of these retransmits are removed from the unsent queue, + * they will be counted in n_rtx_spurious. Therefore, actually sent + * retransmits equals to (n_rtx_rto - n_rtx_spurious). + */ + PCB_STATS_INC(n_rtx_rto); + } /* concatenate unsent queue after unacked queue */ seg->next = pcb->unsent; #if TCP_OVERSIZE && TCP_OVERSIZE_DBGCHECK @@ -1838,6 +1857,7 @@ tcp_rexmit_rto(struct tcp_pcb *pcb) /* increment number of retransmissions */ ++pcb->nrtx; + PCB_STATS_INC(n_rto); /* Don't take any RTT measurements after retransmitting. */ pcb->rttest = 0; @@ -1883,6 +1903,7 @@ tcp_rexmit(struct tcp_pcb *pcb) #endif /* TCP_OVERSIZE */ ++pcb->nrtx; + PCB_STATS_INC(n_rtx_fast); /* Don't take any rtt measurements after retransmitting. */ pcb->rttest = 0; diff --git a/src/vma/sock/sockinfo_tcp.cpp b/src/vma/sock/sockinfo_tcp.cpp index 663461b20..3bee271d6 100644 --- a/src/vma/sock/sockinfo_tcp.cpp +++ b/src/vma/sock/sockinfo_tcp.cpp @@ -256,6 +256,10 @@ sockinfo_tcp::sockinfo_tcp(int fd): tcp_pcb_init(&m_pcb, TCP_PRIO_NORMAL); +#ifdef DEFINED_EXTRA_STATS + vma_stats_instance_add_tcp(&m_pcb.stats, m_p_socket_stats); +#endif /* DEFINED_EXTRA_STATS */ + si_tcp_logdbg("new pcb %p pcb state %d", &m_pcb, get_tcp_state(&m_pcb)); tcp_arg(&m_pcb, this); tcp_ip_output(&m_pcb, sockinfo_tcp::ip_output); @@ -329,6 +333,10 @@ sockinfo_tcp::~sockinfo_tcp() prepare_to_close(true); } +#ifdef DEFINED_EXTRA_STATS + vma_stats_instance_del_tcp(&m_pcb.stats); +#endif /* DEFINED_EXTRA_STATS */ + do_wakeup(); destructor_helper(); @@ -846,6 +854,7 @@ ssize_t sockinfo_tcp::tx(vma_tx_call_attr_t &tx_arg) errno = ECONNRESET; goto err; } + EXTRA_STATS_INC(m_pcb.stats.n_blocked_sndbuf); //force out TCP data before going on wait() tcp_output(&m_pcb); @@ -1105,6 +1114,8 @@ err_t sockinfo_tcp::ip_output(struct pbuf *p, void* v_p_conn, int is_rexmit, uin if (is_rexmit) { p_si_tcp->m_p_socket_stats->counters.n_tx_retransmits++; + if (p_si_tcp->m_pcb.cwnd < p_si_tcp->m_pcb.ssthresh) + EXTRA_STATS_INC(p_si_tcp->m_pcb.stats.n_rtx_ss); } return ERR_OK; diff --git a/src/vma/util/vma_stats.h b/src/vma/util/vma_stats.h index 15fba0593..29eac3d64 100644 --- a/src/vma/util/vma_stats.h +++ b/src/vma/util/vma_stats.h @@ -43,6 +43,7 @@ #include #include #include +#include #define NUM_OF_SUPPORTED_CQS 16 #define NUM_OF_SUPPORTED_RINGS 16 @@ -188,6 +189,9 @@ typedef struct { uint32_t n_rx_zcopy_pkt_count; uint32_t n_tx_ready_byte_count; socket_counters_t counters; +#ifdef DEFINED_EXTRA_STATS + socket_tcp_stats_t tcp_stats; +#endif /* DEFINED_EXTRA_STATS */ std::bitset mc_grp_map; ring_logic_t ring_alloc_logic_rx; ring_logic_t ring_alloc_logic_tx; @@ -204,6 +208,9 @@ typedef struct { threadid_last_rx = threadid_last_tx = pid_t(0); n_rx_ready_pkt_count = n_rx_ready_byte_count = n_rx_ready_byte_limit = n_rx_zcopy_pkt_count = n_tx_ready_byte_count = 0; memset(&counters, 0, sizeof(counters)); +#ifdef DEFINED_EXTRA_STATS + memset(&tcp_stats, 0, sizeof(tcp_stats)); +#endif /* DEFINED_EXTRA_STATS */ mc_grp_map.reset(); ring_user_id_rx = ring_user_id_tx = 0; ring_alloc_logic_rx = ring_alloc_logic_tx = RING_LOGIC_PER_INTERFACE; @@ -374,6 +381,10 @@ void vma_shmem_stats_close(); void vma_stats_instance_create_socket_block(socket_stats_t*); void vma_stats_instance_remove_socket_block(socket_stats_t*); +#ifdef DEFINED_EXTRA_STATS +void vma_stats_instance_add_tcp(socket_tcp_stats_t*, socket_stats_t*); +void vma_stats_instance_del_tcp(socket_tcp_stats_t*); +#endif /* DEFINED_EXTRA_STATS */ void vma_stats_mc_group_add(in_addr_t mc_grp, socket_stats_t* p_socket_stats); void vma_stats_mc_group_remove(in_addr_t mc_grp, socket_stats_t* p_socket_stats); From a5243d012528a54e989fbab7b38a9ec29060a2bb Mon Sep 17 00:00:00 2001 From: Dmytro Podgornyi Date: Mon, 2 Dec 2019 15:51:10 +0000 Subject: [PATCH 2/2] issue: 1897191 Improve extra TCP statistics - Revert changes to stats_publisher and stats_data_reader. Instead, modify the stats directly in m_p_socket_stats via a pointer. This saves 1 copy operation per tick. - Move modification of the retransmit counters to a separate private method. The motivation is to reduce copy-paste and create a common execution path for both TSO and no-TSO builds. It won't require to check both builds for test coverage. Signed-off-by: Dmytro Podgornyi --- src/stats/stats_data_reader.h | 3 --- src/stats/stats_printer.cpp | 1 + src/stats/stats_publisher.cpp | 44 ++++------------------------------- src/vma/lwip/stats.h | 2 +- src/vma/lwip/tcp.c | 31 +++++++++++++++--------- src/vma/lwip/tcp.h | 7 +++++- src/vma/sock/sockinfo_tcp.cpp | 26 ++++++++++----------- src/vma/sock/sockinfo_tcp.h | 3 +++ src/vma/util/vma_stats.h | 4 ---- 9 files changed, 48 insertions(+), 73 deletions(-) diff --git a/src/stats/stats_data_reader.h b/src/stats/stats_data_reader.h index f007413bf..6f72fede9 100644 --- a/src/stats/stats_data_reader.h +++ b/src/stats/stats_data_reader.h @@ -52,12 +52,9 @@ class stats_data_reader : public timer_handler void handle_timer_expired(void *ctx); void register_to_timer(); void add_data_reader(void* local_addr, void* shm_addr, int size); - void* find_data_reader(void* local_addr); void* pop_data_reader(void* local_addr); private: - void* find_data_reader_unlocked(void* local_addr); - void* m_timer_handler; stats_read_map_t m_data_map; lock_spin m_lock_data_map; diff --git a/src/stats/stats_printer.cpp b/src/stats/stats_printer.cpp index e2c5f7bfd..a83877397 100644 --- a/src/stats/stats_printer.cpp +++ b/src/stats/stats_printer.cpp @@ -199,6 +199,7 @@ void print_full_stats(socket_stats_t* p_si_stats, mc_grp_info_t* p_mc_grp_info, #ifdef DEFINED_EXTRA_STATS if (p_si_stats->socket_type == SOCK_STREAM && b_any_activity) { + fprintf(filename, "TCP --------------------------------\n"); fprintf(filename, "TCP n_rto: %u\n", p_si_stats->tcp_stats.n_rto); fprintf(filename, "TCP n_rtx_fast: %u\n", p_si_stats->tcp_stats.n_rtx_fast); fprintf(filename, "TCP n_rtx_rto: %u\n", p_si_stats->tcp_stats.n_rtx_rto); diff --git a/src/stats/stats_publisher.cpp b/src/stats/stats_publisher.cpp index f910cdd71..372d24d4b 100644 --- a/src/stats/stats_publisher.cpp +++ b/src/stats/stats_publisher.cpp @@ -138,30 +138,13 @@ void stats_data_reader::add_data_reader(void* local_addr, void* shm_addr, int si m_lock_data_map.unlock(); } -void* stats_data_reader::find_data_reader_unlocked(void* local_addr) -{ - stats_read_map_t::iterator iter = m_data_map.find(local_addr); - if (iter != m_data_map.end()) {//found - return SHM_DATA_ADDRESS; - } - return NULL; -} - -void* stats_data_reader::find_data_reader(void* local_addr) -{ - void* rv; - m_lock_data_map.lock(); - rv = find_data_reader_unlocked(local_addr); - m_lock_data_map.unlock(); - return rv; -} - void* stats_data_reader::pop_data_reader(void* local_addr) { - void* rv; + void* rv = NULL; m_lock_data_map.lock(); - rv = find_data_reader_unlocked(local_addr); - if (rv) { + stats_read_map_t::iterator iter = m_data_map.find(local_addr); + if (iter != m_data_map.end()) {//found + rv = SHM_DATA_ADDRESS; m_data_map.erase(local_addr); } m_lock_data_map.unlock(); @@ -398,25 +381,6 @@ void vma_stats_instance_remove_socket_block(socket_stats_t* local_addr) g_lock_skt_inst_arr.unlock(); } -#ifdef DEFINED_EXTRA_STATS -void vma_stats_instance_add_tcp(socket_tcp_stats_t* tcp_stats_addr, socket_stats_t* stats_addr) -{ - socket_stats_t* p_skt_stats; - - p_skt_stats = (socket_stats_t*)g_p_stats_data_reader->find_data_reader(stats_addr); - if (p_skt_stats) { - g_p_stats_data_reader->add_data_reader(tcp_stats_addr, - &p_skt_stats->tcp_stats, - sizeof(socket_tcp_stats_t)); - } -} - -void vma_stats_instance_del_tcp(socket_tcp_stats_t* tcp_stats_addr) -{ - (void)g_p_stats_data_reader->pop_data_reader(tcp_stats_addr); -} -#endif /* DEFINED_EXTRA_STATS */ - void vma_stats_mc_group_add(in_addr_t mc_grp, socket_stats_t* p_socket_stats) { int empty_entry = -1; diff --git a/src/vma/lwip/stats.h b/src/vma/lwip/stats.h index b2584b3c5..28c9ff771 100644 --- a/src/vma/lwip/stats.h +++ b/src/vma/lwip/stats.h @@ -153,7 +153,7 @@ typedef struct socket_tcp_stats socket_tcp_stats_t; #define EXTRA_STATS_INC(x) do {} while (0) #endif /* DEFINED_EXTRA_STATS */ -#define PCB_STATS_INC(x) EXTRA_STATS_INC(pcb->stats.x) +#define PCB_STATS_INC(x) EXTRA_STATS_INC(pcb->p_stats->x) #ifdef __cplusplus } diff --git a/src/vma/lwip/tcp.c b/src/vma/lwip/tcp.c index be3b4af10..d81e31ce9 100644 --- a/src/vma/lwip/tcp.c +++ b/src/vma/lwip/tcp.c @@ -109,30 +109,39 @@ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; struct tcp_pcb *tcp_tmp_pcb; #ifdef DEFINED_EXTRA_STATS +void register_tcp_stats_instance(struct tcp_pcb *pcb, socket_tcp_stats_t *stats) +{ + pcb->p_stats = stats; +} + static void copy_tcp_metrics(struct tcp_pcb *pcb) { struct tcp_seg *seg; + socket_tcp_stats_t *stats = pcb->p_stats; u32_t n; - pcb->stats.n_mss = pcb->mss; - pcb->stats.n_rto_timer = pcb->rto * slow_tmr_interval; - pcb->stats.n_snd_wnd = pcb->snd_wnd; - pcb->stats.n_cwnd = pcb->cwnd; - pcb->stats.n_ssthresh = pcb->ssthresh; - pcb->stats.n_snd_nxt = pcb->snd_nxt; - pcb->stats.n_lastack = pcb->lastack; + if (stats == NULL) + return; + + stats->n_mss = pcb->mss; + stats->n_rto_timer = pcb->rto * slow_tmr_interval; + stats->n_snd_wnd = pcb->snd_wnd; + stats->n_cwnd = pcb->cwnd; + stats->n_ssthresh = pcb->ssthresh; + stats->n_snd_nxt = pcb->snd_nxt; + stats->n_lastack = pcb->lastack; for (seg = pcb->unsent, n = 0; seg != NULL; seg = seg->next, ++n); - pcb->stats.n_unsent_q = n; + stats->n_unsent_q = n; for (seg = pcb->unacked, n = 0; seg != NULL; seg = seg->next, ++n); - pcb->stats.n_unacked_q = n; + stats->n_unacked_q = n; for (seg = pcb->ooseq, n = 0; seg != NULL; seg = seg->next, ++n); - pcb->stats.n_ooseq_q = n; + stats->n_ooseq_q = n; } #else /* DEFINED_EXTRA_STATS */ static void copy_tcp_metrics(struct tcp_pcb *pcb) { - /* Do nothing is extra statistics is off. */ + /* Do nothing if extra statistics is off. */ (void)pcb; } #endif /* DEFINED_EXTRA_STATS */ diff --git a/src/vma/lwip/tcp.h b/src/vma/lwip/tcp.h index 2a7fabf0a..9550a8469 100644 --- a/src/vma/lwip/tcp.h +++ b/src/vma/lwip/tcp.h @@ -300,7 +300,7 @@ struct tcp_pcb { #define TF_WND_SCALE ((u16_t)0x0100U) /* Window Scale option enabled */ #ifdef DEFINED_EXTRA_STATS - socket_tcp_stats_t stats; + socket_tcp_stats_t *p_stats; #endif /* DEFINED_EXTRA_STATS */ /* the rest of the fields are in host byte order @@ -488,6 +488,11 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, /*Initialization of tcp_pcb structure*/ void tcp_pcb_init (struct tcp_pcb* pcb, u8_t prio); +#ifdef DEFINED_EXTRA_STATS +/* Set pointer to extra TCP stats instance */ +void register_tcp_stats_instance(struct tcp_pcb *pcb, socket_tcp_stats_t *stats); +#endif /* DEFINED_EXTRA_STATS */ + void tcp_arg (struct tcp_pcb *pcb, void *arg); void tcp_ip_output (struct tcp_pcb *pcb, ip_output_fn ip_output); void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); diff --git a/src/vma/sock/sockinfo_tcp.cpp b/src/vma/sock/sockinfo_tcp.cpp index 3bee271d6..237e0e367 100644 --- a/src/vma/sock/sockinfo_tcp.cpp +++ b/src/vma/sock/sockinfo_tcp.cpp @@ -255,9 +255,8 @@ sockinfo_tcp::sockinfo_tcp(int fd): si_tcp_logdbg("tcp socket created"); tcp_pcb_init(&m_pcb, TCP_PRIO_NORMAL); - #ifdef DEFINED_EXTRA_STATS - vma_stats_instance_add_tcp(&m_pcb.stats, m_p_socket_stats); + register_tcp_stats_instance(&m_pcb, &m_p_socket_stats->tcp_stats); #endif /* DEFINED_EXTRA_STATS */ si_tcp_logdbg("new pcb %p pcb state %d", &m_pcb, get_tcp_state(&m_pcb)); @@ -333,10 +332,6 @@ sockinfo_tcp::~sockinfo_tcp() prepare_to_close(true); } -#ifdef DEFINED_EXTRA_STATS - vma_stats_instance_del_tcp(&m_pcb.stats); -#endif /* DEFINED_EXTRA_STATS */ - do_wakeup(); destructor_helper(); @@ -854,7 +849,7 @@ ssize_t sockinfo_tcp::tx(vma_tx_call_attr_t &tx_arg) errno = ECONNRESET; goto err; } - EXTRA_STATS_INC(m_pcb.stats.n_blocked_sndbuf); + EXTRA_STATS_INC(m_pcb.p_stats->n_blocked_sndbuf); //force out TCP data before going on wait() tcp_output(&m_pcb); @@ -989,6 +984,13 @@ ssize_t sockinfo_tcp::tx(vma_tx_call_attr_t &tx_arg) return ret; } +void sockinfo_tcp::on_retransmit() +{ + m_p_socket_stats->counters.n_tx_retransmits++; + if (m_pcb.cwnd < m_pcb.ssthresh) + EXTRA_STATS_INC(m_pcb.p_stats->n_rtx_ss); +} + #ifdef DEFINED_TSO err_t sockinfo_tcp::ip_output(struct pbuf *p, void* v_p_conn, uint16_t flags) { @@ -1027,7 +1029,7 @@ err_t sockinfo_tcp::ip_output(struct pbuf *p, void* v_p_conn, uint16_t flags) } if (is_set(attr.flags, VMA_TX_PACKET_REXMIT)) { - p_si_tcp->m_p_socket_stats->counters.n_tx_retransmits++; + p_si_tcp->on_retransmit(); } return ERR_OK; @@ -1067,7 +1069,7 @@ err_t sockinfo_tcp::ip_output_syn_ack(struct pbuf *p, void* v_p_conn, uint16_t f attr = (vma_wr_tx_packet_attr)flags; if (is_set(attr, VMA_TX_PACKET_REXMIT)) - p_si_tcp->m_p_socket_stats->counters.n_tx_retransmits++; + p_si_tcp->on_retransmit(); ((dst_entry_tcp*)p_dst)->slow_send_neigh(p_iovec, count, p_si_tcp->m_so_ratelimit); @@ -1113,9 +1115,7 @@ err_t sockinfo_tcp::ip_output(struct pbuf *p, void* v_p_conn, int is_rexmit, uin } if (is_rexmit) { - p_si_tcp->m_p_socket_stats->counters.n_tx_retransmits++; - if (p_si_tcp->m_pcb.cwnd < p_si_tcp->m_pcb.ssthresh) - EXTRA_STATS_INC(p_si_tcp->m_pcb.stats.n_rtx_ss); + p_si_tcp->on_retransmit(); } return ERR_OK; @@ -1155,7 +1155,7 @@ err_t sockinfo_tcp::ip_output_syn_ack(struct pbuf *p, void* v_p_conn, int is_rex } if (is_rexmit) - p_si_tcp->m_p_socket_stats->counters.n_tx_retransmits++; + p_si_tcp->on_retransmit(); ((dst_entry_tcp*)p_dst)->slow_send_neigh(p_iovec, count, p_si_tcp->m_so_ratelimit); diff --git a/src/vma/sock/sockinfo_tcp.h b/src/vma/sock/sockinfo_tcp.h index e5e228973..88a24190f 100644 --- a/src/vma/sock/sockinfo_tcp.h +++ b/src/vma/sock/sockinfo_tcp.h @@ -312,6 +312,9 @@ class sockinfo_tcp : public sockinfo, public timer_handler inline void unlock_tcp_con(); void tcp_timer(); + // Increment retransmit counters + void on_retransmit(); + bool prepare_listen_to_close(); //Builds rfs key diff --git a/src/vma/util/vma_stats.h b/src/vma/util/vma_stats.h index 29eac3d64..819c0f021 100644 --- a/src/vma/util/vma_stats.h +++ b/src/vma/util/vma_stats.h @@ -381,10 +381,6 @@ void vma_shmem_stats_close(); void vma_stats_instance_create_socket_block(socket_stats_t*); void vma_stats_instance_remove_socket_block(socket_stats_t*); -#ifdef DEFINED_EXTRA_STATS -void vma_stats_instance_add_tcp(socket_tcp_stats_t*, socket_stats_t*); -void vma_stats_instance_del_tcp(socket_tcp_stats_t*); -#endif /* DEFINED_EXTRA_STATS */ void vma_stats_mc_group_add(in_addr_t mc_grp, socket_stats_t* p_socket_stats); void vma_stats_mc_group_remove(in_addr_t mc_grp, socket_stats_t* p_socket_stats);