diff --git a/api/counter.h b/api/counter.h index debcaace1..b4406dcff 100644 --- a/api/counter.h +++ b/api/counter.h @@ -49,6 +49,9 @@ yanet_get_chain_counters( const char *chain_name ); +struct counter_handle_list * +yanet_get_nic_counters(struct dp_config *dp_config); + // Get module counters, optionally filtered by name. struct counter_handle_list * yanet_get_module_counters( diff --git a/controlplane/ffi/shm.go b/controlplane/ffi/shm.go index 15a3dc799..d8338ddaf 100644 --- a/controlplane/ffi/shm.go +++ b/controlplane/ffi/shm.go @@ -755,6 +755,17 @@ func (m *DPConfig) PerformanceCounters( return result, nil } +func (m *DPConfig) NICCounters() []CounterInfo { + counters := C.yanet_get_nic_counters(m.ptr) + defer C.yanet_counter_handle_list_free(counters) + + if counters == nil { + return nil + } + + return m.encodeCounters(counters) +} + type ModuleReference struct { Device string Pipeline string diff --git a/controlplane/internal/gateway/counters_service.go b/controlplane/internal/gateway/counters_service.go index 68783d762..9cbe87f5e 100644 --- a/controlplane/internal/gateway/counters_service.go +++ b/controlplane/internal/gateway/counters_service.go @@ -129,6 +129,20 @@ func (m *CountersService) Module( return response, nil } +func (m *CountersService) NIC( + ctx context.Context, + request *ynpb.NICCounterRequest, +) (*ynpb.CountersResponse, error) { + dpConfig := m.shm.DPConfig(m.instanceID) + counterValues := dpConfig.NICCounters() + + response := &ynpb.CountersResponse{ + Counters: m.encodeCounters(counterValues), + } + + return response, nil +} + func (m *CountersService) Perf( ctx context.Context, request *ynpb.PerfCountersRequest, diff --git a/controlplane/ynpb/counters.proto b/controlplane/ynpb/counters.proto index 97c8cd365..99bd765eb 100644 --- a/controlplane/ynpb/counters.proto +++ b/controlplane/ynpb/counters.proto @@ -11,11 +11,14 @@ service CountersService { rpc Function(FunctionCountersRequest) returns (CountersResponse) {} rpc Chain(ChainCountersRequest) returns (CountersResponse) {} rpc Module(ModuleCountersRequest) returns (CountersResponse) {} + rpc NIC(NICCounterRequest) returns (CountersResponse) {} rpc Perf(PerfCountersRequest) returns (PerfCountersResponse) {} } message DeviceCountersRequest { string device = 1; } +message NICCounterRequest { string device = 1; } + message PipelineCountersRequest { string device = 1; string pipeline = 2; diff --git a/dataplane/dataplane.c b/dataplane/dataplane.c index 14d3b4e80..30bda79ee 100644 --- a/dataplane/dataplane.c +++ b/dataplane/dataplane.c @@ -617,11 +617,7 @@ stat_thread(void *arg) { struct rte_eth_xstat_name names[4096]; struct rte_eth_xstat xstats0[dataplane->device_count][4096]; - struct rte_eth_stats stats0[dataplane->device_count]; for (uint16_t idx = 0; idx < dataplane->device_count; ++idx) { - rte_eth_stats_get( - dataplane->devices[idx].port_id, &stats0[idx] - ); rte_eth_xstats_get( dataplane->devices[idx].port_id, xstats0[idx], 4096 ); @@ -631,26 +627,6 @@ stat_thread(void *arg) { sleep(1); for (uint16_t idx = 0; idx < dataplane->device_count; ++idx) { - struct rte_eth_stats stats1; - rte_eth_stats_get( - dataplane->devices[idx].port_id, &stats1 - ); - fprintf(log, - "dev %u ib %li ob %li ip %li op %li ie %li oe " - "%li\n", - idx, - (int64_t)(stats1.ibytes - stats0[idx].ibytes), - (int64_t)(stats1.obytes - stats0[idx].obytes), - (int64_t)(stats1.ipackets - stats0[idx].ipackets - ), - (int64_t)(stats1.opackets - stats0[idx].opackets - ), - (int64_t)(stats1.ierrors - stats0[idx].ierrors), - (int64_t)(stats1.oerrors - stats0[idx].oerrors) - ); - - memcpy(&stats0[idx], &stats1, sizeof(stats1)); - struct rte_eth_xstat xstats1[4096]; rte_eth_xstats_get_names( dataplane->devices[idx].port_id, names, 4096 diff --git a/dataplane/worker.c b/dataplane/worker.c index 60cc8c7cf..6036f88b2 100644 --- a/dataplane/worker.c +++ b/dataplane/worker.c @@ -55,6 +55,8 @@ #include +#define NIC_STATS_FREQUENCY 1000 + static void worker_read(struct dataplane_worker *worker, struct packet_list *packets) { struct worker_read_ctx *ctx = &worker->read_ctx; @@ -271,6 +273,21 @@ worker_write(struct dataplane_worker *worker, struct packet_list *packets) { } } +void worker_unload_nic_stats(struct dataplane_worker *worker) { + struct rte_eth_stats stats1; + struct dp_worker *dp_worker = worker->dp_worker; + + rte_eth_stats_get(worker->port_id, &stats1); + + *dp_worker->nic_rx_bytes = stats1.ibytes; + *dp_worker->nic_tx_bytes = stats1.obytes; + *dp_worker->nic_rx_packets = stats1.ipackets; + *dp_worker->nic_tx_packets = stats1.opackets; + *dp_worker->nic_rx_errors = stats1.ierrors; + *dp_worker->nic_tx_errors = stats1.oerrors; + *dp_worker->nic_rx_nombuf = stats1.rx_nombuf; +} + static void worker_loop_round(struct dataplane_worker *worker) { // Initialize current worker time @@ -313,7 +330,10 @@ worker_loop_round(struct dataplane_worker *worker) { cp_config_gen->device_registry.registry.capacity; while (1) { - + if (*worker->dp_worker->iterations % NIC_STATS_FREQUENCY == 0) { + worker_unload_nic_stats(worker); + } + struct packet_front schedule_input[device_count]; for (uint64_t idx = 0; idx < device_count; ++idx) packet_front_init(schedule_input + idx); @@ -406,6 +426,32 @@ worker_thread_start(void *arg) { return NULL; } +static const struct { + const char *name; + uint64_t size; + const size_t *offset; +} worker_counter_info[] = { + {"iterations", 1, (const size_t[]){offsetof(struct dp_worker, iterations)}}, + {"rx", 2, (const size_t[]){offsetof(struct dp_worker, rx_count), offsetof(struct dp_worker, rx_size)}}, + {"tx", 2, (const size_t[]){offsetof(struct dp_worker, tx_count), offsetof(struct dp_worker, tx_size)}}, + {"remote_rx", 1, (const size_t[]){offsetof(struct dp_worker, remote_rx_count)}}, + {"remote_tx", 1, (const size_t[]){offsetof(struct dp_worker, remote_tx_count)}}, + {"nic_rx", 2, (const size_t[]){offsetof(struct dp_worker, nic_rx_packets), offsetof(struct dp_worker, nic_rx_bytes)}}, + {"nic_tx", 2, (const size_t[]){offsetof(struct dp_worker, nic_tx_packets), offsetof(struct dp_worker, nic_tx_bytes)}}, + {"nic_rx_tx_errors", 2, (const size_t[]){offsetof(struct dp_worker, nic_rx_errors), offsetof(struct dp_worker, nic_tx_errors)}}, + {"nic_rx_nombuf", 1, (const size_t[]){offsetof(struct dp_worker, nic_rx_nombuf)}}, +}; + +uint64_t** +get_worker_field_ptr(struct dp_worker *worker, size_t info_index, size_t offset_index) { + return (uint64_t**)((char*)worker + worker_counter_info[info_index].offset[offset_index]); +} + +#define ARRAY_SIZE(arr) (size_t)(sizeof(arr) / sizeof((arr)[0])) + +static uint64_t +worker_counter_ids[ARRAY_SIZE(worker_counter_info)]; + int dataplane_worker_init( struct dataplane *dataplane, @@ -551,14 +597,14 @@ dataplane_worker_init( counter_registry_init( &dp_config->worker_counters, &dp_config->memory_context, 0 ); - - counter_registry_register(&dp_config->worker_counters, "iterations", 1); - - counter_registry_register(&dp_config->worker_counters, "rx", 2); - counter_registry_register(&dp_config->worker_counters, "tx", 2); - counter_registry_register(&dp_config->worker_counters, "remote_rx", 2); - - counter_registry_register(&dp_config->worker_counters, "remote_tx", 2); + + for (size_t i = 0; i < ARRAY_SIZE(worker_counter_info); ++i) { + worker_counter_ids[i] = counter_registry_register( + &dp_config->worker_counters, + worker_counter_info[i].name, + worker_counter_info[i].size + ); + } return 0; @@ -574,53 +620,18 @@ dataplane_worker_start(struct dataplane_worker *worker) { struct dp_worker *dp_worker = worker->dp_worker; struct dp_config *dp_config = worker->instance->dp_config; // FIXME: do not use hard-coded counter identifiers - dp_worker->iterations = counter_get_address( - 0, dp_worker->idx, ADDR_OF(&dp_config->worker_counter_storage) - ); - dp_worker->rx_count = - counter_get_address( - 1, - dp_worker->idx, - ADDR_OF(&dp_config->worker_counter_storage) - ) + - 0; - dp_worker->rx_size = counter_get_address( - 1, - dp_worker->idx, - ADDR_OF(&dp_config->worker_counter_storage) - ) + - 1; - - dp_worker->tx_count = - counter_get_address( - 2, - dp_worker->idx, - ADDR_OF(&dp_config->worker_counter_storage) - ) + - 0; - dp_worker->tx_size = counter_get_address( - 2, - dp_worker->idx, - ADDR_OF(&dp_config->worker_counter_storage) - ) + - 1; - - dp_worker->remote_rx_count = - counter_get_address( - 3, - dp_worker->idx, - ADDR_OF(&dp_config->worker_counter_storage) - ) + - 0; - - dp_worker->remote_tx_count = - counter_get_address( - 4, - dp_worker->idx, - ADDR_OF(&dp_config->worker_counter_storage) - ) + - 0; + for (size_t i = 0; i < ARRAY_SIZE(worker_counter_info); ++i) { + for (size_t j = 0; j < worker_counter_info[i].size; ++j) { + uint64_t **field_ptr = get_worker_field_ptr(dp_worker, i, j); + *field_ptr = counter_get_address( + worker_counter_ids[i], + dp_worker->idx, + ADDR_OF(&dp_config->worker_counter_storage) + ) + j; + } + } + pthread_attr_t wrk_th_attr; pthread_attr_init(&wrk_th_attr); diff --git a/lib/controlplane/agent/agent.c b/lib/controlplane/agent/agent.c index cbe065c04..f91a1a2f0 100644 --- a/lib/controlplane/agent/agent.c +++ b/lib/controlplane/agent/agent.c @@ -1648,6 +1648,68 @@ yanet_get_device_counters( return list; } +struct counter_handle_list * +yanet_get_nic_counters(struct dp_config *dp_config) { + const char *query[] = { + "nic_rx", + "nic_tx", + "nic_rx_tx_errors", + "nic_rx_nombuf", + }; + int query_count = sizeof(query) / sizeof(query[0]); + + struct counter_registry *counter_registry = &dp_config->worker_counters; + struct counter_storage *storage = + ADDR_OF(&dp_config->worker_counter_storage); + + uint64_t count = counter_registry->count; + struct counter *names = ADDR_OF(&counter_registry->names); + + uint64_t match_count = 0; + + for (uint64_t idx = 0; idx < count; ++idx) { + if (!counter_name_matches_query( + names[idx].name, query, query_count + )) { + continue; + } + + match_count++; + } + + if (match_count == 0) { + return NULL; + } + + struct counter_handle_list *list = (struct counter_handle_list *)malloc( + sizeof(struct counter_handle_list) + + sizeof(struct counter_handle) * match_count + ); + + if (list == NULL) + return NULL; + list->instance_count = ADDR_OF(&storage->allocator)->instance_count; + list->count = count; + struct counter_handle *handlers = list->counters; + + uint64_t out_idx = 0; + for (uint64_t idx = 0; idx < count; ++idx) { + if (!counter_name_matches_query( + names[idx].name, query, query_count + )) { + continue; + } + strtcpy(handlers[out_idx].name, names[idx].name, 60); + handlers[out_idx].size = names[idx].size; + handlers[out_idx].gen = names[idx].gen; + handlers[out_idx].value_handle = + counter_get_value_handle(idx, storage); + out_idx++; + } + + return list; +} + struct counter_handle * yanet_get_counter(struct counter_handle_list *counters, uint64_t idx) { if (idx >= counters->count) diff --git a/lib/dataplane/config/zone.h b/lib/dataplane/config/zone.h index 1c6643145..a245505ae 100644 --- a/lib/dataplane/config/zone.h +++ b/lib/dataplane/config/zone.h @@ -62,6 +62,21 @@ struct dp_worker { struct rte_mempool *rx_mempool; uint8_t pad[24]; + + // trade-off: nic stats unload not often + // bcs put it in second cache line + uint64_t *nic_rx_packets; + uint64_t *nic_rx_bytes; + + uint64_t *nic_tx_packets; + uint64_t *nic_tx_bytes; + + uint64_t *nic_rx_errors; + uint64_t *nic_tx_errors; + + uint64_t *nic_rx_nombuf; + + uint8_t pad2[8]; }; struct dp_config { uint32_t instance_count;