Skip to content

Commit 68f5a4d

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

File tree

5 files changed

+279
-21
lines changed

5 files changed

+279
-21
lines changed

src/include/zf/zf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <zf/types.h>
2626
#include <zf/zf_alts.h>
2727
#include <zf/zf_ds.h>
28+
#include <zf/zf_stats.h>
2829

2930
#undef __IN_ZF_TOP_H__
3031
#endif /* __ZF_TOP_H__ */

src/include/zf/zf_stats.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/* SPDX-FileCopyrightText: (c) Advanced Micro Devices, Inc. */
3+
/**************************************************************************\
4+
*//*! \file
5+
** \brief TCPDirect stats API
6+
*//*
7+
\**************************************************************************/
8+
9+
#ifndef __ZF_STATS_H__
10+
#define __ZF_STATS_H__
11+
12+
#ifndef __IN_ZF_TOP_H__
13+
# error "Please include zf.h to use TCPDirect."
14+
#endif
15+
16+
17+
/*! \brief Layout for a field of statistics */
18+
typedef struct {
19+
/** Name of statistics field */
20+
char* evsfl_name;
21+
/** Offset of statistics field, in bytes */
22+
int evsfl_offset;
23+
/** Size of statistics field, in bytes */
24+
int evsfl_size;
25+
} zf_stats_field_layout;
26+
27+
/*! \brief Layout for statistics */
28+
typedef struct {
29+
/** Size of data for statistics */
30+
int evsl_data_size;
31+
/** Number of fields of statistics */
32+
int evsl_fields_num;
33+
/** Array of fields of statistics */
34+
zf_stats_field_layout evsl_fields[];
35+
} zf_stats_layout;
36+
37+
/*! \brief */
38+
typedef struct {
39+
/** Number of underlying interfaces present in stack */
40+
int num_intfs;
41+
/** Size of memory needed to query the stats in bytes */
42+
int total_data_size;
43+
/** Array of layouts, one per interface */
44+
zf_stats_layout** layout;
45+
} zf_layout_collection;
46+
47+
/*! \brief Allocate and retrieve layout for available statistics
48+
**
49+
** \param stack The stack to query.
50+
** \param collection Pointer to an zf_stats_collection, that is allocated and
51+
** updated on return with the layout for available
52+
** statistics. This must be released when no longer needed
53+
** using zf_stats_free_query_layout().
54+
**
55+
** \return Zero on success or negative error code.
56+
**
57+
** Retrieve layout for available statistics.
58+
*/
59+
ZF_LIBENTRY int zf_stats_alloc_layout_collection(struct zf_stack* stack,
60+
zf_layout_collection** collection);
61+
62+
/*! \brief Release the layout allocated by zf_stats_alloc_query_layout().
63+
**
64+
** \param collection Pointer to an zf_stats_collection that was allocated using
65+
** zf_stats_alloc_layout_collection().
66+
*/
67+
ZF_LIBENTRY void zf_stats_free_layout_collection(
68+
zf_layout_collection* collection);
69+
70+
/*! \brief Retrieve a set of statistic values
71+
**
72+
** \param stack The stack to query.
73+
** \param data Pointer to a buffer, into which the statistics are
74+
** retrieved.
75+
** The size of this buffer must be equal to the value of
76+
** total_data_size in the zf_layout_collection structure.
77+
** \param collection Pointer to a zf_layout_collection, that was generated for this
78+
** stack by zf_stats_query_layout.
79+
** \param do_reset True to reset the statistics after retrieving them.
80+
**
81+
** \return zero or a negative error code.
82+
**
83+
** Retrieve a set of statistic values.
84+
**
85+
** If do_reset is true, the statistics are reset after reading.
86+
**
87+
** \note This requires full feature firmware. If used with low-latency
88+
** firmware, no error is given, and the statistics are invalid (typically
89+
** all zeroes).
90+
*/
91+
ZF_LIBENTRY int zf_stats_query(struct zf_stack* stack, void* data,
92+
zf_layout_collection* collection,
93+
int do_reset);
94+
95+
#endif /* __ZF_STATS_H__ */
96+
/** @} */

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: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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_layout_collection(struct zf_stack* stack,
30+
zf_layout_collection** collection)
31+
{
32+
int i, malloc_sz, rc = 0;
33+
int num_nics = stack->nics_n;
34+
zf_layout_collection* c;
35+
36+
c = (zf_layout_collection*)malloc(sizeof(zf_layout_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+
c->total_data_size = 0;
48+
49+
for( i = 0; i < num_nics && rc == 0; i++ ) {
50+
ef_vi* vi = &stack->nic[i].vi;
51+
rc = ef_vi_stats_query_layout(vi,
52+
(const ef_vi_stats_layout** const) &c->layout[i]);
53+
c->total_data_size += c->layout[i]->evsl_data_size;
54+
}
55+
56+
57+
if( rc < 0 ) {
58+
zf_stats_free_layout_collection(c);
59+
return rc;
60+
}
61+
*collection = c;
62+
return 0;
63+
}
64+
65+
66+
void
67+
zf_stats_free_layout_collection(zf_layout_collection* collection)
68+
{
69+
free(collection->layout);
70+
free(collection);
71+
}
72+
73+
74+
int
75+
zf_stats_query(struct zf_stack* stack, void* data,
76+
zf_layout_collection* collection, int do_reset)
77+
{
78+
int i, rc = 0;
79+
int num_intfs = stack->nics_n;
80+
char* pData = (char*)data;
81+
82+
assert(num_intfs == collection->num_intfs);
83+
84+
for( i = 0; i < num_intfs && rc == 0; i++ ) {
85+
ef_vi* vi = &stack->nic[i].vi;
86+
rc = ef_vi_stats_query(vi, vi->dh, (void*)pData, do_reset);
87+
pData += collection->layout[i]->evsl_data_size;
88+
}
89+
90+
return rc;
91+
}

src/tests/zf_apps/zfsink.c

Lines changed: 90 additions & 20 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

@@ -61,18 +63,6 @@ static void usage_err(void)
6163
exit(1);
6264
}
6365

64-
65-
static void vlog(const char* fmt, ...)
66-
{
67-
va_list args;
68-
va_start(args, fmt);
69-
pthread_mutex_lock(&printf_mutex);
70-
vprintf(fmt, args);
71-
pthread_mutex_unlock(&printf_mutex);
72-
va_end(args);
73-
}
74-
75-
7666
static void try_recv(struct zfur* ur)
7767
{
7868
struct {
@@ -98,10 +88,12 @@ static void try_recv(struct zfur* ur)
9888
struct timespec ts;
9989
int rc = zfur_pkt_get_timestamp(ur, &rd.msg, &ts, 0, &flags);
10090

91+
pthread_mutex_lock(&printf_mutex);
10192
if( rc == 0 )
102-
vlog("Hardware timestamp: %lld.%.9ld\n", ts.tv_sec, ts.tv_nsec);
93+
printf("Hardware timestamp: %ld.%.9ld\n", ts.tv_sec, ts.tv_nsec);
10394
else
104-
vlog("Error retrieving timestamp! Return code: %d\n", rc);
95+
printf("Error retrieving timestamp! Return code: %d\n", rc);
96+
pthread_mutex_unlock(&printf_mutex);
10597
}
10698

10799
zfur_zc_recv_done(ur, &rd.msg);
@@ -243,14 +235,72 @@ void print_attrs(struct zf_attr* attr)
243235
}
244236

245237

246-
static void monitor()
238+
static void zf_stats_header_print(struct zf_stack* stack,
239+
zf_layout_collection* stats_collection)
240+
{
241+
int i;
242+
243+
if( stats_collection->num_intfs > 1 )
244+
printf("\n#");
245+
246+
/* only display names for the first NIC and assume others are the same */
247+
for( i = 0; i < stats_collection->layout[0]->evsl_fields_num; ++i )
248+
printf(" %10s", stats_collection->layout[0]->evsl_fields[i].evsfl_name);
249+
}
250+
251+
252+
static void zf_stats_print(struct zf_stack* stack, uint8_t* stats_data,
253+
zf_layout_collection* stats_collection)
254+
{
255+
int i, n, n_pad;
256+
uint8_t* cur_data = stats_data;
257+
const zf_stats_layout * layout;
258+
259+
for( n = 0; n < stats_collection->num_intfs; n++ ) {
260+
if( stats_collection->num_intfs > 1 )
261+
printf("\n ");
262+
263+
layout = stats_collection->layout[n];
264+
for( i = 0; i < layout->evsl_fields_num; ++i ) {
265+
const zf_stats_field_layout* f = &layout->evsl_fields[i];
266+
n_pad = strlen(f->evsfl_name);
267+
if( n_pad < 10 )
268+
n_pad = 10;
269+
switch( f->evsfl_size ) {
270+
case sizeof(uint32_t):
271+
printf(" %*d", n_pad, *(uint32_t*)(cur_data + f->evsfl_offset));
272+
break;
273+
default:
274+
printf(" %*s", n_pad, ".");
275+
};
276+
}
277+
cur_data += layout->evsl_data_size;
278+
}
279+
}
280+
281+
282+
static void monitor(struct zf_stack* stack)
247283
{
248284
uint64_t now_bytes, prev_bytes;
249285
struct timeval start, end;
250286
uint64_t prev_pkts, now_pkts;
251287
int ms, pkt_rate, mbps;
252288

253-
vlog("#%9s %16s %16s", "pkt-rate", "bandwidth(Mbps)", "total-pkts\n");
289+
zf_layout_collection* stats_collection;
290+
uint8_t* stats_data = NULL;
291+
292+
pthread_mutex_lock(&printf_mutex);
293+
printf("#%9s %16s %16s", "pkt-rate", "bandwidth(Mbps)", "total-pkts");
294+
295+
if( cfg_intf_stats ) {
296+
ZF_TEST(zf_stats_alloc_layout_collection(stack, &stats_collection) == 0);
297+
zf_stats_header_print(stack, stats_collection);
298+
299+
ZF_TEST((stats_data = malloc(stats_collection->total_data_size)) != NULL);
300+
}
301+
302+
printf("\n");
303+
pthread_mutex_unlock(&printf_mutex);
254304

255305
prev_pkts = res.n_rx_pkts;
256306
prev_bytes = res.n_rx_bytes;
@@ -265,18 +315,35 @@ static void monitor()
265315
ms += (end.tv_usec - start.tv_usec) / 1000;
266316
pkt_rate = (int) ((now_pkts - prev_pkts) * 1000 / ms);
267317
mbps = (int) ((now_bytes - prev_bytes) * 8 / 1000 / ms);
268-
vlog("%10d %16d %16"PRIu64"\n", pkt_rate, mbps, now_pkts);
318+
319+
if( cfg_intf_stats )
320+
zf_stats_query(stack, stats_data, stats_collection, 1);
321+
322+
pthread_mutex_lock(&printf_mutex);
323+
printf("%10d %16d %16"PRIu64, pkt_rate, mbps, now_pkts);
324+
325+
if( cfg_intf_stats )
326+
zf_stats_print(stack, stats_data, stats_collection);
327+
328+
printf("\n");
269329
fflush(stdout);
330+
pthread_mutex_unlock(&printf_mutex);
331+
270332
prev_pkts = now_pkts;
271333
prev_bytes = now_bytes;
272334
start = end;
273335
}
336+
337+
if( cfg_intf_stats ) {
338+
free(stats_data);
339+
zf_stats_free_layout_collection(stats_collection);
340+
}
274341
}
275342

276343

277344
static void* monitor_fn(void* arg)
278345
{
279-
monitor();
346+
monitor( (struct zf_stack*)arg );
280347
return NULL;
281348
}
282349

@@ -289,7 +356,7 @@ int main(int argc, char* argv[])
289356
bool cfg_print_attrs = false;
290357

291358
int c;
292-
while( (c = getopt(argc, argv, "hmrwqp")) != -1 )
359+
while( (c = getopt(argc, argv, "hmrwqps")) != -1 )
293360
switch( c ) {
294361
case 'h':
295362
usage_msg(stdout);
@@ -309,6 +376,9 @@ int main(int argc, char* argv[])
309376
case 'p':
310377
cfg_print_attrs = true;
311378
break;
379+
case 's':
380+
cfg_intf_stats = true;
381+
break;
312382
case '?':
313383
exit(1);
314384
default:
@@ -374,7 +444,7 @@ int main(int argc, char* argv[])
374444
res.n_rx_pkts = 0;
375445

376446
if( ! cfg_quiet )
377-
ZF_TRY(pthread_create(&thread_id, NULL, monitor_fn, NULL) == 0);
447+
ZF_TRY(pthread_create(&thread_id, NULL, monitor_fn, stack) == 0);
378448

379449
if( cfg_waitable_fd )
380450
ev_loop_waitable_fd(stack, muxer);

0 commit comments

Comments
 (0)