Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/include/zf/zf.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <zf/types.h>
#include <zf/zf_alts.h>
#include <zf/zf_ds.h>
#include <zf/zf_stats.h>

#undef __IN_ZF_TOP_H__
#endif /* __ZF_TOP_H__ */
Expand Down
76 changes: 76 additions & 0 deletions src/include/zf/zf_stats.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: MIT */
/* SPDX-FileCopyrightText: (c) Advanced Micro Devices, Inc. */
/**************************************************************************\
*//*! \file
** \brief TCPDirect stats API
*//*
\**************************************************************************/

#ifndef __ZF_STATS_H__
#define __ZF_STATS_H__

#ifndef __IN_ZF_TOP_H__
# error "Please include zf.h to use TCPDirect."
#endif

#include <etherfabric/vi.h>

typedef ef_vi_stats_field_layout zf_stats_field_layout;
typedef ef_vi_stats_layout zf_stats_layout;

/*! \brief */
typedef struct {
/** Number of underlying interfaces present in stack */
int num_intfs;
/** Size of memory needed to query the stats in bytes */
int total_data_size;
/** Array of layouts, one per interface */
zf_stats_layout** layout;
} zf_interface_stats;

/*! \brief Allocate and retrieve layout for available statistics
**
** \param stack The stack to query.
** \param collection Pointer to an zf_interface_stats, that is allocated and
** updated on return with the layout for available
** statistics. This must be released when no longer needed
** using zf_stats_free_layout_collection().
**
** \return Zero on success or negative error code.
**
** Retrieve layout for available statistics.
*/
ZF_LIBENTRY int
zf_stats_alloc_interface_stats(struct zf_stack* stack,
zf_interface_stats** collection);

/*! \brief Release the layout allocated by zf_stats_alloc_query_layout().
**
** \param collection Pointer to an zf_interface_stats that was allocated
** using zf_stats_alloc_layout_collection().
*/
ZF_LIBENTRY void zf_stats_free_interface_stats(zf_interface_stats* collection);

/*! \brief Retrieve a set of statistic values
**
** \param stack The stack to query.
** \param data Pointer to a buffer, into which the statistics are
** retrieved.
** The size of this buffer must be equal to the value of
** total_data_size in the zf_interface_stats structure.
** \param collection Pointer to a zf_interface_stats, that was allocated for
** this stack by zf_stats_alloc_layout_collection.
** \param do_reset True to reset the statistics after retrieving them.
**
** \return zero or a negative error code.
**
** Retrieve a set of statistic values.
**
** If do_reset is true, the statistics are reset after reading.
*/
ZF_LIBENTRY int zf_stats_query(struct zf_stack* stack, void* data,
zf_interface_stats* collection,
int do_reset);

#endif /* __ZF_STATS_H__ */
/** @} */
2 changes: 1 addition & 1 deletion src/lib/zf/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
PUBLIC_LIB_SRCS := zf.c log.c attr.c stack.c pool.c udp_rx.c rx.c udp_tx.c \
muxer.c tcp.c tcp_in.c tcp_out.c tcp_core.c rx_table.c zf_alts.c \
lazy_alloc.c x86.c timers.c cplane.c zf_tcp.c zf_stackdump.c \
dshm.c zf_alt_buffer_model.c zf_ds.c bond.c tx_warm.c
dshm.c zf_alt_buffer_model.c zf_ds.c bond.c tx_warm.c zf_stats.c

# Source files that are not distributed, living in private/.
PRIVATE_LIB_SRCS := stack_fast.c stack_alloc.c tcp_fast.c reactor.c
Expand Down
68 changes: 68 additions & 0 deletions src/lib/zf/zf_stats.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: MIT */
/* SPDX-FileCopyrightText: (c) Advanced Micro Devices, Inc. */
#include <zf_internal/zf_stack.h>

int
zf_stats_alloc_interface_stats(struct zf_stack* stack,
zf_interface_stats** collection)
{
int i, rc = 0;
int num_nics = stack->nics_n;
zf_interface_stats* c;

c = (zf_interface_stats*) malloc(sizeof(*c));
if( c == NULL )
return -ENOMEM;

c->layout = (zf_stats_layout**) malloc(sizeof(*c->layout) * num_nics);
if( c->layout == NULL ) {
free(c);
return -ENOMEM;
}
c->num_intfs = num_nics;
c->total_data_size = 0;

for( i = 0; i < num_nics && rc == 0; i++ ) {
ef_vi* vi = &stack->nic[i].vi;
rc = ef_vi_stats_query_layout(vi,
(const ef_vi_stats_layout** const) &c->layout[i]);
if( rc == 0 )
c->total_data_size += c->layout[i]->evsl_data_size;
}


if( rc < 0 ) {
zf_stats_free_interface_stats(c);
return rc;
}
*collection = c;
return 0;
}


void
zf_stats_free_interface_stats(zf_interface_stats* collection)
{
free(collection->layout);
free(collection);
}


int
zf_stats_query(struct zf_stack* stack, void* data,
zf_interface_stats* collection, int do_reset)
{
int i, rc = 0;
int num_intfs = stack->nics_n;
char* pData = (char*)data;

assert(num_intfs == collection->num_intfs);

for( i = 0; i < num_intfs && rc == 0; i++ ) {
ef_vi* vi = &stack->nic[i].vi;
rc = ef_vi_stats_query(vi, vi->dh, (void*)pData, do_reset);
pData += collection->layout[i]->evsl_data_size;
}

return rc;
}
110 changes: 90 additions & 20 deletions src/tests/zf_apps/zfsink.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct resources {

static bool cfg_quiet = false;
static bool cfg_rx_timestamping = false;
static bool cfg_intf_stats = false;
static struct resources res;

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


Expand All @@ -61,18 +63,6 @@ static void usage_err(void)
exit(1);
}


static void vlog(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
pthread_mutex_lock(&printf_mutex);
vprintf(fmt, args);
pthread_mutex_unlock(&printf_mutex);
va_end(args);
}


static void try_recv(struct zfur* ur)
{
struct {
Expand All @@ -98,10 +88,12 @@ static void try_recv(struct zfur* ur)
struct timespec ts;
int rc = zfur_pkt_get_timestamp(ur, &rd.msg, &ts, 0, &flags);

pthread_mutex_lock(&printf_mutex);
if( rc == 0 )
vlog("Hardware timestamp: %lld.%.9ld\n", ts.tv_sec, ts.tv_nsec);
printf("Hardware timestamp: %ld.%.9ld\n", ts.tv_sec, ts.tv_nsec);
else
vlog("Error retrieving timestamp! Return code: %d\n", rc);
printf("Error retrieving timestamp! Return code: %d\n", rc);
pthread_mutex_unlock(&printf_mutex);
}

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


static void monitor()
static void zf_stats_header_print(struct zf_stack* stack,
zf_interface_stats* stats_collection)
{
int i;

if( stats_collection->num_intfs > 1 )
printf("\n#");

/* only display names for the first NIC and assume others are the same */
for( i = 0; i < stats_collection->layout[0]->evsl_fields_num; ++i )
printf(" %10s", stats_collection->layout[0]->evsl_fields[i].evsfl_name);
}


static void zf_stats_print(struct zf_stack* stack, uint8_t* stats_data,
zf_interface_stats* stats_collection)
{
int i, n, n_pad;
uint8_t* cur_data = stats_data;
const zf_stats_layout * layout;

for( n = 0; n < stats_collection->num_intfs; n++ ) {
if( stats_collection->num_intfs > 1 )
printf("\n ");

layout = stats_collection->layout[n];
for( i = 0; i < layout->evsl_fields_num; ++i ) {
const zf_stats_field_layout* f = &layout->evsl_fields[i];
n_pad = strlen(f->evsfl_name);
if( n_pad < 10 )
n_pad = 10;
switch( f->evsfl_size ) {
case sizeof(uint32_t):
printf(" %*d", n_pad, *(uint32_t*)(cur_data + f->evsfl_offset));
break;
default:
printf(" %*s", n_pad, ".");
};
}
cur_data += layout->evsl_data_size;
}
}


static void monitor(struct zf_stack* stack)
{
uint64_t now_bytes, prev_bytes;
struct timeval start, end;
uint64_t prev_pkts, now_pkts;
int ms, pkt_rate, mbps;

vlog("#%9s %16s %16s", "pkt-rate", "bandwidth(Mbps)", "total-pkts\n");
zf_interface_stats* stats_collection;
uint8_t* stats_data = NULL;

pthread_mutex_lock(&printf_mutex);
printf("#%9s %16s %16s", "pkt-rate", "bandwidth(Mbps)", "total-pkts");

if( cfg_intf_stats ) {
ZF_TEST(zf_stats_alloc_interface_stats(stack, &stats_collection) == 0);
zf_stats_header_print(stack, stats_collection);

ZF_TEST((stats_data = malloc(stats_collection->total_data_size)) != NULL);
}

printf("\n");
pthread_mutex_unlock(&printf_mutex);

prev_pkts = res.n_rx_pkts;
prev_bytes = res.n_rx_bytes;
Expand All @@ -265,18 +315,35 @@ static void monitor()
ms += (end.tv_usec - start.tv_usec) / 1000;
pkt_rate = (int) ((now_pkts - prev_pkts) * 1000 / ms);
mbps = (int) ((now_bytes - prev_bytes) * 8 / 1000 / ms);
vlog("%10d %16d %16"PRIu64"\n", pkt_rate, mbps, now_pkts);

if( cfg_intf_stats )
zf_stats_query(stack, stats_data, stats_collection, 1);

pthread_mutex_lock(&printf_mutex);
printf("%10d %16d %16"PRIu64, pkt_rate, mbps, now_pkts);

if( cfg_intf_stats )
zf_stats_print(stack, stats_data, stats_collection);

printf("\n");
fflush(stdout);
pthread_mutex_unlock(&printf_mutex);

prev_pkts = now_pkts;
prev_bytes = now_bytes;
start = end;
}

if( cfg_intf_stats ) {
free(stats_data);
zf_stats_free_interface_stats(stats_collection);
}
}


static void* monitor_fn(void* arg)
{
monitor();
monitor( (struct zf_stack*)arg );
return NULL;
}

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

int c;
while( (c = getopt(argc, argv, "hmrwqp")) != -1 )
while( (c = getopt(argc, argv, "hmrwqps")) != -1 )
switch( c ) {
case 'h':
usage_msg(stdout);
Expand All @@ -309,6 +376,9 @@ int main(int argc, char* argv[])
case 'p':
cfg_print_attrs = true;
break;
case 's':
cfg_intf_stats = true;
break;
case '?':
exit(1);
default:
Expand Down Expand Up @@ -374,7 +444,7 @@ int main(int argc, char* argv[])
res.n_rx_pkts = 0;

if( ! cfg_quiet )
ZF_TRY(pthread_create(&thread_id, NULL, monitor_fn, NULL) == 0);
ZF_TRY(pthread_create(&thread_id, NULL, monitor_fn, stack) == 0);

if( cfg_waitable_fd )
ev_loop_waitable_fd(stack, muxer);
Expand Down