net: Add statistics how long packets have spent in TX path

Calculate how long on average net_pkt has spent on its way from
application to the network device driver. The data is calculated
for all network packets and not just for UDP or TCP ones like in
RX statistics.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2019-10-08 16:00:37 +03:00
parent 4f92b7b648
commit d03cb7367c
7 changed files with 98 additions and 68 deletions

View file

@ -97,10 +97,21 @@ struct net_pkt {
struct net_if *orig_iface; /* Original network interface */
#endif
/* We do not support combination of TXTIME and TXTIME_STATS as the
* same variable is shared in net_pkt.h
*/
#if defined(CONFIG_NET_PKT_TXTIME) && defined(CONFIG_NET_PKT_TXTIME_STATS)
#error \
"Cannot define both CONFIG_NET_PKT_TXTIME and CONFIG_NET_PKT_TXTIME_STATS"
#endif
#if defined(CONFIG_NET_PKT_TIMESTAMP) || defined(CONFIG_NET_PKT_TXTIME) || \
defined(CONFIG_NET_PKT_RXTIME_STATS)
defined(CONFIG_NET_PKT_RXTIME_STATS) || \
defined(CONFIG_NET_PKT_TXTIME_STATS)
union {
#if defined(CONFIG_NET_PKT_TIMESTAMP) || defined(CONFIG_NET_PKT_RXTIME_STATS)
#if defined(CONFIG_NET_PKT_TIMESTAMP) || \
defined(CONFIG_NET_PKT_RXTIME_STATS) || \
defined(CONFIG_NET_PKT_TXTIME_STATS)
/** Timestamp if available. */
struct net_ptp_time timestamp;
#endif /* CONFIG_NET_PKT_TIMESTAMP */

View file

@ -203,11 +203,11 @@ struct net_stats_ipv6_mld {
};
/**
* @brief Network packet transfer times
* @brief Network packet transfer times for calculating average TX time
*/
struct net_stats_tx_time {
u64_t time_sum;
net_stats_t time_count;
u64_t sum;
net_stats_t count;
};
/**
@ -223,10 +223,10 @@ struct net_stats_rx_time {
*/
struct net_stats_tc {
struct {
struct net_stats_tx_time tx_time;
net_stats_t pkts;
net_stats_t bytes;
u8_t priority;
struct net_stats_tx_time tx_time;
} sent[NET_TC_TX_COUNT];
struct {
@ -293,7 +293,13 @@ struct net_stats {
struct net_stats_tc tc;
#endif
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP) && \
defined(CONFIG_NET_PKT_TXTIME_STATS)
#error \
"Cannot define both CONFIG_NET_CONTEXT_TIMESTAMP and CONFIG_NET_PKT_TXTIME_STATS"
#endif
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP) || \
defined(CONFIG_NET_PKT_TXTIME_STATS)
/** Network packet TX time statistics */
struct net_stats_tx_time tx_time;
#endif

View file

@ -661,6 +661,23 @@ config NET_PKT_RXTIME_STATS
in net-shell.
The RX statistics are only calculated for UDP and TCP packets.
config NET_PKT_TXTIME_STATS
bool "Enable network packet TX time statistics"
select NET_PKT_TIMESTAMP
select NET_STATISTICS
depends on (NET_UDP || NET_TCP) && !NET_PKT_TXTIME
help
Enable network packet TX time statistics support. This is used to
calculate how long on average it takes for a packet to travel from
application to just before it is sent to network. The TX timing
information can then be seen in network interface statistics in
net-shell.
The RX calculation is done only for UDP or TCP packets, but for TX
we do not know the protocol so the TX packet timing is done for all
network protocol packets.
Note that CONFIG_NET_PKT_TXTIME cannot be set at the same time
because net_pkt shares the time variable for statistics and TX time.
config NET_PROMISCUOUS_MODE
bool "Enable promiscuous mode support [EXPERIMENTAL]"
select NET_MGMT

View file

@ -150,14 +150,12 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
struct net_context *context;
int status;
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
/* Timestamp of the current network packet sent */
/* Timestamp of the current network packet sent if enabled */
struct net_ptp_time start_timestamp;
u32_t curr_time = 0;
/* We collect send statistics for each socket priority */
/* We collect send statistics for each socket priority if enabled */
u8_t pkt_priority;
#endif
if (!pkt) {
return false;
@ -175,8 +173,7 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
net_pkt_set_queued(pkt, false);
}
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
if (context) {
if (IS_ENABLED(CONFIG_NET_CONTEXT_TIMESTAMP) && context) {
if (net_context_get_timestamp(context, pkt,
&start_timestamp) < 0) {
start_timestamp.nanosecond = 0;
@ -184,17 +181,28 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
pkt_priority = net_pkt_priority(pkt);
}
}
#endif
if (IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS)) {
memcpy(&start_timestamp, net_pkt_timestamp(pkt),
sizeof(start_timestamp));
pkt_priority = net_pkt_priority(pkt);
}
status = net_if_l2(iface)->send(iface, pkt);
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
if (status >= 0 && context) {
if (IS_ENABLED(CONFIG_NET_CONTEXT_TIMESTAMP) && status >= 0 &&
context) {
if (start_timestamp.nanosecond > 0) {
curr_time = k_cycle_get_32();
}
}
#endif
if (IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS) && status >= 0) {
net_stats_update_tc_tx_time(iface,
pkt_priority,
start_timestamp.nanosecond,
k_cycle_get_32());
}
} else {
/* Drop packet if interface is not up */
@ -214,9 +222,8 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
net_context_send_cb(context, status);
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
if (status >= 0 && start_timestamp.nanosecond &&
curr_time > 0) {
if (IS_ENABLED(CONFIG_NET_CONTEXT_TIMESTAMP) && status >= 0 &&
start_timestamp.nanosecond && curr_time > 0) {
/* So we know now how long the network packet was in
* transit from when it was allocated to when we
* got information that it was sent successfully.
@ -226,7 +233,6 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
start_timestamp.nanosecond,
curr_time);
}
#endif
}
if (dst->addr) {

View file

@ -1193,13 +1193,14 @@ static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, s32_t timeout)
net_pkt_set_priority(pkt, CONFIG_NET_RX_DEFAULT_PRIORITY);
}
if (IS_ENABLED(CONFIG_NET_PKT_RXTIME_STATS)) {
if (IS_ENABLED(CONFIG_NET_PKT_RXTIME_STATS) ||
IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS)) {
struct net_ptp_time tp = {
/* Use the nanosecond field to temporarily
* store the cycle count as it is a 32-bit
* variable. The net_pkt timestamp field is used
* to calculate how long it takes the packet to travel
* from network device driver to the application.
* between network device driver and application.
*/
.nanosecond = k_cycle_get_32(),
};

View file

@ -88,6 +88,17 @@ char *net_sprint_addr(sa_family_t af, const void *addr);
int net_context_get_timestamp(struct net_context *context,
struct net_pkt *pkt,
struct net_ptp_time *timestamp);
#else
static inline int net_context_get_timestamp(struct net_context *context,
struct net_pkt *pkt,
struct net_ptp_time *timestamp)
{
ARG_UNUSED(context);
ARG_UNUSED(pkt);
ARG_UNUSED(timestamp);
return -ENOTSUP;
}
#endif
#if defined(CONFIG_COAP)

View file

@ -318,27 +318,21 @@ static inline void net_stats_update_ipv6_mld_drop(struct net_if *iface)
#define net_stats_update_ipv6_mld_drop(iface)
#endif /* CONFIG_NET_STATISTICS_MLD */
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP) && defined(CONFIG_NET_STATISTICS)
#if (defined(CONFIG_NET_CONTEXT_TIMESTAMP) || \
defined(CONFIG_NET_PKT_TXTIME_STATS)) && defined(CONFIG_NET_STATISTICS)
static inline void net_stats_update_tx_time(struct net_if *iface,
u32_t start_time,
u32_t end_time)
{
u32_t diff = abs(end_time - start_time);
u32_t diff = end_time - start_time;
UPDATE_STAT(iface, stats.tx_time.time_sum +=
SYS_CLOCK_HW_CYCLES_TO_NS64(diff) / 1000);
UPDATE_STAT(iface, stats.tx_time.time_count += 1);
UPDATE_STAT(iface, stats.tx_time.sum +=
SYS_CLOCK_HW_CYCLES_TO_NS64(diff) / NSEC_PER_USEC);
UPDATE_STAT(iface, stats.tx_time.count += 1);
}
#else
static inline void net_stats_update_tx_time(struct net_if *iface,
u32_t start_time,
u32_t end_time)
{
ARG_UNUSED(iface);
ARG_UNUSED(start_time);
ARG_UNUSED(end_time);
}
#endif /* CONFIG_NET_CONTEXT_TIMESTAMP && STATISTICS */
#define net_stats_update_tx_time(iface, start_time, end_time)
#endif /* (TIMESTAMP || NET_PKT_TXTIME_STATS) && NET_STATISTICS */
#if defined(CONFIG_NET_PKT_RXTIME_STATS) && defined(CONFIG_NET_STATISTICS)
static inline void net_stats_update_rx_time(struct net_if *iface,
@ -353,7 +347,7 @@ static inline void net_stats_update_rx_time(struct net_if *iface,
}
#else
#define net_stats_update_rx_time(iface, start_time, end_time)
#endif /* CONFIG_NET_CONTEXT_TIMESTAMP && STATISTICS */
#endif /* NET_CONTEXT_TIMESTAMP && STATISTICS */
#if (NET_TC_COUNT > 1) && defined(CONFIG_NET_STATISTICS) \
&& defined(CONFIG_NET_NATIVE)
@ -374,33 +368,25 @@ static inline void net_stats_update_tc_sent_priority(struct net_if *iface,
UPDATE_STAT(iface, stats.tc.sent[tc].priority = priority);
}
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP) && defined(CONFIG_NET_STATISTICS) \
&& defined(CONFIG_NET_NATIVE)
#if (defined(CONFIG_NET_CONTEXT_TIMESTAMP) || \
defined(CONFIG_NET_PKT_TXTIME_STATS)) && \
defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_NATIVE)
static inline void net_stats_update_tc_tx_time(struct net_if *iface,
u8_t tc,
u32_t start_time,
u32_t end_time)
{
u32_t diff = abs(end_time - start_time);
u32_t diff = end_time - start_time;
UPDATE_STAT(iface, stats.tc.sent[tc].tx_time.time_sum +=
SYS_CLOCK_HW_CYCLES_TO_NS64(diff) / 1000);
UPDATE_STAT(iface, stats.tc.sent[tc].tx_time.time_count += 1);
UPDATE_STAT(iface, stats.tc.sent[tc].tx_time.sum +=
SYS_CLOCK_HW_CYCLES_TO_NS64(diff) / NSEC_PER_USEC);
UPDATE_STAT(iface, stats.tc.sent[tc].tx_time.count += 1);
net_stats_update_tx_time(iface, start_time, end_time);
}
#else
static inline void net_stats_update_tc_tx_time(struct net_if *iface,
u8_t tc,
u32_t start_time,
u32_t end_time)
{
ARG_UNUSED(iface);
ARG_UNUSED(tc);
ARG_UNUSED(start_time);
ARG_UNUSED(end_time);
}
#endif /* CONFIG_NET_CONTEXT_TIMESTAMP && CONFIG_NET_STATISTICS */
#define net_stats_update_tc_tx_time(iface, tc, start_time, end_time)
#endif /* (NET_CONTEXT_TIMESTAMP || NET_PKT_TXTIME_STATS) && NET_STATISTICS */
#if defined(CONFIG_NET_PKT_RXTIME_STATS) && defined(CONFIG_NET_STATISTICS) \
&& defined(CONFIG_NET_NATIVE)
@ -445,8 +431,9 @@ static inline void net_stats_update_tc_recv_priority(struct net_if *iface,
#define net_stats_update_tc_recv_bytes(iface, tc, bytes)
#define net_stats_update_tc_recv_priority(iface, tc, priority)
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP) && defined(CONFIG_NET_STATISTICS) \
&& defined(CONFIG_NET_NATIVE)
#if (defined(CONFIG_NET_CONTEXT_TIMESTAMP) || \
defined(CONFIG_NET_PKT_TXTIME_STATS)) && \
defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_NATIVE)
static inline void net_stats_update_tc_tx_time(struct net_if *iface,
u8_t pkt_priority,
u32_t start_time,
@ -457,17 +444,8 @@ static inline void net_stats_update_tc_tx_time(struct net_if *iface,
net_stats_update_tx_time(iface, start_time, end_time);
}
#else
static inline void net_stats_update_tc_tx_time(struct net_if *iface,
u8_t pkt_priority,
u32_t start_time,
u32_t end_time)
{
ARG_UNUSED(iface);
ARG_UNUSED(pkt_priority);
ARG_UNUSED(start_time);
ARG_UNUSED(end_time);
}
#endif /* CONFIG_NET_CONTEXT_TIMESTAMP && CONFIG_NET_STATISTICS */
#define net_stats_update_tc_tx_time(iface, priority, start_time, end_time)
#endif /* (NET_CONTEXT_TIMESTAMP || NET_PKT_TXTIME_STATS) && NET_STATISTICS */
#if defined(CONFIG_NET_PKT_RXTIME_STATS) && defined(CONFIG_NET_STATISTICS) \
&& defined(CONFIG_NET_NATIVE)