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