From patchwork Wed Sep 23 11:12:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Power, Ciara" X-Patchwork-Id: 78553 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A53AEA04B1; Wed, 23 Sep 2020 13:15:31 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 814041C2F2; Wed, 23 Sep 2020 13:15:31 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id DEDFB1C2F2 for ; Wed, 23 Sep 2020 13:15:29 +0200 (CEST) IronPort-SDR: NVnczortax3C8kxPbqVQrLYQzmxvOFg82DBDgg6ftOPJYBShcsPQlxFsK9Jq/yj9XYQwzmoMM+ OqWfBrxoz1ug== X-IronPort-AV: E=McAfee;i="6000,8403,9752"; a="178932636" X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="178932636" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2020 04:15:25 -0700 IronPort-SDR: pCsFZxrss81t0KAADAwW1Oba/66nyZrFn8uolzL/JQELoG96Y3iCJvf2KOWON6BzJSBJMZPico D91w9Dp/mq3A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="347314593" Received: from silpixa00399953.ir.intel.com (HELO silpixa00399953.ger.corp.intel.com) ([10.237.222.53]) by FMSMGA003.fm.intel.com with ESMTP; 23 Sep 2020 04:15:23 -0700 From: Ciara Power To: dev@dpdk.org Cc: keith.wiles@intel.com, bruce.richardson@intel.com, Ciara Power , Kevin Laatz , Ray Kinsella , Neil Horman Date: Wed, 23 Sep 2020 12:12:26 +0100 Message-Id: <20200923111228.6274-2-ciara.power@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200923111228.6274-1-ciara.power@intel.com> References: <20200612105344.15383-1-ciara.power@intel.com> <20200923111228.6274-1-ciara.power@intel.com> Subject: [dpdk-dev] [PATCH v9 1/3] telemetry: support array values in data objects X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 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" Arrays of type uint64_t/int/string can now be included within an array or dict. One level of embedded containers is supported. This is necessary to allow for instances such as the ethdev queue stats to be reported as a list of uint64_t values, rather than having multiple dict entries with one uint64_t value for each queue stat. The memory management APIs provided by telemetry simplify the memory allocation/free aspect of the embedded container. The rte_tel_data_alloc function is called in the library/app callback to return a pointer to a container that has been allocated memory. When adding this container to an array/dict, a parameter is passed to indicate if the memory should be freed by telemetry after use. This will allow reuse of the allocated memory if the library/app wishes to do so. Signed-off-by: Ciara Power Acked-by: Bruce Richardson --- lib/librte_telemetry/rte_telemetry.h | 70 +++++++++++++++++++ .../rte_telemetry_version.map | 4 ++ lib/librte_telemetry/telemetry.c | 56 +++++++++++++++ lib/librte_telemetry/telemetry_data.c | 51 ++++++++++++++ lib/librte_telemetry/telemetry_data.h | 7 ++ lib/librte_telemetry/telemetry_json.h | 33 +++++++++ 6 files changed, 221 insertions(+) diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h index deac2e71ca..4693275c24 100644 --- a/lib/librte_telemetry/rte_telemetry.h +++ b/lib/librte_telemetry/rte_telemetry.h @@ -47,6 +47,7 @@ enum rte_tel_value_type { RTE_TEL_STRING_VAL, /** a string value */ RTE_TEL_INT_VAL, /** a signed 32-bit int value */ RTE_TEL_U64_VAL, /** an unsigned 64-bit int value */ + RTE_TEL_CONTAINER, /** a container struct */ }; /** @@ -137,6 +138,28 @@ __rte_experimental int rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x); +/** + * Add a container to an array. A container is an existing telemetry data + * array. The array the container is to be added to must have been started by + * rte_tel_data_start_array() with RTE_TEL_CONTAINER as the type parameter. + * The container type must be an array of type uint64_t/int/string. + * + * @param d + * The data structure passed to the callback + * @param val + * The pointer to the container to be stored in the array. + * @param keep + * Flag to indicate that the container memory should not be automatically + * freed by the telemetry library once it has finished with the data. + * 1 = keep, 0 = free. + * @return + * 0 on success, negative errno on error + */ +__rte_experimental +int +rte_tel_data_add_array_container(struct rte_tel_data *d, + struct rte_tel_data *val, int keep); + /** * Add a string value to a dictionary. * The dict must have been started by rte_tel_data_start_dict(). @@ -191,6 +214,30 @@ int rte_tel_data_add_dict_u64(struct rte_tel_data *d, const char *name, uint64_t val); +/** + * Add a container to a dictionary. A container is an existing telemetry data + * array. The dict the container is to be added to must have been started by + * rte_tel_data_start_dict(). The container must be an array of type + * uint64_t/int/string. + * + * @param d + * The data structure passed to the callback + * @param name + * The name the value is to be stored under in the dict. + * @param val + * The pointer to the container to be stored in the dict. + * @param keep + * Flag to indicate that the container memory should not be automatically + * freed by the telemetry library once it has finished with the data. + * 1 = keep, 0 = free. + * @return + * 0 on success, negative errno on error + */ +__rte_experimental +int +rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name, + struct rte_tel_data *val, int keep); + /** * This telemetry callback is used when registering a telemetry command. * It handles getting and formatting information to be returned to telemetry @@ -265,4 +312,27 @@ int rte_telemetry_init(const char *runtime_dir, rte_cpuset_t *cpuset, const char **err_str); +/** + * Get a pointer to a container with memory allocated. The container is to be + * used embedded within an existing telemetry dict/array. + * + * @return + * Pointer to a container. + */ +__rte_experimental +struct rte_tel_data * +rte_tel_data_alloc(void); + +/** + * @internal + * Free a container that has memory allocated. + * + * @param data + * Pointer to container. + *. + */ +__rte_experimental +void +rte_tel_data_free(struct rte_tel_data *data); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_version.map b/lib/librte_telemetry/rte_telemetry_version.map index 86433c21d0..d1dbf8d586 100644 --- a/lib/librte_telemetry/rte_telemetry_version.map +++ b/lib/librte_telemetry/rte_telemetry_version.map @@ -1,12 +1,16 @@ EXPERIMENTAL { global: + rte_tel_data_add_array_container; rte_tel_data_add_array_int; rte_tel_data_add_array_string; rte_tel_data_add_array_u64; + rte_tel_data_add_dict_container; rte_tel_data_add_dict_int; rte_tel_data_add_dict_string; rte_tel_data_add_dict_u64; + rte_tel_data_alloc; + rte_tel_data_free; rte_tel_data_start_array; rte_tel_data_start_dict; rte_tel_data_string; diff --git a/lib/librte_telemetry/telemetry.c b/lib/librte_telemetry/telemetry.c index 51e7ceeb1b..caa2c4a535 100644 --- a/lib/librte_telemetry/telemetry.c +++ b/lib/librte_telemetry/telemetry.c @@ -133,6 +133,35 @@ command_help(const char *cmd __rte_unused, const char *params, return 0; } +static int +container_to_json(const struct rte_tel_data *d, char *out_buf, size_t buf_len) +{ + size_t used = 0; + unsigned int i; + + if (d->type != RTE_TEL_ARRAY_U64 && d->type != RTE_TEL_ARRAY_INT + && d->type != RTE_TEL_ARRAY_STRING) + return snprintf(out_buf, buf_len, "null"); + + used = rte_tel_json_empty_array(out_buf, buf_len, 0); + if (d->type == RTE_TEL_ARRAY_U64) + for (i = 0; i < d->data_len; i++) + used = rte_tel_json_add_array_u64(out_buf, + buf_len, used, + d->data.array[i].u64val); + if (d->type == RTE_TEL_ARRAY_INT) + for (i = 0; i < d->data_len; i++) + used = rte_tel_json_add_array_int(out_buf, + buf_len, used, + d->data.array[i].ival); + if (d->type == RTE_TEL_ARRAY_STRING) + for (i = 0; i < d->data_len; i++) + used = rte_tel_json_add_array_string(out_buf, + buf_len, used, + d->data.array[i].sval); + return used; +} + static void output_json(const char *cmd, const struct rte_tel_data *d, int s) { @@ -179,6 +208,20 @@ output_json(const char *cmd, const struct rte_tel_data *d, int s) buf_len, used, v->name, v->value.u64val); break; + case RTE_TEL_CONTAINER: + { + char temp[buf_len]; + const struct container *cont = + &v->value.container; + if (container_to_json(cont->data, + temp, buf_len) != 0) + used = rte_tel_json_add_obj_json( + cb_data_buf, + buf_len, used, + v->name, temp); + if (!cont->keep) + rte_tel_data_free(cont->data); + } } } used += prefix_used; @@ -187,6 +230,7 @@ output_json(const char *cmd, const struct rte_tel_data *d, int s) case RTE_TEL_ARRAY_STRING: case RTE_TEL_ARRAY_INT: case RTE_TEL_ARRAY_U64: + case RTE_TEL_ARRAY_CONTAINER: prefix_used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":", MAX_CMD_LEN, cmd); cb_data_buf = &out_buf[prefix_used]; @@ -207,6 +251,18 @@ output_json(const char *cmd, const struct rte_tel_data *d, int s) used = rte_tel_json_add_array_u64(cb_data_buf, buf_len, used, d->data.array[i].u64val); + else if (d->type == RTE_TEL_ARRAY_CONTAINER) { + char temp[buf_len]; + const struct container *rec_data = + &d->data.array[i].container; + if (container_to_json(rec_data->data, + temp, buf_len) != 0) + used = rte_tel_json_add_array_json( + cb_data_buf, + buf_len, used, temp); + if (!rec_data->keep) + rte_tel_data_free(rec_data->data); + } used += prefix_used; used += strlcat(out_buf + used, "}", sizeof(out_buf) - used); break; diff --git a/lib/librte_telemetry/telemetry_data.c b/lib/librte_telemetry/telemetry_data.c index f424bbd48f..77b0fe09a5 100644 --- a/lib/librte_telemetry/telemetry_data.c +++ b/lib/librte_telemetry/telemetry_data.c @@ -14,6 +14,7 @@ rte_tel_data_start_array(struct rte_tel_data *d, enum rte_tel_value_type type) RTE_TEL_ARRAY_STRING, /* RTE_TEL_STRING_VAL = 0 */ RTE_TEL_ARRAY_INT, /* RTE_TEL_INT_VAL = 1 */ RTE_TEL_ARRAY_U64, /* RTE_TEL_u64_VAL = 2 */ + RTE_TEL_ARRAY_CONTAINER, /* RTE_TEL_CONTAINER = 3 */ }; d->type = array_types[type]; d->data_len = 0; @@ -74,6 +75,23 @@ rte_tel_data_add_array_u64(struct rte_tel_data *d, uint64_t x) return 0; } +int +rte_tel_data_add_array_container(struct rte_tel_data *d, + struct rte_tel_data *val, int keep) +{ + if (d->type != RTE_TEL_ARRAY_CONTAINER || + (val->type != RTE_TEL_ARRAY_U64 + && val->type != RTE_TEL_ARRAY_INT + && val->type != RTE_TEL_ARRAY_STRING)) + return -EINVAL; + if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES) + return -ENOSPC; + + d->data.array[d->data_len].container.data = val; + d->data.array[d->data_len++].container.keep = !!keep; + return 0; +} + int rte_tel_data_add_dict_string(struct rte_tel_data *d, const char *name, const char *val) @@ -128,3 +146,36 @@ rte_tel_data_add_dict_u64(struct rte_tel_data *d, const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG; } + +int +rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name, + struct rte_tel_data *val, int keep) +{ + struct tel_dict_entry *e = &d->data.dict[d->data_len]; + + if (d->type != RTE_TEL_DICT || (val->type != RTE_TEL_ARRAY_U64 + && val->type != RTE_TEL_ARRAY_INT + && val->type != RTE_TEL_ARRAY_STRING)) + return -EINVAL; + if (d->data_len >= RTE_TEL_MAX_DICT_ENTRIES) + return -ENOSPC; + + d->data_len++; + e->type = RTE_TEL_CONTAINER; + e->value.container.data = val; + e->value.container.keep = !!keep; + const size_t bytes = strlcpy(e->name, name, RTE_TEL_MAX_STRING_LEN); + return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG; +} + +struct rte_tel_data * +rte_tel_data_alloc(void) +{ + return malloc(sizeof(struct rte_tel_data)); +} + +void +rte_tel_data_free(struct rte_tel_data *data) +{ + free(data); +} diff --git a/lib/librte_telemetry/telemetry_data.h b/lib/librte_telemetry/telemetry_data.h index ff3a371a33..adb84a09f1 100644 --- a/lib/librte_telemetry/telemetry_data.h +++ b/lib/librte_telemetry/telemetry_data.h @@ -15,6 +15,12 @@ enum tel_container_types { RTE_TEL_ARRAY_STRING, /** array of string values only */ RTE_TEL_ARRAY_INT, /** array of signed, 32-bit int values */ RTE_TEL_ARRAY_U64, /** array of unsigned 64-bit int values */ + RTE_TEL_ARRAY_CONTAINER, /** array of container structs */ +}; + +struct container { + struct rte_tel_data *data; + int keep; }; /* each type here must have an equivalent enum in the value types enum in @@ -25,6 +31,7 @@ union tel_value { char sval[RTE_TEL_MAX_STRING_LEN]; int ival; uint64_t u64val; + struct container container; }; struct tel_dict_entry { diff --git a/lib/librte_telemetry/telemetry_json.h b/lib/librte_telemetry/telemetry_json.h index a2ce4899e0..ad270b9b30 100644 --- a/lib/librte_telemetry/telemetry_json.h +++ b/lib/librte_telemetry/telemetry_json.h @@ -102,6 +102,22 @@ rte_tel_json_add_array_u64(char *buf, const int len, const int used, return ret == 0 ? used : end + ret; } +/* + * Add a new element with raw JSON value to the JSON array stored in the + * provided buffer. + */ +static inline int +rte_tel_json_add_array_json(char *buf, const int len, const int used, + const char *str) +{ + int ret, end = used - 1; /* strip off final delimiter */ + if (used <= 2) /* assume empty, since minimum is '[]' */ + return __json_snprintf(buf, len, "[%s]", str); + + ret = __json_snprintf(buf + end, len - end, ",%s]", str); + return ret == 0 ? used : end + ret; +} + /** * Add a new element with uint64_t value to the JSON object stored in the * provided buffer. @@ -155,4 +171,21 @@ rte_tel_json_add_obj_str(char *buf, const int len, const int used, return ret == 0 ? used : end + ret; } +/** + * Add a new element with raw JSON value to the JSON object stored in the + * provided buffer. + */ +static inline int +rte_tel_json_add_obj_json(char *buf, const int len, const int used, + const char *name, const char *val) +{ + int ret, end = used - 1; + if (used <= 2) /* assume empty, since minimum is '{}' */ + return __json_snprintf(buf, len, "{\"%s\":%s}", name, val); + + ret = __json_snprintf(buf + end, len - end, ",\"%s\":%s}", + name, val); + return ret == 0 ? used : end + ret; +} + #endif /*_RTE_TELEMETRY_JSON_H_*/ From patchwork Wed Sep 23 11:12:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Power, Ciara" X-Patchwork-Id: 78556 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 96084A04B1; Wed, 23 Sep 2020 13:15:53 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 0ADA91DBE1; Wed, 23 Sep 2020 13:15:37 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id BA4E41DB4D for ; Wed, 23 Sep 2020 13:15:31 +0200 (CEST) IronPort-SDR: wTwDCwfGxxzfH1FLOol1vQsK6VRuui4TgQoKkt6w6FYvSSrjcIutrHA9MMcPQER3TrawO1cd4a Kyz8fiBcyBVA== X-IronPort-AV: E=McAfee;i="6000,8403,9752"; a="178932651" X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="178932651" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2020 04:15:27 -0700 IronPort-SDR: +iiKpKxgBsRVRNAA8uACG4lTOBZypkoAt9XvsZBUDyV5eg6RCpp4uy4Lf2KNJsvxNHOMKI8LuZ fVE6XYN+yG2g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="347314607" Received: from silpixa00399953.ir.intel.com (HELO silpixa00399953.ger.corp.intel.com) ([10.237.222.53]) by FMSMGA003.fm.intel.com with ESMTP; 23 Sep 2020 04:15:25 -0700 From: Ciara Power To: dev@dpdk.org Cc: keith.wiles@intel.com, bruce.richardson@intel.com, Louise Kilheeney , Ciara Power , Kevin Laatz Date: Wed, 23 Sep 2020 12:12:27 +0100 Message-Id: <20200923111228.6274-3-ciara.power@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200923111228.6274-1-ciara.power@intel.com> References: <20200612105344.15383-1-ciara.power@intel.com> <20200923111228.6274-1-ciara.power@intel.com> Subject: [dpdk-dev] [PATCH v9 2/3] test/test_telemetry_data: add unit tests for data to JSON X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 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" From: Louise Kilheeney This patch adds tests for verifying telemetry data structures are converted to JSON as expected. Both flat and recursive data structures are tested, for all possible value types. The app connects to the telemetry socket as a client, and registers one command with a corresponding callback function. Each time the callback function is called, it copies a global data variable to the data pointer passed in by telemetry. When a test case is run, the test case function builds up the global data variable with the relevant data types, and the expected json string output which should be generated from that. The 'test_output()' function is used to trigger the callback and ensure the actual output matches that expected. Signed-off-by: Louise Kilheeney Signed-off-by: Ciara Power Acked-by: Bruce Richardson --- v9: Removed Makefile entry as this is removed on main branch. --- app/test/meson.build | 5 +- app/test/test_telemetry_data.c | 369 +++++++++++++++++++++++++++++++++ 2 files changed, 372 insertions(+), 2 deletions(-) create mode 100644 app/test/test_telemetry_data.c diff --git a/app/test/meson.build b/app/test/meson.build index 181e870290..dedf29dd7f 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -171,6 +171,7 @@ test_deps = ['acl', 'ring', 'security', 'stack', + 'telemetry', 'timer' ] @@ -347,8 +348,8 @@ if dpdk_conf.has('RTE_LIBRTE_SKELETON_EVENTDEV_PMD') test_deps += 'pmd_skeleton_event' endif if dpdk_conf.has('RTE_LIBRTE_TELEMETRY') - test_sources += 'test_telemetry_json.c' - fast_tests += [['telemetry_json_autotest', true]] + test_sources += ['test_telemetry_json.c', 'test_telemetry_data.c'] + fast_tests += [['telemetry_json_autotest', true], ['telemetry_data_autotest', true]] endif # The following linkages of drivers are required because diff --git a/app/test/test_telemetry_data.c b/app/test/test_telemetry_data.c new file mode 100644 index 0000000000..7a31e68a78 --- /dev/null +++ b/app/test/test_telemetry_data.c @@ -0,0 +1,369 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2020 Intel Corporation + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "test.h" +#include "telemetry_data.h" + +#define TELEMETRY_VERSION "v2" +#define REQUEST_CMD "/test" +#define BUF_SIZE 1024 +#define TEST_OUTPUT(exp) test_output(__func__, exp) + +static struct rte_tel_data response_data; +static int sock; + +/* + * This function is the callback registered with Telemetry to be used when + * the /test command is requested. This callback returns the global data built + * up by the individual test cases. + */ +static int +test_cb(const char *cmd __rte_unused, const char *params __rte_unused, + struct rte_tel_data *d) +{ + *d = response_data; + return 0; +} + +/* + * This function is called by each test case function. It communicates with + * the telemetry socket by requesting the /test command, and reading the + * response. The expected response is passed in by the test case function, + * and is compared to the actual response received from Telemetry. + */ +static int +test_output(const char *func_name, const char *expected) +{ + int bytes; + char buf[BUF_SIZE * 16]; + if (write(sock, REQUEST_CMD, strlen(REQUEST_CMD)) < 0) { + printf("%s: Error with socket write - %s\n", __func__, + strerror(errno)); + return -1; + } + bytes = read(sock, buf, sizeof(buf) - 1); + if (bytes < 0) { + printf("%s: Error with socket read - %s\n", __func__, + strerror(errno)); + return -1; + } + buf[bytes] = '\0'; + printf("%s: buf = '%s', expected = '%s'\n", func_name, buf, expected); + return strncmp(expected, buf, sizeof(buf)); +} + +static int +test_dict_with_array_int_values(void) +{ + int i; + + struct rte_tel_data *child_data = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data, RTE_TEL_INT_VAL); + + struct rte_tel_data *child_data2 = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data2, RTE_TEL_INT_VAL); + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_dict(&response_data); + + for (i = 0; i < 5; i++) { + rte_tel_data_add_array_int(child_data, i); + rte_tel_data_add_array_int(child_data2, i); + } + + rte_tel_data_add_dict_container(&response_data, "dict_0", + child_data, 0); + rte_tel_data_add_dict_container(&response_data, "dict_1", + child_data2, 0); + + return TEST_OUTPUT("{\"/test\":{\"dict_0\":[0,1,2,3,4]," + "\"dict_1\":[0,1,2,3,4]}}"); +} + +static int +test_array_with_array_int_values(void) +{ + int i; + + struct rte_tel_data *child_data = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data, RTE_TEL_INT_VAL); + + struct rte_tel_data *child_data2 = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data2, RTE_TEL_INT_VAL); + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); + + for (i = 0; i < 5; i++) { + rte_tel_data_add_array_int(child_data, i); + rte_tel_data_add_array_int(child_data2, i); + } + rte_tel_data_add_array_container(&response_data, child_data, 0); + rte_tel_data_add_array_container(&response_data, child_data2, 0); + + return TEST_OUTPUT("{\"/test\":[[0,1,2,3,4],[0,1,2,3,4]]}"); +} + +static int +test_case_array_int(void) +{ + int i; + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_array(&response_data, RTE_TEL_INT_VAL); + for (i = 0; i < 5; i++) + rte_tel_data_add_array_int(&response_data, i); + return TEST_OUTPUT("{\"/test\":[0,1,2,3,4]}"); +} + +static int +test_case_add_dict_int(void) +{ + int i = 0; + char name_of_value[8]; + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_dict(&response_data); + + for (i = 0; i < 5; i++) { + sprintf(name_of_value, "dict_%d", i); + rte_tel_data_add_dict_int(&response_data, name_of_value, i); + } + + return TEST_OUTPUT("{\"/test\":{\"dict_0\":0,\"dict_1\":1,\"dict_2\":2," + "\"dict_3\":3,\"dict_4\":4}}"); +} + +static int +test_case_array_string(void) +{ + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_array(&response_data, RTE_TEL_STRING_VAL); + rte_tel_data_add_array_string(&response_data, "aaaa"); + rte_tel_data_add_array_string(&response_data, "bbbb"); + rte_tel_data_add_array_string(&response_data, "cccc"); + rte_tel_data_add_array_string(&response_data, "dddd"); + rte_tel_data_add_array_string(&response_data, "eeee"); + + return TEST_OUTPUT("{\"/test\":[\"aaaa\",\"bbbb\",\"cccc\",\"dddd\"," + "\"eeee\"]}"); +} + +static int +test_case_add_dict_string(void) +{ + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_dict(&response_data); + + rte_tel_data_add_dict_string(&response_data, "dict_0", "aaaa"); + rte_tel_data_add_dict_string(&response_data, "dict_1", "bbbb"); + rte_tel_data_add_dict_string(&response_data, "dict_2", "cccc"); + rte_tel_data_add_dict_string(&response_data, "dict_3", "dddd"); + + return TEST_OUTPUT("{\"/test\":{\"dict_0\":\"aaaa\",\"dict_1\":" + "\"bbbb\",\"dict_2\":\"cccc\",\"dict_3\":\"dddd\"}}"); +} + + +static int +test_dict_with_array_string_values(void) +{ + struct rte_tel_data *child_data = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data, RTE_TEL_STRING_VAL); + + struct rte_tel_data *child_data2 = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data2, RTE_TEL_STRING_VAL); + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_dict(&response_data); + + rte_tel_data_add_array_string(child_data, "aaaa"); + rte_tel_data_add_array_string(child_data2, "bbbb"); + + rte_tel_data_add_dict_container(&response_data, "dict_0", + child_data, 0); + rte_tel_data_add_dict_container(&response_data, "dict_1", + child_data2, 0); + + return TEST_OUTPUT("{\"/test\":{\"dict_0\":[\"aaaa\"],\"dict_1\":" + "[\"bbbb\"]}}"); +} + +static int +test_array_with_array_string_values(void) +{ + struct rte_tel_data *child_data = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data, RTE_TEL_STRING_VAL); + + struct rte_tel_data *child_data2 = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data2, RTE_TEL_STRING_VAL); + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); + + rte_tel_data_add_array_string(child_data, "aaaa"); + rte_tel_data_add_array_string(child_data2, "bbbb"); + + rte_tel_data_add_array_container(&response_data, child_data, 0); + rte_tel_data_add_array_container(&response_data, child_data2, 0); + + return TEST_OUTPUT("{\"/test\":[[\"aaaa\"],[\"bbbb\"]]}"); +} + +static int +test_case_array_u64(void) +{ + int i; + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_array(&response_data, RTE_TEL_U64_VAL); + for (i = 0; i < 5; i++) + rte_tel_data_add_array_u64(&response_data, i); + return TEST_OUTPUT("{\"/test\":[0,1,2,3,4]}"); +} + +static int +test_case_add_dict_u64(void) +{ + int i = 0; + char name_of_value[8]; + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_dict(&response_data); + + for (i = 0; i < 5; i++) { + sprintf(name_of_value, "dict_%d", i); + rte_tel_data_add_dict_u64(&response_data, name_of_value, i); + } + return TEST_OUTPUT("{\"/test\":{\"dict_0\":0,\"dict_1\":1,\"dict_2\":2," + "\"dict_3\":3,\"dict_4\":4}}"); +} + +static int +test_dict_with_array_u64_values(void) +{ + int i; + + struct rte_tel_data *child_data = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data, RTE_TEL_U64_VAL); + + struct rte_tel_data *child_data2 = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data2, RTE_TEL_U64_VAL); + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_dict(&response_data); + + for (i = 0; i < 10; i++) { + rte_tel_data_add_array_u64(child_data, i); + rte_tel_data_add_array_u64(child_data2, i); + } + + rte_tel_data_add_dict_container(&response_data, "dict_0", + child_data, 0); + rte_tel_data_add_dict_container(&response_data, "dict_1", + child_data2, 0); + + return TEST_OUTPUT("{\"/test\":{\"dict_0\":[0,1,2,3,4,5,6,7,8,9]," + "\"dict_1\":[0,1,2,3,4,5,6,7,8,9]}}"); +} + +static int +test_array_with_array_u64_values(void) +{ + int i; + + struct rte_tel_data *child_data = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data, RTE_TEL_U64_VAL); + + struct rte_tel_data *child_data2 = rte_tel_data_alloc(); + rte_tel_data_start_array(child_data2, RTE_TEL_U64_VAL); + + memset(&response_data, 0, sizeof(response_data)); + rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); + + for (i = 0; i < 5; i++) { + rte_tel_data_add_array_u64(child_data, i); + rte_tel_data_add_array_u64(child_data2, i); + } + rte_tel_data_add_array_container(&response_data, child_data, 0); + rte_tel_data_add_array_container(&response_data, child_data2, 0); + + return TEST_OUTPUT("{\"/test\":[[0,1,2,3,4],[0,1,2,3,4]]}"); +} + +static int +connect_to_socket(void) +{ + char buf[BUF_SIZE]; + int sock, bytes; + struct sockaddr_un telem_addr; + + sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (sock < 0) { + printf("\n%s: Error creating socket: %s\n", __func__, + strerror(errno)); + return -1; + } + telem_addr.sun_family = AF_UNIX; + snprintf(telem_addr.sun_path, sizeof(telem_addr.sun_path), + "%s/dpdk_telemetry.%s", rte_eal_get_runtime_dir(), + TELEMETRY_VERSION); + if (connect(sock, (struct sockaddr *) &telem_addr, + sizeof(telem_addr)) < 0) + printf("\n%s: Error connecting to socket: %s\n", __func__, + strerror(errno)); + + bytes = read(sock, buf, sizeof(buf) - 1); + if (bytes < 0) { + printf("%s: Error with socket read - %s\n", __func__, + strerror(errno)); + return -1; + } + buf[bytes] = '\0'; + printf("\n%s: %s\n", __func__, buf); + return sock; +} + +static int +test_telemetry_data(void) +{ + typedef int (*test_case)(void); + unsigned int i = 0; + + sock = connect_to_socket(); + if (sock <= 0) + return -1; + + test_case test_cases[] = {test_case_array_string, + test_case_array_int, test_case_array_u64, + test_case_add_dict_int, test_case_add_dict_u64, + test_case_add_dict_string, + test_dict_with_array_int_values, + test_dict_with_array_u64_values, + test_dict_with_array_string_values, + test_array_with_array_int_values, + test_array_with_array_u64_values, + test_array_with_array_string_values }; + + rte_telemetry_register_cmd(REQUEST_CMD, test_cb, "Test"); + for (i = 0; i < RTE_DIM(test_cases); i++) { + if (test_cases[i]() != 0) { + close(sock); + return -1; + } + } + close(sock); + return 0; +} + +REGISTER_TEST_COMMAND(telemetry_data_autotest, test_telemetry_data); From patchwork Wed Sep 23 11:12:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Power, Ciara" X-Patchwork-Id: 78555 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id DD466A04B1; Wed, 23 Sep 2020 13:15:45 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 98D391DB8A; Wed, 23 Sep 2020 13:15:35 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id AE4CF1DB4B for ; Wed, 23 Sep 2020 13:15:31 +0200 (CEST) IronPort-SDR: 05TTJFeDCEWbe9kkRHW2otF+ClMh6BudQIUwwG7fzRO/xlzJe0MaCZEochgA/1lr39dQDbeOjP oXngyjsx1RYg== X-IronPort-AV: E=McAfee;i="6000,8403,9752"; a="178932666" X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="178932666" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2020 04:15:29 -0700 IronPort-SDR: JEZ/EBrkifjPSIH0nF3epQ/QKI1GQR8vDIOTmDijQrft+4zu6xYRVzcFdB6di7vPtsuwv3Rlq7 8BE7oVdCwdng== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="347314629" Received: from silpixa00399953.ir.intel.com (HELO silpixa00399953.ger.corp.intel.com) ([10.237.222.53]) by FMSMGA003.fm.intel.com with ESMTP; 23 Sep 2020 04:15:27 -0700 From: Ciara Power To: dev@dpdk.org Cc: keith.wiles@intel.com, bruce.richardson@intel.com, Ciara Power , Thomas Monjalon , Ferruh Yigit , Andrew Rybchenko Date: Wed, 23 Sep 2020 12:12:28 +0100 Message-Id: <20200923111228.6274-4-ciara.power@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200923111228.6274-1-ciara.power@intel.com> References: <20200612105344.15383-1-ciara.power@intel.com> <20200923111228.6274-1-ciara.power@intel.com> Subject: [dpdk-dev] [PATCH v9 3/3] ethdev: add common stats for telemetry X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 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" The ethdev library now registers a telemetry command for common ethdev statistics. An example usage is shown below: Connecting to /var/run/dpdk/rte/dpdk_telemetry.v2 {"version": "DPDK 20.08.0-rc1", "pid": 14119, "max_output_len": 16384} --> /ethdev/stats,0 {"/ethdev/stats": {"ipackets": 0, "opackets": 0, "ibytes": 0, "obytes": \ 0, "imissed": 0, "ierrors": 0, "oerrors": 0, "rx_nombuf": 0, \ "q_ipackets": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \ "q_opackets": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \ "q_ibytes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \ "q_obytes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \ "q_errors": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}} Signed-off-by: Ciara Power Acked-by: Bruce Richardson --- lib/librte_ethdev/rte_ethdev.c | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index dfe5c1b488..81bb86c433 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -5328,6 +5328,57 @@ handle_port_list(const char *cmd __rte_unused, return 0; } +static void +add_port_queue_stats(struct rte_tel_data *d, uint64_t *q_stats, + const char *stat_name) +{ + int q; + struct rte_tel_data *q_data = rte_tel_data_alloc(); + rte_tel_data_start_array(q_data, RTE_TEL_U64_VAL); + for (q = 0; q < RTE_ETHDEV_QUEUE_STAT_CNTRS; q++) + rte_tel_data_add_array_u64(q_data, q_stats[q]); + rte_tel_data_add_dict_container(d, stat_name, q_data, 0); +} + +#define ADD_DICT_STAT(stats, s) rte_tel_data_add_dict_u64(d, #s, stats.s) + +static int +handle_port_stats(const char *cmd __rte_unused, + const char *params, + struct rte_tel_data *d) +{ + struct rte_eth_stats stats; + int port_id, ret; + + if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + return -1; + + port_id = atoi(params); + if (!rte_eth_dev_is_valid_port(port_id)) + return -1; + + ret = rte_eth_stats_get(port_id, &stats); + if (ret < 0) + return -1; + + rte_tel_data_start_dict(d); + ADD_DICT_STAT(stats, ipackets); + ADD_DICT_STAT(stats, opackets); + ADD_DICT_STAT(stats, ibytes); + ADD_DICT_STAT(stats, obytes); + ADD_DICT_STAT(stats, imissed); + ADD_DICT_STAT(stats, ierrors); + ADD_DICT_STAT(stats, oerrors); + ADD_DICT_STAT(stats, rx_nombuf); + add_port_queue_stats(d, stats.q_ipackets, "q_ipackets"); + add_port_queue_stats(d, stats.q_opackets, "q_opackets"); + add_port_queue_stats(d, stats.q_ibytes, "q_ibytes"); + add_port_queue_stats(d, stats.q_obytes, "q_obytes"); + add_port_queue_stats(d, stats.q_errors, "q_errors"); + + return 0; +} + static int handle_port_xstats(const char *cmd __rte_unused, const char *params, @@ -5414,6 +5465,8 @@ RTE_INIT(ethdev_init_telemetry) { rte_telemetry_register_cmd("/ethdev/list", handle_port_list, "Returns list of available ethdev ports. Takes no parameters"); + rte_telemetry_register_cmd("/ethdev/stats", handle_port_stats, + "Returns the common stats for a port. Parameters: int port_id"); rte_telemetry_register_cmd("/ethdev/xstats", handle_port_xstats, "Returns the extended stats for a port. Parameters: int port_id"); rte_telemetry_register_cmd("/ethdev/link_status",