pipeline: add table statistics to SWX
authorCristian Dumitrescu <cristian.dumitrescu@intel.com>
Fri, 16 Apr 2021 23:46:41 +0000 (00:46 +0100)
committerThomas Monjalon <thomas@monjalon.net>
Tue, 20 Apr 2021 00:27:56 +0000 (02:27 +0200)
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 <cristian.dumitrescu@intel.com>
Signed-off-by: Yogesh Jangra <yogesh.jangra@intel.com>
examples/pipeline/cli.c
lib/librte_pipeline/rte_swx_ctl.h
lib/librte_pipeline/rte_swx_pipeline.c
lib/librte_pipeline/version.map

index 9d7d69d..b5295c6 100644 (file)
@@ -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[] =
index b8f22c5..2e3f00d 100644 (file)
@@ -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.
  */
index d4d6124..1b3bf62 100644 (file)
@@ -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,
index 2049d6d..a4d7d97 100644 (file)
@@ -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;