Skip to content

Commit 159dd3b

Browse files
author
Richard Drinkwater
committed
ON-16037: added functions to read stats for interfaces
1 parent ebb51d9 commit 159dd3b

File tree

4 files changed

+255
-7
lines changed

4 files changed

+255
-7
lines changed

src/include/zf/zf_stack.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,5 +167,81 @@ enum zf_stack_feature {
167167
*/
168168
ZF_LIBENTRY int zf_stack_query_feature(struct zf_stack* stack, enum zf_stack_feature feature);
169169

170+
/*! \brief Layout for a field of statistics */
171+
typedef struct {
172+
/** Name of statistics field */
173+
char* evsfl_name;
174+
/** Offset of statistics file, in bytes */
175+
int evsfl_offset;
176+
/** Size of statistics field, in bytes */
177+
int evsfl_size;
178+
} zf_stats_field_layout;
179+
180+
/*! \brief Layout for statistics */
181+
typedef struct {
182+
/** Size of data for statistics */
183+
int evsl_data_size;
184+
/** Number of fields of statistics */
185+
int evsl_fields_num;
186+
/** Array of fields of statistics */
187+
zf_stats_field_layout evsl_fields[];
188+
} zf_stats_layout;
189+
190+
/*! \brief */
191+
typedef struct {
192+
/** Number of underlying interfaces present in stack */
193+
int num_intfs;
194+
/** Array of layouts, one per interface */
195+
zf_stats_layout** layout;
196+
} zf_stats_collection;
197+
198+
/*! \brief Allocate and retrieve layout for available statistics
199+
**
200+
** \param stack The stack to query.
201+
** \param collection Pointer to an zf_stats_collection, that is allocated and
202+
** updated on return with the layout for available
203+
** statistics. This must be released when no longer needed
204+
** using zf_stats_free_query_layout().
205+
**
206+
** \return Zero on success or negative error code.
207+
**
208+
** Retrieve layout for available statistics.
209+
*/
210+
ZF_LIBENTRY int zf_stats_alloc_query_layout(struct zf_stack* stack,
211+
zf_stats_collection** collection);
212+
213+
/*! \brief Release the layout allocated by zf_stats_alloc_query_layout().
214+
**
215+
** \param collection Pointer to an zf_stats_collection that was allocated using
216+
** zf_stats_alloc_query_layout().
217+
*/
218+
ZF_LIBENTRY void zf_stats_free_query_layout(zf_stats_collection* collection);
219+
220+
/*! \brief Retrieve a set of statistic values
221+
**
222+
** \param stack The stack to query.
223+
** \param data Pointer to a buffer, into which the statistics are
224+
** retrieved.
225+
** The size of this buffer must be equal to the sum of all
226+
** zfsl_data_size fields of the layout description, that can be
227+
** fetched using zf_stats_query_layout().
228+
** \param collection Pointer to a zf_stats_collection, that was generated for this
229+
** stack by zf_stats_query_layout.
230+
** \param do_reset True to reset the statistics after retrieving them.
231+
**
232+
** \return zero or a negative error code.
233+
**
234+
** Retrieve a set of statistic values.
235+
**
236+
** If do_reset is true, the statistics are reset after reading.
237+
**
238+
** \note This requires full feature firmware. If used with low-latency
239+
** firmware, no error is given, and the statistics are invalid (typically
240+
** all zeroes).
241+
*/
242+
ZF_LIBENTRY int zf_stats_query(struct zf_stack* stack, void* data,
243+
zf_stats_collection* collection,
244+
int do_reset);
245+
170246
#endif /* __ZF_STACK_H__ */
171247
/** @} */

src/lib/zf/Makefile.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
PUBLIC_LIB_SRCS := zf.c log.c attr.c stack.c pool.c udp_rx.c rx.c udp_tx.c \
55
muxer.c tcp.c tcp_in.c tcp_out.c tcp_core.c rx_table.c zf_alts.c \
66
lazy_alloc.c x86.c timers.c cplane.c zf_tcp.c zf_stackdump.c \
7-
dshm.c zf_alt_buffer_model.c zf_ds.c bond.c tx_warm.c
7+
dshm.c zf_alt_buffer_model.c zf_ds.c bond.c tx_warm.c zf_stats.c
88

99
# Source files that are not distributed, living in private/.
1010
PRIVATE_LIB_SRCS := stack_fast.c stack_alloc.c tcp_fast.c reactor.c

src/lib/zf/zf_stats.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/* SPDX-FileCopyrightText: (c) Advanced Micro Devices, Inc. */
3+
#include <zf_internal/zf_stack.h>
4+
5+
/* ensure ef_vi/zf structures are the same size in case
6+
* of adding/removing elements
7+
*/
8+
static_assert( sizeof(zf_stats_field_layout) == sizeof(zf_stats_field_layout),
9+
"ef_vi_stats_field_layout and zf_stats_field_layout size mismatch");
10+
static_assert( sizeof(ef_vi_stats_layout) == sizeof(zf_stats_layout),
11+
"ef_vi_stats_layout and zf_stats_layout size mismatch");
12+
13+
static_assert( offsetof(zf_stats_field_layout, evsfl_name) == offsetof(ef_vi_stats_field_layout, evsfl_name),
14+
"zf_stats_field_layout member evsfl_name does not match ef_vi_stats_field_layout");
15+
static_assert( offsetof(zf_stats_field_layout, evsfl_offset) == offsetof(ef_vi_stats_field_layout, evsfl_offset),
16+
"zf_stats_field_layout member evsfl_name does not match ef_vi_stats_field_layout");
17+
static_assert( offsetof(zf_stats_field_layout, evsfl_size) == offsetof(ef_vi_stats_field_layout, evsfl_size),
18+
"zf_stats_field_layout member evsfl_name does not match ef_vi_stats_field_layout");
19+
20+
static_assert( offsetof(zf_stats_layout, evsl_data_size) == offsetof(ef_vi_stats_layout, evsl_data_size),
21+
"zf_stats_field_layout member evsfl_name does not match ef_vi_stats_field_layout");
22+
static_assert( offsetof(zf_stats_layout, evsl_fields_num) == offsetof(ef_vi_stats_layout, evsl_fields_num),
23+
"zf_stats_field_layout member evsfl_name does not match ef_vi_stats_field_layout");
24+
static_assert( offsetof(zf_stats_layout, evsl_fields) == offsetof(ef_vi_stats_layout, evsl_fields),
25+
"zf_stats_field_layout member evsfl_name does not match ef_vi_stats_field_layout");
26+
27+
28+
int
29+
zf_stats_alloc_query_layout(struct zf_stack* stack,
30+
zf_stats_collection** collection)
31+
{
32+
int i, malloc_sz, rc = 0;
33+
int num_nics = stack->nics_n;
34+
zf_stats_collection* c;
35+
36+
c = (zf_stats_collection*)malloc(sizeof(zf_stats_collection));
37+
if( c == NULL )
38+
return -ENOMEM;
39+
40+
malloc_sz = num_nics * sizeof(zf_stats_layout *);
41+
c->layout = (zf_stats_layout**)malloc(malloc_sz);
42+
if( c->layout == NULL ) {
43+
free(c);
44+
return -ENOMEM;
45+
}
46+
c->num_intfs = num_nics;
47+
48+
for( i = 0; i < num_nics && rc == 0; i++ ) {
49+
ef_vi* vi = &stack->nic[i].vi;
50+
rc = ef_vi_stats_query_layout(vi,
51+
(const ef_vi_stats_layout** const) &c->layout[i]);
52+
}
53+
54+
55+
if( rc < 0 ) {
56+
zf_stats_free_query_layout(c);
57+
return rc;
58+
}
59+
*collection = c;
60+
return 0;
61+
}
62+
63+
64+
void
65+
zf_stats_free_query_layout(zf_stats_collection* collection)
66+
{
67+
free(collection->layout);
68+
free(collection);
69+
}
70+
71+
72+
int
73+
zf_stats_query(struct zf_stack* stack, void* data,
74+
zf_stats_collection* collection, int do_reset)
75+
{
76+
int i, rc = 0;
77+
int num_intfs = stack->nics_n;
78+
char* pData = (char*)data;
79+
80+
if( num_intfs > collection->num_intfs )
81+
num_intfs = collection->num_intfs;
82+
83+
for( i = 0; i < num_intfs && rc == 0; i++ ) {
84+
ef_vi* vi = &stack->nic[i].vi;
85+
rc = ef_vi_stats_query(vi, vi->dh, (void*)pData, do_reset);
86+
pData += collection->layout[i]->evsl_data_size;
87+
}
88+
89+
return rc;
90+
}

src/tests/zf_apps/zfsink.c

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct resources {
3434

3535
static bool cfg_quiet = false;
3636
static bool cfg_rx_timestamping = false;
37+
static bool cfg_intf_stats = false;
3738
static struct resources res;
3839

3940
/* Mutex to protect printing from different threads */
@@ -52,6 +53,7 @@ static void usage_msg(FILE* f)
5253
fprintf(f, " -r Enable rx timestamping\n");
5354
fprintf(f, " -q Quiet -- do not emit progress messages\n");
5455
fprintf(f, " -p Print zf attributes after stack startup\n");
56+
fprintf(f, " -s Print interfaces drop stats\n");
5557
}
5658

5759

@@ -243,14 +245,75 @@ void print_attrs(struct zf_attr* attr)
243245
}
244246

245247

246-
static void monitor()
248+
static void zf_stats_header_print(struct zf_stack* stack,
249+
zf_stats_collection* stats_collection)
250+
{
251+
int i;
252+
253+
/* only display names for the first NIC and assume others are the same */
254+
if( stats_collection->num_intfs > 1 ) {
255+
printf("\n#");
256+
}
257+
for( i = 0; i < stats_collection->layout[0]->evsl_fields_num; ++i )
258+
printf(" %10s", stats_collection->layout[0]->evsl_fields[i].evsfl_name);
259+
}
260+
261+
262+
static void zf_stats_print(struct zf_stack* stack, uint8_t* stats_data,
263+
zf_stats_collection* stats_collection)
264+
{
265+
int i, n, n_pad;
266+
uint8_t* cur_data = stats_data;
267+
const zf_stats_layout * layout;
268+
269+
for( n = 0; n < stats_collection->num_intfs; n++ ) {
270+
if( stats_collection->num_intfs > 1 )
271+
printf("\n");
272+
273+
layout = stats_collection->layout[n];
274+
for( i = 0; i < layout->evsl_fields_num; ++i ) {
275+
const zf_stats_field_layout* f = &layout->evsl_fields[i];
276+
n_pad = strlen(f->evsfl_name);
277+
if( n_pad < 10 )
278+
n_pad = 10;
279+
switch( f->evsfl_size ) {
280+
case sizeof(uint32_t):
281+
printf(" %*d", n_pad, *(uint32_t*)(cur_data + f->evsfl_offset));
282+
break;
283+
default:
284+
printf(" %*s", n_pad, ".");
285+
};
286+
}
287+
cur_data += layout->evsl_data_size;
288+
}
289+
}
290+
291+
292+
static void monitor(struct zf_stack* stack)
247293
{
248294
uint64_t now_bytes, prev_bytes;
249295
struct timeval start, end;
250296
uint64_t prev_pkts, now_pkts;
251297
int ms, pkt_rate, mbps;
252298

253-
vlog("#%9s %16s %16s", "pkt-rate", "bandwidth(Mbps)", "total-pkts\n");
299+
zf_stats_collection* stats_collection;
300+
uint8_t* stats_data = NULL;
301+
int i, malloc_sz = 0;
302+
303+
pthread_mutex_lock(&printf_mutex);
304+
printf("#%9s %16s %16s", "pkt-rate", "bandwidth(Mbps)", "total-pkts");
305+
306+
if( cfg_intf_stats ) {
307+
ZF_TEST(zf_stats_alloc_query_layout(stack, &stats_collection) == 0);
308+
zf_stats_header_print(stack, stats_collection);
309+
310+
for( i = 0; i < stats_collection->num_intfs; i++ )
311+
malloc_sz += stats_collection->layout[i]->evsl_data_size;
312+
ZF_TEST((stats_data = malloc(malloc_sz)) != NULL);
313+
}
314+
315+
printf("\n");
316+
pthread_mutex_unlock(&printf_mutex);
254317

255318
prev_pkts = res.n_rx_pkts;
256319
prev_bytes = res.n_rx_bytes;
@@ -265,18 +328,34 @@ static void monitor()
265328
ms += (end.tv_usec - start.tv_usec) / 1000;
266329
pkt_rate = (int) ((now_pkts - prev_pkts) * 1000 / ms);
267330
mbps = (int) ((now_bytes - prev_bytes) * 8 / 1000 / ms);
268-
vlog("%10d %16d %16"PRIu64"\n", pkt_rate, mbps, now_pkts);
331+
332+
pthread_mutex_lock(&printf_mutex);
333+
printf("%10d %16d %16"PRIu64, pkt_rate, mbps, now_pkts);
334+
335+
if( cfg_intf_stats ) {
336+
zf_stats_query(stack, stats_data, stats_collection, 1);
337+
zf_stats_print(stack, stats_data, stats_collection);
338+
}
339+
340+
printf("\n");
269341
fflush(stdout);
342+
pthread_mutex_unlock(&printf_mutex);
343+
270344
prev_pkts = now_pkts;
271345
prev_bytes = now_bytes;
272346
start = end;
273347
}
348+
349+
if( cfg_intf_stats ) {
350+
free(stats_data);
351+
zf_stats_free_query_layout(stats_collection);
352+
}
274353
}
275354

276355

277356
static void* monitor_fn(void* arg)
278357
{
279-
monitor();
358+
monitor( (struct zf_stack*)arg );
280359
return NULL;
281360
}
282361

@@ -289,7 +368,7 @@ int main(int argc, char* argv[])
289368
bool cfg_print_attrs = false;
290369

291370
int c;
292-
while( (c = getopt(argc, argv, "hmrwqp")) != -1 )
371+
while( (c = getopt(argc, argv, "hmrwqps")) != -1 )
293372
switch( c ) {
294373
case 'h':
295374
usage_msg(stdout);
@@ -309,6 +388,9 @@ int main(int argc, char* argv[])
309388
case 'p':
310389
cfg_print_attrs = true;
311390
break;
391+
case 's':
392+
cfg_intf_stats = true;
393+
break;
312394
case '?':
313395
exit(1);
314396
default:
@@ -374,7 +456,7 @@ int main(int argc, char* argv[])
374456
res.n_rx_pkts = 0;
375457

376458
if( ! cfg_quiet )
377-
ZF_TRY(pthread_create(&thread_id, NULL, monitor_fn, NULL) == 0);
459+
ZF_TRY(pthread_create(&thread_id, NULL, monitor_fn, stack) == 0);
378460

379461
if( cfg_waitable_fd )
380462
ev_loop_waitable_fd(stack, muxer);

0 commit comments

Comments
 (0)