From 742b0a57f50e4b7442b22e321c98aa187edb7103 Mon Sep 17 00:00:00 2001 From: Cristian Dumitrescu Date: Sat, 17 Apr 2021 00:46:41 +0100 Subject: [PATCH] pipeline: add table statistics to SWX Add support for table statistics for the SWX pipeline. For each table, we maintain a counter for lookup hit packets, one for lookup miss packets and one packet counter for each table action. Signed-off-by: Cristian Dumitrescu Signed-off-by: Yogesh Jangra --- examples/pipeline/cli.c | 54 +++++++++++++++++++++++- lib/librte_pipeline/rte_swx_ctl.h | 38 +++++++++++++++++ lib/librte_pipeline/rte_swx_pipeline.c | 57 +++++++++++++++++++++++++- lib/librte_pipeline/version.map | 1 + 4 files changed, 148 insertions(+), 2 deletions(-) diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c index 9d7d69d346..b5295c6c46 100644 --- a/examples/pipeline/cli.c +++ b/examples/pipeline/cli.c @@ -1802,7 +1802,7 @@ cmd_pipeline_stats(char **tokens, out += strlen(out); } - snprintf(out, out_size, "Output ports:\n"); + snprintf(out, out_size, "\nOutput ports:\n"); out_size -= strlen(out); out += strlen(out); @@ -1818,6 +1818,58 @@ cmd_pipeline_stats(char **tokens, out_size -= strlen(out); out += strlen(out); } + + snprintf(out, out_size, "\nTables:\n"); + out_size -= strlen(out); + out += strlen(out); + + for (i = 0; i < info.n_tables; i++) { + struct rte_swx_ctl_table_info table_info; + uint64_t n_pkts_action[info.n_actions]; + struct rte_swx_table_stats stats = { + .n_pkts_hit = 0, + .n_pkts_miss = 0, + .n_pkts_action = n_pkts_action, + }; + uint32_t j; + + status = rte_swx_ctl_table_info_get(p->p, i, &table_info); + if (status) { + snprintf(out, out_size, "Table info get error."); + return; + } + + status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats); + if (status) { + snprintf(out, out_size, "Table stats read error."); + return; + } + + snprintf(out, out_size, "\tTable %s:\n" + "\t\tHit (packets): %" PRIu64 "\n" + "\t\tMiss (packets): %" PRIu64 "\n", + table_info.name, + stats.n_pkts_hit, + stats.n_pkts_miss); + out_size -= strlen(out); + out += strlen(out); + + for (j = 0; j < info.n_actions; j++) { + struct rte_swx_ctl_action_info action_info; + + status = rte_swx_ctl_action_info_get(p->p, j, &action_info); + if (status) { + snprintf(out, out_size, "Action info get error."); + return; + } + + snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", + action_info.name, + stats.n_pkts_action[j]); + out_size -= strlen(out); + out += strlen(out); + } + } } static const char cmd_thread_pipeline_enable_help[] = diff --git a/lib/librte_pipeline/rte_swx_ctl.h b/lib/librte_pipeline/rte_swx_ctl.h index b8f22c516e..2e3f00d1fb 100644 --- a/lib/librte_pipeline/rte_swx_ctl.h +++ b/lib/librte_pipeline/rte_swx_ctl.h @@ -341,6 +341,44 @@ rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p, struct rte_swx_table_ops *table_ops, int *is_stub); +/** Table statistics. */ +struct rte_swx_table_stats { + /** Number of packets with lookup hit. */ + uint64_t n_pkts_hit; + + /** Number of packets with lookup miss. */ + uint64_t n_pkts_miss; + + /** Number of packets (with either lookup hit or miss) per pipeline + * action. Array of pipeline *n_actions* elements indedex by the + * pipeline-level *action_id*, therefore this array has the same size + * for all the tables within the same pipeline. + */ + uint64_t *n_pkts_action; +}; + +/** + * Table statistics counters read + * + * @param[in] p + * Pipeline handle. + * @param[in] table_name + * Table name. + * @param[out] stats + * Table stats. Must point to a pre-allocated structure. The *n_pkts_action* + * field also needs to be pre-allocated as array of pipeline *n_actions* + * elements. The pipeline actions that are not valid for the current table + * have their associated *n_pkts_action* element always set to zero. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p, + const char *table_name, + struct rte_swx_table_stats *stats); + /* * Table Update API. */ diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c index d4d612409a..1b3bf6269e 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -776,6 +776,11 @@ struct table_runtime { uint8_t **key; }; +struct table_statistics { + uint64_t n_pkts_hit[2]; /* 0 = Miss, 1 = Hit. */ + uint64_t *n_pkts_action; +}; + /* * Register array. */ @@ -1214,6 +1219,7 @@ struct rte_swx_pipeline { struct port_out_runtime *out; struct instruction **action_instructions; struct rte_swx_table_state *table_state; + struct table_statistics *table_stats; struct regarray_runtime *regarray_runtime; struct metarray_runtime *metarray_runtime; struct instruction *instructions; @@ -3354,7 +3360,8 @@ instr_table_exec(struct rte_swx_pipeline *p) uint32_t table_id = ip->table.table_id; struct rte_swx_table_state *ts = &t->table_state[table_id]; struct table_runtime *table = &t->tables[table_id]; - uint64_t action_id; + struct table_statistics *stats = &p->table_stats[table_id]; + uint64_t action_id, n_pkts_hit, n_pkts_action; uint8_t *action_data; int done, hit; @@ -3377,6 +3384,8 @@ instr_table_exec(struct rte_swx_pipeline *p) action_id = hit ? action_id : ts->default_action_id; action_data = hit ? action_data : ts->default_action_data; + n_pkts_hit = stats->n_pkts_hit[hit]; + n_pkts_action = stats->n_pkts_action[action_id]; TRACE("[Thread %2u] table %u (%s, action %u)\n", p->thread_id, @@ -3387,6 +3396,8 @@ instr_table_exec(struct rte_swx_pipeline *p) t->action_id = action_id; t->structs[0] = action_data; t->hit = hit; + stats->n_pkts_hit[hit] = n_pkts_hit + 1; + stats->n_pkts_action[action_id] = n_pkts_action + 1; /* Thread. */ thread_ip_action_call(p, t, action_id); @@ -8950,6 +8961,16 @@ table_build(struct rte_swx_pipeline *p) { uint32_t i; + /* Per pipeline: table statistics. */ + p->table_stats = calloc(p->n_tables, sizeof(struct table_statistics)); + CHECK(p->table_stats, ENOMEM); + + for (i = 0; i < p->n_tables; i++) { + p->table_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); + CHECK(p->table_stats[i].n_pkts_action, ENOMEM); + } + + /* Per thread: table runt-time. */ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { struct thread *t = &p->threads[i]; struct table *table; @@ -9008,6 +9029,13 @@ table_build_free(struct rte_swx_pipeline *p) free(t->tables); t->tables = NULL; } + + if (p->table_stats) { + for (i = 0; i < p->n_tables; i++) + free(p->table_stats[i].n_pkts_action); + + free(p->table_stats); + } } static void @@ -9762,6 +9790,33 @@ rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p, return 0; } +int +rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p, + const char *table_name, + struct rte_swx_table_stats *stats) +{ + struct table *table; + struct table_statistics *table_stats; + + if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action) + return -EINVAL; + + table = table_find(p, table_name); + if (!table) + return -EINVAL; + + table_stats = &p->table_stats[table->id]; + + memcpy(&stats->n_pkts_action, + &table_stats->n_pkts_action, + p->n_actions * sizeof(uint64_t)); + + stats->n_pkts_hit = table_stats->n_pkts_hit[1]; + stats->n_pkts_miss = table_stats->n_pkts_hit[0]; + + return 0; +} + int rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p, uint32_t regarray_id, diff --git a/lib/librte_pipeline/version.map b/lib/librte_pipeline/version.map index 2049d6d694..a4d7d97882 100644 --- a/lib/librte_pipeline/version.map +++ b/lib/librte_pipeline/version.map @@ -112,6 +112,7 @@ EXPERIMENTAL { rte_swx_ctl_meter_stats_read; rte_swx_ctl_pipeline_regarray_read; rte_swx_ctl_pipeline_regarray_write; + rte_swx_ctl_pipeline_table_stats_read; rte_swx_ctl_regarray_info_get; rte_swx_pipeline_metarray_config; rte_swx_pipeline_regarray_config; -- 2.20.1