Skip to content

Commit 3f2e6d1

Browse files
Added stats for ethernet interface
1 parent 4896ed2 commit 3f2e6d1

File tree

2 files changed

+225
-2
lines changed

2 files changed

+225
-2
lines changed

Diff for: libraries/lwIpWrapper/src/CNetIf.cpp

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "CNetIf.h"
2+
#include "CNetifStats.h"
23
#include <functional>
34

45
IPAddress CNetIf::default_ip("192.168.0.10");
@@ -12,6 +13,10 @@ bool CLwipIf::connected_to_access_point = false;
1213
WifiStatus_t CLwipIf::wifi_status = WL_IDLE_STATUS;
1314
bool CLwipIf::pending_eth_rx = false;
1415

16+
#ifdef CNETIF_STATS_ENABLED
17+
struct netif_stats stats[NETWORK_INTERFACES_MAX_NUM];
18+
#endif
19+
1520
FspTimer CLwipIf::timer;
1621

1722
ip_addr_t* u8_to_ip_addr(uint8_t* ipu8, ip_addr_t* ipaddr)
@@ -285,6 +290,7 @@ void CEth::handleEthRx()
285290
* desired performance
286291
*/
287292
__disable_irq();
293+
NETIF_STATS_RX_TIME_START(stats[NI_ETHERNET]);
288294

289295
volatile uint32_t rx_frame_dim = 0;
290296
volatile uint8_t* rx_frame_buf = eth_input(&rx_frame_dim);
@@ -299,11 +305,24 @@ void CEth::handleEthRx()
299305

300306
if (ni.input((struct pbuf*)p, &ni) != ERR_OK) {
301307
pbuf_free((struct pbuf*)p);
308+
309+
NETIF_STATS_INCREMENT_RX_NI_INPUT_FAILED_CALLS(stats[NI_ETHERNET]);
310+
NETIF_STATS_INCREMENT_RX_INTERRUPT_FAILED_CALLS(stats[NI_ETHERNET]);
311+
} else {
312+
NETIF_STATS_INCREMENT_RX_BYTES(stats[NI_ETHERNET], rx_frame_dim);
302313
}
314+
} else {
315+
NETIF_STATS_INCREMENT_RX_PBUF_ALLOC_FAILED_CALLS(stats[NI_ETHERNET]);
316+
NETIF_STATS_INCREMENT_RX_INTERRUPT_FAILED_CALLS(stats[NI_ETHERNET]);
303317
}
304-
305-
eth_release_rx_buffer();
318+
} else {
319+
NETIF_STATS_INCREMENT_RX_INTERRUPT_FAILED_CALLS(stats[NI_ETHERNET]);
306320
}
321+
322+
eth_release_rx_buffer();
323+
324+
NETIF_STATS_RX_TIME_AVERAGE(stats[NI_ETHERNET]);
325+
NETIF_STATS_INCREMENT_RX_INTERRUPT_CALLS(stats[NI_ETHERNET]);
307326
__enable_irq();
308327
}
309328

@@ -350,6 +369,8 @@ err_t CEth::output(struct netif* _ni, struct pbuf *p) {
350369
(void)_ni;
351370

352371
err_t errval = ERR_OK;
372+
NETIF_STATS_INCREMENT_TX_TRANSMIT_CALLS(stats[NI_ETHERNET]);
373+
NETIF_STATS_TX_TIME_START(stats[NI_ETHERNET]);
353374

354375
if(eth_output_can_transimit()) {
355376
uint16_t tx_buf_dim = 0;
@@ -362,10 +383,16 @@ err_t CEth::output(struct netif* _ni, struct pbuf *p) {
362383

363384
if (bytes_actually_copied > 0 && !eth_output(tx_buf, bytes_actually_copied)) {
364385
errval = ERR_IF;
386+
NETIF_STATS_INCREMENT_TX_TRANSMIT_FAILED_CALLS(stats[NI_ETHERNET]);
387+
} else {
388+
NETIF_STATS_INCREMENT_TX_BYTES(stats[NI_ETHERNET], bytes_actually_copied);
365389
}
366390
} else {
367391
errval = ERR_INPROGRESS;
392+
NETIF_STATS_INCREMENT_TX_TRANSMIT_FAILED_CALLS(stats[NI_ETHERNET]);
368393
}
394+
395+
NETIF_STATS_TX_TIME_AVERAGE(stats[NI_ETHERNET]);
369396
return errval;
370397
}
371398

@@ -1308,6 +1335,8 @@ void CEth::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
13081335
eth_set_rx_frame_cbk(std::bind(&CEth::handleEthRx, this));
13091336
eth_set_link_on_cbk(std::bind(&CEth::setLinkUp, this));
13101337
eth_set_link_off_cbk(std::bind(&CEth::setLinkDown, this));
1338+
1339+
NETIF_STATS_INIT(stats[NI_ETHERNET]);
13111340
}
13121341

13131342
/* -------------------------------------------------------------------------- */

Diff for: libraries/lwIpWrapper/src/CNetifStats.h

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#pragma once
2+
/*
3+
* This library aims to provide debug utilities for performances on Network interfaces
4+
* that are being used in lwip wrapper
5+
*
6+
* USAGE:
7+
*
8+
* In the Net interface define the struct (it should be accessible from outside)
9+
*
10+
* #ifdef CNETIF_STATS_ENABLED
11+
* struct netif_stats stats;
12+
* #endif
13+
*
14+
* Initialize the struct:
15+
*
16+
* NETIF_STATS_INIT(stats);
17+
*
18+
* Then use the MACROS defined in this file. NOTE if CNETIF_STATS_ENABLED is not defined the macros will
19+
* be solved as empty, thus no need to use #ifdef.
20+
*
21+
* In the sketch you need to import the symbol for the stats and define a buffer
22+
* (in can be dinamically allocated, it should only require 300 chars).
23+
*
24+
* #include <CNetifStats.h>
25+
* #ifdef CNETIF_STATS_ENABLED
26+
* extern netif_stats stats;
27+
* char cnetif_stats_buffer[300];
28+
* #endif
29+
*
30+
* Then you can call the routine to print the stats:
31+
*
32+
* #ifdef CNETIF_STATS_ENABLED
33+
* NETIF_STATS_SPRINT_DEBUG(cnetif_stats_buffer, stats);
34+
* DEBUG_INFO(cnetif_stats_buffer);
35+
* #endif
36+
*
37+
* You can optionally print the metrics yourself, for how to look at netif_stats_sprintf function
38+
*/
39+
40+
// #define CNETIF_STATS_ENABLED
41+
#ifdef CNETIF_STATS_ENABLED
42+
43+
#include <stdio.h>
44+
45+
struct netif_stats {
46+
// this metric cunts the number of times the rx interrupt routine is called by the driver
47+
uint32_t rx_interrupt_calls;
48+
// this metric count the number of time the transmit routine is invoked on the driver
49+
uint32_t tx_transmit_calls;
50+
// this metric counts the total number of failed rx calls, for whatever reason
51+
uint32_t rx_interrupt_failed_calls;
52+
// this metric count the number of times the rx routine failed allocating the buffer for the incoming packet
53+
uint32_t rx_pbuf_alloc_failed_calls;
54+
// this metric count the number of times the rx routing failed inserting the pbuf inside lwip
55+
uint32_t rx_ni_input_failed_calls;
56+
// this metric counts the number of times the tx routine failed
57+
uint32_t tx_transmit_failed_calls;
58+
59+
// the following metrics count the size (bytes) of packets being handled in rx and tx
60+
uint32_t rx_bytes;
61+
uint32_t tx_bytes;
62+
63+
// the following measure contains the size (bytes) of packets being handled in rx and tx
64+
// before the reset, used to calculate avg speed
65+
uint32_t prev_rx_bytes;
66+
uint32_t prev_tx_bytes;
67+
time_t measure_start;
68+
69+
// the following metrics are used to calculate the average time spent in rx interrupt and tx routine, measured in us
70+
float average_rx_time;
71+
uint32_t average_rx_time_counter;
72+
float average_tx_time;
73+
uint32_t average_tx_time_counter;
74+
75+
// the following variables are used to hold the starting time for average a single time measurement
76+
time_t rx_time_start;
77+
time_t tx_time_start;
78+
};
79+
80+
/*
81+
* This function initializes the counters on the netif_struct_t
82+
*/
83+
inline void netif_stats_init(struct netif_stats& stats, time_t time=micros()) {
84+
stats.rx_interrupt_calls = 0;
85+
stats.rx_interrupt_failed_calls = 0;
86+
stats.rx_pbuf_alloc_failed_calls = 0;
87+
stats.rx_ni_input_failed_calls = 0;
88+
stats.tx_transmit_calls = 0;
89+
stats.tx_transmit_failed_calls = 0;
90+
91+
stats.rx_bytes = 0;
92+
stats.tx_bytes = 0;
93+
stats.prev_rx_bytes = 0;
94+
stats.prev_tx_bytes = 0;
95+
stats.measure_start = time;
96+
97+
98+
stats.average_rx_time = 0;
99+
stats.average_rx_time_counter = 0;
100+
stats.average_tx_time = 0;
101+
stats.average_tx_time_counter = 0;
102+
}
103+
104+
/*
105+
* This is an utility function used to calculate an average of a sequence of numbers without storing them,
106+
* it can accept any tipes that support *, + and / operators.
107+
* This function automatically increments the counter
108+
* This function returns the next average
109+
*/
110+
template<typename T, typename S>
111+
inline T netif_stats_streaming_average(const T& metric, const T new_value, S& counter) {
112+
return ((metric*counter) + (new_value)) / (++counter);
113+
}
114+
115+
/*
116+
* This function is used to reset the metrics that are used for averages.
117+
* It is intended to be called after the prints
118+
*/
119+
inline void netif_stats_reset_averages(struct netif_stats& stats, time_t time=micros()) {
120+
stats.prev_rx_bytes = stats.rx_bytes;
121+
stats.prev_tx_bytes = stats.tx_bytes;
122+
123+
stats.average_rx_time = 0;
124+
stats.average_rx_time_counter = 0;
125+
126+
stats.average_tx_time = 0;
127+
stats.average_tx_time_counter = 0;
128+
stats.measure_start = time;
129+
}
130+
131+
/*
132+
* This routine outputs a string containing a summary of the measured stats,
133+
* the buffer passed should be 270 bytes
134+
*/
135+
inline void netif_stats_sprintf(char* buffer, const struct netif_stats& stats, size_t size=500, time_t time=micros()) {
136+
snprintf(
137+
buffer,
138+
size,
139+
"RX bytes: %10u, calls: %10u, failed: %10u, failed alloc: %10u, failed inputs: %10u\n"
140+
"TX bytes: %10u, calls: %10u, failed: %10u\n"
141+
"RX time: %10.2fus speed: %10.2fKB/s\n"
142+
"TX time: %10.2fus speed: %10.2fKB/s\n",
143+
stats.rx_bytes, stats.rx_interrupt_calls, stats.rx_interrupt_failed_calls, stats.rx_pbuf_alloc_failed_calls, stats.rx_ni_input_failed_calls,
144+
stats.tx_bytes, stats.tx_transmit_calls, stats.tx_transmit_failed_calls,
145+
stats.average_rx_time, float(stats.rx_bytes - stats.prev_rx_bytes) / (time-stats.measure_start) * 10e6 / 1024, // Measured in KB/s
146+
stats.average_tx_time, float(stats.tx_bytes - stats.prev_tx_bytes) / (time-stats.measure_start) * 10e6 / 1024
147+
);
148+
}
149+
150+
#define NETIF_STATS_INIT(stats) netif_stats_init(stats)
151+
#define NETIF_STATS_RESET_AVERAGES(stats) netif_stats_reset_averages(stats)
152+
#define NETIF_STATS_SPRINT_DEBUG(buffer, stats) netif_stats_sprintf(buffer, stats)
153+
154+
#define NETIF_STATS_INCREMENT_RX_INTERRUPT_CALLS(stats) stats.rx_interrupt_calls++
155+
#define NETIF_STATS_INCREMENT_RX_INTERRUPT_FAILED_CALLS(stats) stats.rx_interrupt_failed_calls++
156+
#define NETIF_STATS_INCREMENT_RX_PBUF_ALLOC_FAILED_CALLS(stats) stats.rx_pbuf_alloc_failed_calls++
157+
#define NETIF_STATS_INCREMENT_RX_NI_INPUT_FAILED_CALLS(stats) stats.rx_ni_input_failed_calls++
158+
#define NETIF_STATS_INCREMENT_TX_TRANSMIT_CALLS(stats) stats.tx_transmit_calls++
159+
#define NETIF_STATS_INCREMENT_TX_TRANSMIT_FAILED_CALLS(stats) stats.tx_transmit_failed_calls++
160+
161+
#define NETIF_STATS_INCREMENT_RX_BYTES(stats, bytes) stats.rx_bytes+=bytes
162+
#define NETIF_STATS_INCREMENT_TX_BYTES(stats, bytes) stats.tx_bytes+=bytes
163+
164+
#define NETIF_STATS_RX_TIME_START(stats) stats.rx_time_start = micros()
165+
#define NETIF_STATS_RX_TIME_AVERAGE(stats) stats.average_rx_time = netif_stats_streaming_average(stats.average_rx_time, float(micros() - stats.rx_time_start), stats.average_rx_time_counter)
166+
167+
#define NETIF_STATS_TX_TIME_START(stats) stats.tx_time_start = micros()
168+
#define NETIF_STATS_TX_TIME_AVERAGE(stats) stats.average_tx_time = netif_stats_streaming_average(stats.average_tx_time, float(micros() - stats.tx_time_start), stats.average_tx_time_counter)
169+
170+
171+
#else // CNETIF_STATS_ENABLED
172+
173+
#define NETIF_STATS_INIT(stats) (void)0
174+
#define NETIF_STATS_RESET_AVERAGES(stats) (void)0
175+
#define NETIF_STATS_SPRINT_DEBUG(stats, buffer) (void)0
176+
177+
#define NETIF_STATS_INCREMENT_RX_INTERRUPT_CALLS(stats) (void)0
178+
#define NETIF_STATS_INCREMENT_RX_INTERRUPT_FAILED_CALLS(stats) (void)0
179+
#define NETIF_STATS_INCREMENT_RX_PBUF_ALLOC_FAILED_CALLS(stats) (void)0
180+
#define NETIF_STATS_INCREMENT_RX_NI_INPUT_FAILED_CALLS(stats) (void)0
181+
#define NETIF_STATS_INCREMENT_TX_TRANSMIT_CALLS(stats) (void)0
182+
#define NETIF_STATS_INCREMENT_TX_TRANSMIT_FAILED_CALLS(stats) (void)0
183+
184+
#define NETIF_STATS_INCREMENT_RX_BYTES(stats, bytes) (void)0
185+
#define NETIF_STATS_INCREMENT_TX_BYTES(stats, bytes) (void)0
186+
187+
#define NETIF_STATS_RX_TIME_START(stats) (void)0
188+
#define NETIF_STATS_RX_TIME_AVERAGE(stats) (void)0
189+
190+
#define NETIF_STATS_TX_TIME_START(stats) (void)0
191+
#define NETIF_STATS_TX_TIME_AVERAGE(stats) (void)0
192+
193+
194+
#endif // CNETIF_STATS_ENABLED

0 commit comments

Comments
 (0)