From patchwork Fri Apr 16 23:46:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 91691 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 045BBA0A02; Sat, 17 Apr 2021 01:46:46 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6EC564068F; Sat, 17 Apr 2021 01:46:46 +0200 (CEST) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by mails.dpdk.org (Postfix) with ESMTP id 6500140143 for ; Sat, 17 Apr 2021 01:46:44 +0200 (CEST) IronPort-SDR: 9KQA2WCv7iimIQLpGY1iZC6o6rieJoW+e01ZfCVFpUVEfuoW5KAoVPXaTL8y1CJIM5Ocgx7HyR WQBWtOyFzkcw== X-IronPort-AV: E=McAfee;i="6200,9189,9956"; a="194687935" X-IronPort-AV: E=Sophos;i="5.82,228,1613462400"; d="scan'208";a="194687935" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Apr 2021 16:46:43 -0700 IronPort-SDR: cU7/qkNJi0jNGgfUkOUgkT8WZCpxxQFM5cLGqdWpDOn4fJXe1IzCAj108XxL2rqxGobQzQu62L axxqLMb+wG0A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.82,228,1613462400"; d="scan'208";a="444638229" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by fmsmga004.fm.intel.com with ESMTP; 16 Apr 2021 16:46:42 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Cc: Yogesh Jangra Date: Sat, 17 Apr 2021 00:46:41 +0100 Message-Id: <20210416234641.16304-1-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 Subject: [dpdk-dev] [PATCH] pipeline: add table statistics X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 ef47febaa..215dd8e85 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 4e5befb50..dee788be8 100644 --- a/lib/librte_pipeline/rte_swx_ctl.h +++ b/lib/librte_pipeline/rte_swx_ctl.h @@ -347,6 +347,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 aeb445755..4e358bbda 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -789,6 +789,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. */ @@ -1311,6 +1316,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; @@ -3473,7 +3479,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; @@ -3496,6 +3503,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, @@ -3506,6 +3515,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); @@ -9537,6 +9548,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; @@ -9595,6 +9616,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 @@ -10350,6 +10378,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 2049d6d69..a4d7d9788 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;