DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] mem: telemetry support for memseg and element information
@ 2022-05-19  6:30 Amit Prakash Shukla
  2022-05-19 12:42 ` David Marchand
                   ` (3 more replies)
  0 siblings, 4 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-05-19  6:30 UTC (permalink / raw)
  To: Anatoly Burakov, Ciara Power
  Cc: dev, jerinj, bruce.richardson, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/active_memseg_list
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/active_memseg_list
{"/eal/active_memseg_list": [0, 1]}

2. /eal/memseg_list,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input. Command also
supports help.
Example:
--> /eal/memseg_list,help
{"/eal/memseg_list": "/eal/memseg_list,<memseg-list-id>"}

--> /eal/memseg_list,1
{"/eal/memseg_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
 12, 13, 14, 15]}

3. /eal/memseg_info,<memseg-list-id>:<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input. Command also
supports help.
Example:
--> /eal/memseg_info,help
{"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>: \
<memseg-id>"}

--> /eal/memseg_info,0:10
{"/eal/memseg_info": {"Memseg_list_index": 0,  \
"Memseg_index": 10, "Memseg_list_len": 64,     \
"Start_addr": "0x260000000", "End_addr": "0x280000000",  \
"Size": 536870912}}

--> /eal/memseg_info,1:15
{"/eal/memseg_info": {"Memseg_list_index": 1,   \
"Memseg_index": 15, "Memseg_list_len": 64,      \
"Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
"Size": 536870912}}

4. /eal/elem_list,<heap-id>:<memseg-list-id>:<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Command also supports help.
Example:
--> /eal/elem_list,help
{"/eal/elem_list": "/eal/elem_list,<heap-id>:  \
<memseg-list-id>:<memseg-id>"}

--> /eal/elem_list,0:0:63
{"/eal/elem_list": {"Element_count": 52}}

--> /eal/elem_list,0:1:15
{"/eal/elem_list": {"Element_count": 52}}

5. /eal/elem_info,<heap-id>:<memseg-list-id>:<memseg-id>:  \
   <elem-start-id>-<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed. Command also supports help.
Example:
--> /eal/elem_info,help
{"/eal/elem_info": "/eal/elem_info,<heap-id>:  \
<memseg-list-id>:<memseg-id>: <elem-start-id>-<elem-end-id>"}

--> /eal/elem_info,0:1:15:1-2
{"/eal/elem_info": {"elem_info.1": {"msl_id": 1,     \
"ms_id": 15, "memseg_start_addr": "0xb20000000",     \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb201fe680",                 \
"element_end_addr": "0xb20bfe700",                   \
"element_size": 10485888, "element_state": "Busy"},  \
"elem_info.2": {"msl_id": 1, "ms_id": 15,            \
"memseg_start_addr": "0xb20000000",                  \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb20bfe700",                 \
"element_end_addr": "0xb215fe780", "element_size": 10485888, \
"element_state": "Busy"}, "Element_count": 2}}

Increased telemetry output buffer to 64K to support large
size telemetry data output.

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
 lib/eal/common/eal_common_memory.c | 453 ++++++++++++++++++++++++++++-
 lib/telemetry/telemetry.c          |   2 +-
 2 files changed, 448 insertions(+), 7 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 688dc615d7..80dde5f0f4 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -18,6 +18,7 @@
 #include <rte_log.h>
 #ifndef RTE_EXEC_ENV_WINDOWS
 #include <rte_telemetry.h>
+#include <telemetry_data.h>
 #endif
 
 #include "eal_memalloc.h"
@@ -26,6 +27,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1113,11 +1115,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_REQ			"/eal/memseg_list"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ACTIVE_MEMSEG_LIST_REQ	"/eal/active_memseg_list"
+#define EAL_ELEMENT_LIST_REQ		"/eal/elem_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/elem_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1252,7 +1260,6 @@ memzone_list_cb(const struct rte_memzone *mz __rte_unused,
 	rte_tel_data_add_array_int(d, mz_idx);
 }
 
-
 /* Telemetry callback handler to list the memzones reserved. */
 static int
 handle_eal_memzone_list_request(const char *cmd __rte_unused,
@@ -1265,6 +1272,425 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+static int
+handle_eal_active_memseg_request(const char *cmd __rte_unused,
+				 const char *params __rte_unused,
+				 struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_request(const char *cmd __rte_unused, const char *params,
+			  struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	char *params_args;
+	int ms_idx;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>", EAL_MEMSEG_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	ms_list_idx = strtoul(params_args, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	free(params_args);
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	uint32_t msl_len;
+	char dlim[2] = ":";
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>:<memseg-id>",
+			 EAL_MEMSEG_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token != NULL)
+		ms_list_idx = strtoul(token, NULL, 10);
+
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token != NULL)
+		ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	msl_len = arr->len;
+
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->hugepage_sz;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
+	snprintf(addr, ADDR_STR, "%p", (void *)ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "%p", (void *)ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_int(d, "Size", ms_size);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	char dlim[2] = ":";
+	int elem_count = 0;
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>:<memseg-list-id>:<memseg-id>",
+			 EAL_ELEMENT_LIST_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token != NULL)
+		heap_id = strtoul(token, NULL, 10);
+
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token != NULL)
+		ms_list_idx = strtoul(token, NULL, 10);
+
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token != NULL)
+		ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char dlim[2] = ":";
+	char dlim2[2] = "-";
+	char str[ADDR_STR];
+	char *params_args;
+	char *token;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>:<memseg-list-id>:<memseg-id>:"
+			 "<elem-start-id>-<elem-end-id>",
+			 EAL_ELEMENT_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token != NULL)
+		heap_id = strtoul(token, NULL, 10);
+
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token != NULL)
+		ms_list_idx = strtoul(token, NULL, 10);
+
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token != NULL)
+		ms_idx = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim2);
+	if (token != NULL)
+		start_elem = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim2);
+	if (token != NULL)
+		end_elem = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		memset(c, 0, sizeof(struct rte_tel_data));
+		rte_tel_data_start_dict(c);
+
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "%p", (void *)ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "%p", (void *)ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "%p", (void *)elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "%p", (void *)elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s.%u", "elem_info", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1279,5 +1705,20 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_REQ, handle_eal_memseg_request,
+			"Returns hugepage list. Parameters: int hp_list_id");
+	rte_telemetry_register_cmd(
+			EAL_ACTIVE_MEMSEG_LIST_REQ, handle_eal_active_memseg_request,
+			"Returns hugepage list. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns hugepage information. Parameters: int hp_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns element information. Takes no parameters");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element information. Parameters: int elem_id");
 }
 #endif
diff --git a/lib/telemetry/telemetry.c b/lib/telemetry/telemetry.c
index c6fd03a5ab..a044e6ea5f 100644
--- a/lib/telemetry/telemetry.c
+++ b/lib/telemetry/telemetry.c
@@ -23,7 +23,7 @@
 #include "telemetry_internal.h"
 
 #define MAX_CMD_LEN 56
-#define MAX_OUTPUT_LEN (1024 * 16)
+#define MAX_OUTPUT_LEN (1024 * 64)
 #define MAX_CONNECTIONS 10
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH] mem: telemetry support for memseg and element information
  2022-05-19  6:30 [PATCH] mem: telemetry support for memseg and element information Amit Prakash Shukla
@ 2022-05-19 12:42 ` David Marchand
  2022-05-19 18:57 ` [PATCH v2] " Amit Prakash Shukla
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 42+ messages in thread
From: David Marchand @ 2022-05-19 12:42 UTC (permalink / raw)
  To: Amit Prakash Shukla
  Cc: Anatoly Burakov, Ciara Power, dev, Jerin Jacob Kollanukkaran,
	Bruce Richardson

On Thu, May 19, 2022 at 8:31 AM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
> diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
> index 688dc615d7..80dde5f0f4 100644
> --- a/lib/eal/common/eal_common_memory.c
> +++ b/lib/eal/common/eal_common_memory.c
> @@ -18,6 +18,7 @@
>  #include <rte_log.h>
>  #ifndef RTE_EXEC_ENV_WINDOWS
>  #include <rte_telemetry.h>
> +#include <telemetry_data.h>

You can remove this include after you remove later call to: memset(c,
0, sizeof(struct rte_tel_data));


>  #endif
>
>  #include "eal_memalloc.h"
> @@ -26,6 +27,7 @@
>  #include "eal_memcfg.h"
>  #include "eal_options.h"
>  #include "malloc_heap.h"
> +#include "malloc_elem.h"
>
>  /*
>   * Try to mmap *size bytes in /dev/zero. If it is successful, return the
> @@ -1113,11 +1115,17 @@ rte_eal_memory_init(void)
>  }
>
>  #ifndef RTE_EXEC_ENV_WINDOWS
> -#define EAL_MEMZONE_LIST_REQ   "/eal/memzone_list"
> -#define EAL_MEMZONE_INFO_REQ   "/eal/memzone_info"
> -#define EAL_HEAP_LIST_REQ      "/eal/heap_list"
> -#define EAL_HEAP_INFO_REQ      "/eal/heap_info"
> -#define ADDR_STR               15
> +#define EAL_MEMZONE_LIST_REQ           "/eal/memzone_list"
> +#define EAL_MEMZONE_INFO_REQ           "/eal/memzone_info"
> +#define EAL_HEAP_LIST_REQ              "/eal/heap_list"
> +#define EAL_HEAP_INFO_REQ              "/eal/heap_info"
> +#define EAL_MEMSEG_REQ                 "/eal/memseg_list"
> +#define EAL_MEMSEG_INFO_REQ            "/eal/memseg_info"
> +#define EAL_ACTIVE_MEMSEG_LIST_REQ     "/eal/active_memseg_list"
> +#define EAL_ELEMENT_LIST_REQ           "/eal/elem_list"
> +#define EAL_ELEMENT_INFO_REQ           "/eal/elem_info"
> +#define ADDR_STR                       15
> +
>
>  /* Telemetry callback handler to return heap stats for requested heap id. */
>  static int
> @@ -1252,7 +1260,6 @@ memzone_list_cb(const struct rte_memzone *mz __rte_unused,
>         rte_tel_data_add_array_int(d, mz_idx);
>  }
>
> -

Unrelated change.


>  /* Telemetry callback handler to list the memzones reserved. */
>  static int
>  handle_eal_memzone_list_request(const char *cmd __rte_unused,
> @@ -1265,6 +1272,425 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
>         return 0;
>  }
>
> +static int
> +handle_eal_active_memseg_request(const char *cmd __rte_unused,
> +                                const char *params __rte_unused,
> +                                struct rte_tel_data *d)
> +{
> +       struct rte_mem_config *mcfg;
> +       int i;
> +
> +       rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +       rte_mcfg_mem_read_lock();
> +       mcfg = rte_eal_get_configuration()->mem_config;
> +
> +       for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
> +               struct rte_memseg_list *msl = &mcfg->memsegs[i];
> +               if (msl->memseg_arr.count == 0)
> +                       continue;
> +
> +               rte_tel_data_add_array_int(d, i);
> +       }
> +       rte_mcfg_mem_read_unlock();
> +
> +       return 0;
> +}
> +
> +static int
> +handle_eal_memseg_request(const char *cmd __rte_unused, const char *params,
> +                         struct rte_tel_data *d)
> +{
> +       struct rte_mem_config *mcfg;
> +       struct rte_memseg_list *msl;
> +       struct rte_fbarray *arr;
> +       uint32_t ms_list_idx;
> +       char *params_args;
> +       int ms_idx;
> +
> +       if (params == NULL || strlen(params) == 0)
> +               return -1;
> +
> +       if (strncasecmp(params, "help", strlen(params)) == 0) {
> +               char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> +               snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> +                        "%s,<memseg-list-id>", EAL_MEMSEG_REQ);
> +               rte_tel_data_string(d, buff);
> +               return 0;
> +       }
> +
> +       /* strtok expects char * and param is const char *. Hence on using
> +        * params as "const char *" compiler throws warning.
> +        */

This is probably copy/paste from other handlers, there is no strtok call here.
Please remove this comment and unneeded strdup'd params_args below.


I can see that this code replies for invalid input:

Calling /eal/memseg_list,z
{"/eal/memseg_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182,
183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266,
267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280,
281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322,
323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336,
337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350,
351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378,
379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406,
407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420,
421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434,
435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448,
449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462,
463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476,
477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490,
491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504,
505, 506, 507, 508, 509, 510, 511]}

It might be worth adding a isdigit() check here.


> +       params_args = strdup(params);
> +       ms_list_idx = strtoul(params_args, NULL, 10);
> +       if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> +               free(params_args);
> +               return -1;
> +       }
> +
> +       free(params_args);
> +       rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +       rte_mcfg_mem_read_lock();
> +       mcfg = rte_eal_get_configuration()->mem_config;
> +       msl = &mcfg->memsegs[ms_list_idx];
> +       if (msl->memseg_arr.count == 0)
> +               goto done;
> +
> +       arr = &msl->memseg_arr;
> +
> +       ms_idx = rte_fbarray_find_next_used(arr, 0);
> +       while (ms_idx >= 0) {
> +               rte_tel_data_add_array_int(d, ms_idx);
> +               ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
> +       }
> +
> +done:
> +       rte_mcfg_mem_read_unlock();
> +
> +       return 0;
> +}


CI reports build issues, please remove casts / fix integer formats.
I did not check further.


-- 
David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v2] mem: telemetry support for memseg and element information
  2022-05-19  6:30 [PATCH] mem: telemetry support for memseg and element information Amit Prakash Shukla
  2022-05-19 12:42 ` David Marchand
@ 2022-05-19 18:57 ` Amit Prakash Shukla
  2022-05-23 11:14   ` Bruce Richardson
  2022-05-24 10:33 ` [PATCH v3] " Amit Prakash Shukla
  2022-05-25 10:33 ` [PATCH v4 1/2] " Amit Prakash Shukla
  3 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-05-19 18:57 UTC (permalink / raw)
  To: Anatoly Burakov, Ciara Power
  Cc: dev, jerinj, bruce.richardson, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/active_memseg_list
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/active_memseg_list
{"/eal/active_memseg_list": [0, 1]}

2. /eal/memseg_list,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input. Command also
supports help.
Example:
--> /eal/memseg_list,help
{"/eal/memseg_list": "/eal/memseg_list,<memseg-list-id>"}

--> /eal/memseg_list,1
{"/eal/memseg_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
 12, 13, 14, 15]}

3. /eal/memseg_info,<memseg-list-id>:<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input. Command also
supports help.
Example:
--> /eal/memseg_info,help
{"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>: \
<memseg-id>"}

--> /eal/memseg_info,0:10
{"/eal/memseg_info": {"Memseg_list_index": 0,  \
"Memseg_index": 10, "Memseg_list_len": 64,     \
"Start_addr": "0x260000000", "End_addr": "0x280000000",  \
"Size": 536870912}}

--> /eal/memseg_info,1:15
{"/eal/memseg_info": {"Memseg_list_index": 1,   \
"Memseg_index": 15, "Memseg_list_len": 64,      \
"Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
"Size": 536870912}}

4. /eal/elem_list,<heap-id>:<memseg-list-id>:<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Command also supports help.
Example:
--> /eal/elem_list,help
{"/eal/elem_list": "/eal/elem_list,<heap-id>:  \
<memseg-list-id>:<memseg-id>"}

--> /eal/elem_list,0:0:63
{"/eal/elem_list": {"Element_count": 52}}

--> /eal/elem_list,0:1:15
{"/eal/elem_list": {"Element_count": 52}}

5. /eal/elem_info,<heap-id>:<memseg-list-id>:<memseg-id>:  \
   <elem-start-id>-<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed. Command also supports help.
Example:
--> /eal/elem_info,help
{"/eal/elem_info": "/eal/elem_info,<heap-id>:  \
<memseg-list-id>:<memseg-id>: <elem-start-id>-<elem-end-id>"}

--> /eal/elem_info,0:1:15:1-2
{"/eal/elem_info": {"elem_info.1": {"msl_id": 1,     \
"ms_id": 15, "memseg_start_addr": "0xb20000000",     \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb201fe680",                 \
"element_end_addr": "0xb20bfe700",                   \
"element_size": 10485888, "element_state": "Busy"},  \
"elem_info.2": {"msl_id": 1, "ms_id": 15,            \
"memseg_start_addr": "0xb20000000",                  \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb20bfe700",                 \
"element_end_addr": "0xb215fe780", "element_size": 10485888, \
"element_state": "Busy"}, "Element_count": 2}}

Increased telemetry output buffer to 64K to support large
size telemetry data output.

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Fixed compilation error related int-to-pointer-cast
- Changes for code review suggestions

 lib/eal/common/eal_common_memory.c | 481 ++++++++++++++++++++++++++++-
 lib/telemetry/telemetry.c          |   2 +-
 2 files changed, 477 insertions(+), 6 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 688dc615d7..820fe8cf2c 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -26,6 +26,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1113,11 +1114,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_REQ			"/eal/memseg_list"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ACTIVE_MEMSEG_LIST_REQ	"/eal/active_memseg_list"
+#define EAL_ELEMENT_LIST_REQ		"/eal/elem_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/elem_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1265,6 +1272,455 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+static int
+handle_eal_active_memseg_request(const char *cmd __rte_unused,
+				 const char *params __rte_unused,
+				 struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_request(const char *cmd __rte_unused, const char *params,
+			  struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	int ms_idx;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>", EAL_MEMSEG_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	if (!isdigit(*params))
+		return -1;
+
+	ms_list_idx = strtoul(params, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	uint32_t msl_len;
+	char dlim[2] = ":";
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>:<memseg-id>",
+			 EAL_MEMSEG_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	msl_len = arr->len;
+
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->hugepage_sz;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_int(d, "Size", ms_size);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	char dlim[2] = ":";
+	int elem_count = 0;
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>:<memseg-list-id>:<memseg-id>",
+			 EAL_ELEMENT_LIST_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char dlim[2] = ":";
+	char dlim2[2] = "-";
+	char str[ADDR_STR];
+	char *params_args;
+	char *token;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>:<memseg-list-id>:<memseg-id>:"
+			 "<elem-start-id>-<elem-end-id>",
+			 EAL_ELEMENT_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim2);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	start_elem = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim2);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	end_elem = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	if (end_elem < start_elem)
+		return -1;
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		rte_tel_data_start_dict(c);
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s.%u", "elem_info", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1279,5 +1735,20 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_REQ, handle_eal_memseg_request,
+			"Returns hugepage list. Parameters: int hp_list_id");
+	rte_telemetry_register_cmd(
+			EAL_ACTIVE_MEMSEG_LIST_REQ, handle_eal_active_memseg_request,
+			"Returns hugepage list. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns hugepage information. Parameters: int hp_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns element information. Takes no parameters");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element information. Parameters: int elem_id");
 }
 #endif
diff --git a/lib/telemetry/telemetry.c b/lib/telemetry/telemetry.c
index c6fd03a5ab..a044e6ea5f 100644
--- a/lib/telemetry/telemetry.c
+++ b/lib/telemetry/telemetry.c
@@ -23,7 +23,7 @@
 #include "telemetry_internal.h"
 
 #define MAX_CMD_LEN 56
-#define MAX_OUTPUT_LEN (1024 * 16)
+#define MAX_OUTPUT_LEN (1024 * 64)
 #define MAX_CONNECTIONS 10
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2] mem: telemetry support for memseg and element information
  2022-05-19 18:57 ` [PATCH v2] " Amit Prakash Shukla
@ 2022-05-23 11:14   ` Bruce Richardson
  2022-05-23 13:35     ` [EXT] " Amit Prakash Shukla
  0 siblings, 1 reply; 42+ messages in thread
From: Bruce Richardson @ 2022-05-23 11:14 UTC (permalink / raw)
  To: Amit Prakash Shukla; +Cc: Anatoly Burakov, Ciara Power, dev, jerinj

On Fri, May 20, 2022 at 12:27:12AM +0530, Amit Prakash Shukla wrote:
> Changes adds telemetry support to display memory occupancy
> in memseg and the information of the elements allocated from
> a memseg based on arguments provided by user. This patch
> adds following endpoints:
> 
> 1. /eal/active_memseg_list
> The command displays the memseg list from which the memory
> has been allocated.
> Example:
> --> /eal/active_memseg_list
> {"/eal/active_memseg_list": [0, 1]}
> 
> 2. /eal/memseg_list,<memseg-list-id>
> The command outputs the memsegs, from which the memory is
> allocated, for the memseg_list given as input. Command also
> supports help.
> Example:
> --> /eal/memseg_list,help
> {"/eal/memseg_list": "/eal/memseg_list,<memseg-list-id>"}
> 
> --> /eal/memseg_list,1
> {"/eal/memseg_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
>  12, 13, 14, 15]}
> 

This is really confusing because, if I understand this correctly,  we have
a conflict of terms here - in telemetry "list" is generally used to get the
possible values of ids at the top level, with the info and other commands
used to get the next level of detail down, while the initial command here
returns details on the memseg lists, i.e. it should really be
"memseg_list_list" command, i.e. list the memseg lists. Can we perhaps come
up with a different term for the memseg list, because right now I think the
above commands should be "memseg_list_list" and "memseg_list_info"?


> 3. /eal/memseg_info,<memseg-list-id>:<memseg-id>
> The command outputs the memseg information based on the
> memseg-list and the memseg-id given as input. Command also
> supports help.
> Example:
> --> /eal/memseg_info,help
> {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>: \
> <memseg-id>"}
> 
> --> /eal/memseg_info,0:10
> {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> "Memseg_index": 10, "Memseg_list_len": 64,     \
> "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> "Size": 536870912}}
> 
> --> /eal/memseg_info,1:15
> {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> "Memseg_index": 15, "Memseg_list_len": 64,      \
> "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> "Size": 536870912}}
> 

For telemetry library, the parameters should all be comma-separated rather
than colon-separated.

> 4. /eal/elem_list,<heap-id>:<memseg-list-id>:<memseg-id>
> The command outputs number of elements in a memseg based
> on the heap-id, memseg-list-id and memseg-id given as input.
> Command also supports help.
> Example:
> --> /eal/elem_list,help
> {"/eal/elem_list": "/eal/elem_list,<heap-id>:  \
> <memseg-list-id>:<memseg-id>"}
> 
> --> /eal/elem_list,0:0:63
> {"/eal/elem_list": {"Element_count": 52}}
> 
> --> /eal/elem_list,0:1:15
> {"/eal/elem_list": {"Element_count": 52}}
> 
> 5. /eal/elem_info,<heap-id>:<memseg-list-id>:<memseg-id>:  \
>    <elem-start-id>-<elem-end-id>
> The command outputs element information like element start
> address, end address, to which memseg it belongs, element
> state, element size. User can give a range of elements to be
> printed. Command also supports help.
> Example:
> --> /eal/elem_info,help
> {"/eal/elem_info": "/eal/elem_info,<heap-id>:  \
> <memseg-list-id>:<memseg-id>: <elem-start-id>-<elem-end-id>"}
> 
> --> /eal/elem_info,0:1:15:1-2
> {"/eal/elem_info": {"elem_info.1": {"msl_id": 1,     \
> "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb201fe680",                 \
> "element_end_addr": "0xb20bfe700",                   \
> "element_size": 10485888, "element_state": "Busy"},  \
> "elem_info.2": {"msl_id": 1, "ms_id": 15,            \
> "memseg_start_addr": "0xb20000000",                  \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb20bfe700",                 \
> "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> "element_state": "Busy"}, "Element_count": 2}}
> 

The "elem" name is ambiguous, I think. Are these malloc elements or some
other type of elements.


> Increased telemetry output buffer to 64K to support large
> size telemetry data output.
> 

That's a 4x increase in max size. Is it really necessary? Is telemetry the
best way to output this info, and do you see users really needing it?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v2] mem: telemetry support for memseg and element information
  2022-05-23 11:14   ` Bruce Richardson
@ 2022-05-23 13:35     ` Amit Prakash Shukla
  2022-05-23 13:43       ` Bruce Richardson
  0 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-05-23 13:35 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: Anatoly Burakov, Ciara Power, dev, Jerin Jacob Kollanukkaran

Thanks Bruce for the review suggestions. I make the changes as suggested in next version of the patch.

> -----Original Message-----
> From: Bruce Richardson <bruce.richardson@intel.com>
> Sent: Monday, May 23, 2022 4:45 PM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>
> Cc: Anatoly Burakov <anatoly.burakov@intel.com>; Ciara Power
> <ciara.power@intel.com>; dev@dpdk.org; Jerin Jacob Kollanukkaran
> <jerinj@marvell.com>
> Subject: [EXT] Re: [PATCH v2] mem: telemetry support for memseg and
> element information
> 
> External Email
> 
> ----------------------------------------------------------------------
> On Fri, May 20, 2022 at 12:27:12AM +0530, Amit Prakash Shukla wrote:
> > Changes adds telemetry support to display memory occupancy in memseg
> > and the information of the elements allocated from a memseg based on
> > arguments provided by user. This patch adds following endpoints:
> >
> > 1. /eal/active_memseg_list
> > The command displays the memseg list from which the memory has been
> > allocated.
> > Example:
> > --> /eal/active_memseg_list
> > {"/eal/active_memseg_list": [0, 1]}
> >
> > 2. /eal/memseg_list,<memseg-list-id>
> > The command outputs the memsegs, from which the memory is allocated,
> > for the memseg_list given as input. Command also supports help.
> > Example:
> > --> /eal/memseg_list,help
> > {"/eal/memseg_list": "/eal/memseg_list,<memseg-list-id>"}
> >
> > --> /eal/memseg_list,1
> > {"/eal/memseg_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \  12, 13,
> > 14, 15]}
> >
> 
> This is really confusing because, if I understand this correctly,  we have a
> conflict of terms here - in telemetry "list" is generally used to get the possible
> values of ids at the top level, with the info and other commands used to get
> the next level of detail down, while the initial command here returns details
> on the memseg lists, i.e. it should really be "memseg_list_list" command, i.e.
> list the memseg lists. Can we perhaps come up with a different term for the
> memseg list, because right now I think the above commands should be
> "memseg_list_list" and "memseg_list_info"?
> 

Sure, will change the naming.

> 
> > 3. /eal/memseg_info,<memseg-list-id>:<memseg-id>
> > The command outputs the memseg information based on the memseg-list
> > and the memseg-id given as input. Command also supports help.
> > Example:
> > --> /eal/memseg_info,help
> > {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>: \
> > <memseg-id>"}
> >
> > --> /eal/memseg_info,0:10
> > {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> > "Memseg_index": 10, "Memseg_list_len": 64,     \
> > "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> > "Size": 536870912}}
> >
> > --> /eal/memseg_info,1:15
> > {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> > "Memseg_index": 15, "Memseg_list_len": 64,      \
> > "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> > "Size": 536870912}}
> >
> 
> For telemetry library, the parameters should all be comma-separated rather
> than colon-separated.
> 

Sure, will change it to comma-separated.

> > 4. /eal/elem_list,<heap-id>:<memseg-list-id>:<memseg-id>
> > The command outputs number of elements in a memseg based on the
> > heap-id, memseg-list-id and memseg-id given as input.
> > Command also supports help.
> > Example:
> > --> /eal/elem_list,help
> > {"/eal/elem_list": "/eal/elem_list,<heap-id>:  \
> > <memseg-list-id>:<memseg-id>"}
> >
> > --> /eal/elem_list,0:0:63
> > {"/eal/elem_list": {"Element_count": 52}}
> >
> > --> /eal/elem_list,0:1:15
> > {"/eal/elem_list": {"Element_count": 52}}
> >
> > 5. /eal/elem_info,<heap-id>:<memseg-list-id>:<memseg-id>:  \
> >    <elem-start-id>-<elem-end-id>
> > The command outputs element information like element start address,
> > end address, to which memseg it belongs, element state, element size.
> > User can give a range of elements to be printed. Command also supports
> > help.
> > Example:
> > --> /eal/elem_info,help
> > {"/eal/elem_info": "/eal/elem_info,<heap-id>:  \
> > <memseg-list-id>:<memseg-id>: <elem-start-id>-<elem-end-id>"}
> >

The last 2 arguments "<elem-start-id>-<elem-end-id>" is to print range of elements. Can I use hyphen here ?

> > --> /eal/elem_info,0:1:15:1-2
> > {"/eal/elem_info": {"elem_info.1": {"msl_id": 1,     \
> > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb201fe680",                 \
> > "element_end_addr": "0xb20bfe700",                   \
> > "element_size": 10485888, "element_state": "Busy"},  \
> > "elem_info.2": {"msl_id": 1, "ms_id": 15,            \
> > "memseg_start_addr": "0xb20000000",                  \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb20bfe700",                 \
> > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > "element_state": "Busy"}, "Element_count": 2}}
> >
> 
> The "elem" name is ambiguous, I think. Are these malloc elements or some
> other type of elements.
> 

These are malloc elements. I will change the naming.

> 
> > Increased telemetry output buffer to 64K to support large size
> > telemetry data output.
> >
> 
> That's a 4x increase in max size. Is it really necessary? Is telemetry the best
> way to output this info, and do you see users really needing it?

This change is not required now. The code has been internally optimized. I will revert this change.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [EXT] Re: [PATCH v2] mem: telemetry support for memseg and element information
  2022-05-23 13:35     ` [EXT] " Amit Prakash Shukla
@ 2022-05-23 13:43       ` Bruce Richardson
  2022-05-24 10:30         ` Amit Prakash Shukla
  0 siblings, 1 reply; 42+ messages in thread
From: Bruce Richardson @ 2022-05-23 13:43 UTC (permalink / raw)
  To: Amit Prakash Shukla
  Cc: Anatoly Burakov, Ciara Power, dev, Jerin Jacob Kollanukkaran

On Mon, May 23, 2022 at 01:35:06PM +0000, Amit Prakash Shukla wrote:
> Thanks Bruce for the review suggestions. I make the changes as suggested in next version of the patch.
> 
> > -----Original Message-----
> > From: Bruce Richardson <bruce.richardson@intel.com>
> > Sent: Monday, May 23, 2022 4:45 PM
> > To: Amit Prakash Shukla <amitprakashs@marvell.com>
> > Cc: Anatoly Burakov <anatoly.burakov@intel.com>; Ciara Power
> > <ciara.power@intel.com>; dev@dpdk.org; Jerin Jacob Kollanukkaran
> > <jerinj@marvell.com>
> > Subject: [EXT] Re: [PATCH v2] mem: telemetry support for memseg and
> > element information
> > 
> > External Email
> > 
> > ----------------------------------------------------------------------
> > On Fri, May 20, 2022 at 12:27:12AM +0530, Amit Prakash Shukla wrote:
> > > Changes adds telemetry support to display memory occupancy in memseg
> > > and the information of the elements allocated from a memseg based on
> > > arguments provided by user. This patch adds following endpoints:
> > >
> > > 1. /eal/active_memseg_list
> > > The command displays the memseg list from which the memory has been
> > > allocated.
> > > Example:
> > > --> /eal/active_memseg_list
> > > {"/eal/active_memseg_list": [0, 1]}
> > >
> > > 2. /eal/memseg_list,<memseg-list-id>
> > > The command outputs the memsegs, from which the memory is allocated,
> > > for the memseg_list given as input. Command also supports help.
> > > Example:
> > > --> /eal/memseg_list,help
> > > {"/eal/memseg_list": "/eal/memseg_list,<memseg-list-id>"}
> > >
> > > --> /eal/memseg_list,1
> > > {"/eal/memseg_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \  12, 13,
> > > 14, 15]}
> > >
> > 
> > This is really confusing because, if I understand this correctly,  we have a
> > conflict of terms here - in telemetry "list" is generally used to get the possible
> > values of ids at the top level, with the info and other commands used to get
> > the next level of detail down, while the initial command here returns details
> > on the memseg lists, i.e. it should really be "memseg_list_list" command, i.e.
> > list the memseg lists. Can we perhaps come up with a different term for the
> > memseg list, because right now I think the above commands should be
> > "memseg_list_list" and "memseg_list_info"?
> > 
> 
> Sure, will change the naming.
> 

Have a think about it too, because my suggested naming is still rather
unwieldy and not very nice. I'm not sure what the best naming here is.

Are the memsegs only identified by number inside each memseg list? Are
there no names that could be used instead? Could you merge the
memseg_list_list and memseg_list_info into one to print out a list of all
memsegs in one go across multiple lists? How many memsegs are there likely
to be?

> > 
> > > 3. /eal/memseg_info,<memseg-list-id>:<memseg-id>
> > > The command outputs the memseg information based on the memseg-list
> > > and the memseg-id given as input. Command also supports help.
> > > Example:
> > > --> /eal/memseg_info,help
> > > {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>: \
> > > <memseg-id>"}
> > >
> > > --> /eal/memseg_info,0:10
> > > {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> > > "Memseg_index": 10, "Memseg_list_len": 64,     \
> > > "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> > > "Size": 536870912}}
> > >
> > > --> /eal/memseg_info,1:15
> > > {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> > > "Memseg_index": 15, "Memseg_list_len": 64,      \
> > > "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> > > "Size": 536870912}}
> > >
> > 
> > For telemetry library, the parameters should all be comma-separated rather
> > than colon-separated.
> > 
> 
> Sure, will change it to comma-separated.
> 
> > > 4. /eal/elem_list,<heap-id>:<memseg-list-id>:<memseg-id>
> > > The command outputs number of elements in a memseg based on the
> > > heap-id, memseg-list-id and memseg-id given as input.
> > > Command also supports help.
> > > Example:
> > > --> /eal/elem_list,help
> > > {"/eal/elem_list": "/eal/elem_list,<heap-id>:  \
> > > <memseg-list-id>:<memseg-id>"}
> > >
> > > --> /eal/elem_list,0:0:63
> > > {"/eal/elem_list": {"Element_count": 52}}
> > >
> > > --> /eal/elem_list,0:1:15
> > > {"/eal/elem_list": {"Element_count": 52}}
> > >
> > > 5. /eal/elem_info,<heap-id>:<memseg-list-id>:<memseg-id>:  \
> > >    <elem-start-id>-<elem-end-id>
> > > The command outputs element information like element start address,
> > > end address, to which memseg it belongs, element state, element size.
> > > User can give a range of elements to be printed. Command also supports
> > > help.
> > > Example:
> > > --> /eal/elem_info,help
> > > {"/eal/elem_info": "/eal/elem_info,<heap-id>:  \
> > > <memseg-list-id>:<memseg-id>: <elem-start-id>-<elem-end-id>"}
> > >
> 
> The last 2 arguments "<elem-start-id>-<elem-end-id>" is to print range of elements. Can I use hyphen here ?
> 

I'm not sure I like printing based off a range, especially since doing so
can lead to very large outputs. I would still tend towards separating with
a comma here, if you only support a single range at a time. I would only
support using a "-" in the specifier, if you supported multiple range
options in one go, e.g. as is done with DPDK -l EAL flag.

> > > --> /eal/elem_info,0:1:15:1-2
> > > {"/eal/elem_info": {"elem_info.1": {"msl_id": 1,     \
> > > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > > "memseg_end_addr": "0xb40000000",                    \
> > > "element_start_addr": "0xb201fe680",                 \
> > > "element_end_addr": "0xb20bfe700",                   \
> > > "element_size": 10485888, "element_state": "Busy"},  \
> > > "elem_info.2": {"msl_id": 1, "ms_id": 15,            \
> > > "memseg_start_addr": "0xb20000000",                  \
> > > "memseg_end_addr": "0xb40000000",                    \
> > > "element_start_addr": "0xb20bfe700",                 \
> > > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > > "element_state": "Busy"}, "Element_count": 2}}
> > >
> > 
> > The "elem" name is ambiguous, I think. Are these malloc elements or some
> > other type of elements.
> > 
> 
> These are malloc elements. I will change the naming.
> 
> > 
> > > Increased telemetry output buffer to 64K to support large size
> > > telemetry data output.
> > >
> > 
> > That's a 4x increase in max size. Is it really necessary? Is telemetry the best
> > way to output this info, and do you see users really needing it?
> 
> This change is not required now. The code has been internally optimized. I will revert this change.

Thanks,
/Bruce

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v2] mem: telemetry support for memseg and element information
  2022-05-23 13:43       ` Bruce Richardson
@ 2022-05-24 10:30         ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-05-24 10:30 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: Anatoly Burakov, Ciara Power, dev, Jerin Jacob Kollanukkaran



> -----Original Message-----
> From: Bruce Richardson <bruce.richardson@intel.com>
> Sent: Monday, May 23, 2022 7:14 PM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>
> Cc: Anatoly Burakov <anatoly.burakov@intel.com>; Ciara Power
> <ciara.power@intel.com>; dev@dpdk.org; Jerin Jacob Kollanukkaran
> <jerinj@marvell.com>
> Subject: Re: [EXT] Re: [PATCH v2] mem: telemetry support for memseg and
> element information
> 
> On Mon, May 23, 2022 at 01:35:06PM +0000, Amit Prakash Shukla wrote:
> > Thanks Bruce for the review suggestions. I make the changes as suggested
> in next version of the patch.
> >
> > > -----Original Message-----
> > > From: Bruce Richardson <bruce.richardson@intel.com>
> > > Sent: Monday, May 23, 2022 4:45 PM
> > > To: Amit Prakash Shukla <amitprakashs@marvell.com>
> > > Cc: Anatoly Burakov <anatoly.burakov@intel.com>; Ciara Power
> > > <ciara.power@intel.com>; dev@dpdk.org; Jerin Jacob Kollanukkaran
> > > <jerinj@marvell.com>
> > > Subject: [EXT] Re: [PATCH v2] mem: telemetry support for memseg and
> > > element information
> > >
> > > External Email
> > >
> > > --------------------------------------------------------------------
> > > -- On Fri, May 20, 2022 at 12:27:12AM +0530, Amit Prakash Shukla
> > > wrote:
> > > > Changes adds telemetry support to display memory occupancy in
> > > > memseg and the information of the elements allocated from a memseg
> > > > based on arguments provided by user. This patch adds following
> endpoints:
> > > >
> > > > 1. /eal/active_memseg_list
> > > > The command displays the memseg list from which the memory has
> > > > been allocated.
> > > > Example:
> > > > --> /eal/active_memseg_list
> > > > {"/eal/active_memseg_list": [0, 1]}
> > > >
> > > > 2. /eal/memseg_list,<memseg-list-id> The command outputs the
> > > > memsegs, from which the memory is allocated, for the memseg_list
> > > > given as input. Command also supports help.
> > > > Example:
> > > > --> /eal/memseg_list,help
> > > > {"/eal/memseg_list": "/eal/memseg_list,<memseg-list-id>"}
> > > >
> > > > --> /eal/memseg_list,1
> > > > {"/eal/memseg_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \  12,
> > > > 13, 14, 15]}
> > > >
> > >
> > > This is really confusing because, if I understand this correctly,
> > > we have a conflict of terms here - in telemetry "list" is generally
> > > used to get the possible values of ids at the top level, with the
> > > info and other commands used to get the next level of detail down,
> > > while the initial command here returns details on the memseg lists, i.e. it
> should really be "memseg_list_list" command, i.e.
> > > list the memseg lists. Can we perhaps come up with a different term
> > > for the memseg list, because right now I think the above commands
> > > should be "memseg_list_list" and "memseg_list_info"?
> > >
> >
> > Sure, will change the naming.
> >
> 
> Have a think about it too, because my suggested naming is still rather
> unwieldy and not very nice. I'm not sure what the best naming here is.

Sure.

> 
> Are the memsegs only identified by number inside each memseg list? Are
> there no names that could be used instead?

Each memseg-list contains a fbarray and fbarray contains list of memsegs.
Memsegs in fbarray are identified by numbers.

> Could you merge the
> memseg_list_list and memseg_list_info into one to print out a list of all
> memsegs in one go across multiple lists? 

Have kept memseg_list_list and memseg_list_info separate for users to identify, 
while requesting memseg info, which memseg list a memseg belongs to.

>How many memsegs are there likely
> to be?

Max memsegs per list is 8192.
#define RTE_MAX_MEMSEG_LISTS 128
#define RTE_MAX_MEMSEG_PER_LIST 8192 

> > >
> > > > 3. /eal/memseg_info,<memseg-list-id>:<memseg-id>
> > > > The command outputs the memseg information based on the
> > > > memseg-list and the memseg-id given as input. Command also
> supports help.
> > > > Example:
> > > > --> /eal/memseg_info,help
> > > > {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>: \
> > > > <memseg-id>"}
> > > >
> > > > --> /eal/memseg_info,0:10
> > > > {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> > > > "Memseg_index": 10, "Memseg_list_len": 64,     \
> > > > "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> > > > "Size": 536870912}}
> > > >
> > > > --> /eal/memseg_info,1:15
> > > > {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> > > > "Memseg_index": 15, "Memseg_list_len": 64,      \
> > > > "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> > > > "Size": 536870912}}
> > > >
> > >
> > > For telemetry library, the parameters should all be comma-separated
> > > rather than colon-separated.
> > >
> >
> > Sure, will change it to comma-separated.
> >
> > > > 4. /eal/elem_list,<heap-id>:<memseg-list-id>:<memseg-id>
> > > > The command outputs number of elements in a memseg based on the
> > > > heap-id, memseg-list-id and memseg-id given as input.
> > > > Command also supports help.
> > > > Example:
> > > > --> /eal/elem_list,help
> > > > {"/eal/elem_list": "/eal/elem_list,<heap-id>:  \
> > > > <memseg-list-id>:<memseg-id>"}
> > > >
> > > > --> /eal/elem_list,0:0:63
> > > > {"/eal/elem_list": {"Element_count": 52}}
> > > >
> > > > --> /eal/elem_list,0:1:15
> > > > {"/eal/elem_list": {"Element_count": 52}}
> > > >
> > > > 5. /eal/elem_info,<heap-id>:<memseg-list-id>:<memseg-id>:  \
> > > >    <elem-start-id>-<elem-end-id>
> > > > The command outputs element information like element start
> > > > address, end address, to which memseg it belongs, element state,
> element size.
> > > > User can give a range of elements to be printed. Command also
> > > > supports help.
> > > > Example:
> > > > --> /eal/elem_info,help
> > > > {"/eal/elem_info": "/eal/elem_info,<heap-id>:  \
> > > > <memseg-list-id>:<memseg-id>: <elem-start-id>-<elem-end-id>"}
> > > >
> >
> > The last 2 arguments "<elem-start-id>-<elem-end-id>" is to print range of
> elements. Can I use hyphen here ?
> >
> 
> I'm not sure I like printing based off a range, especially since doing so can lead
> to very large outputs. I would still tend towards separating with a comma
> here, if you only support a single range at a time. I would only support using a
> "-" in the specifier, if you supported multiple range options in one go, e.g. as
> is done with DPDK -l EAL flag.
> 
> > > > --> /eal/elem_info,0:1:15:1-2
> > > > {"/eal/elem_info": {"elem_info.1": {"msl_id": 1,     \
> > > > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > > > "memseg_end_addr": "0xb40000000",                    \
> > > > "element_start_addr": "0xb201fe680",                 \
> > > > "element_end_addr": "0xb20bfe700",                   \
> > > > "element_size": 10485888, "element_state": "Busy"},  \
> > > > "elem_info.2": {"msl_id": 1, "ms_id": 15,            \
> > > > "memseg_start_addr": "0xb20000000",                  \
> > > > "memseg_end_addr": "0xb40000000",                    \
> > > > "element_start_addr": "0xb20bfe700",                 \
> > > > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > > > "element_state": "Busy"}, "Element_count": 2}}
> > > >
> > >
> > > The "elem" name is ambiguous, I think. Are these malloc elements or
> > > some other type of elements.
> > >
> >
> > These are malloc elements. I will change the naming.
> >
> > >
> > > > Increased telemetry output buffer to 64K to support large size
> > > > telemetry data output.
> > > >
> > >
> > > That's a 4x increase in max size. Is it really necessary? Is
> > > telemetry the best way to output this info, and do you see users really
> needing it?
> >
> > This change is not required now. The code has been internally optimized. I
> will revert this change.
> 
> Thanks,
> /Bruce

Thanks,
Amit Shukla

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v3] mem: telemetry support for memseg and element information
  2022-05-19  6:30 [PATCH] mem: telemetry support for memseg and element information Amit Prakash Shukla
  2022-05-19 12:42 ` David Marchand
  2022-05-19 18:57 ` [PATCH v2] " Amit Prakash Shukla
@ 2022-05-24 10:33 ` Amit Prakash Shukla
  2022-05-25 10:33 ` [PATCH v4 1/2] " Amit Prakash Shukla
  3 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-05-24 10:33 UTC (permalink / raw)
  To: Anatoly Burakov; +Cc: dev, jerinj, bruce.richardson, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/memseg_list_array
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/memseg_list_array
{"/eal/memseg_list_array": [0, 1]}

2. /eal/memseg_list_info,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input. Command also
supports help.
Example:
--> /eal/memseg_list_info,help
{"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}

--> /eal/memseg_list_info,1
{"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
 12, 13, 14, 15]}

3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input. Command also
supports help.
Example:
--> /eal/memseg_info,help
{"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>, \
<memseg-id>"}

--> /eal/memseg_info,0,10
{"/eal/memseg_info": {"Memseg_list_index": 0,  \
"Memseg_index": 10, "Memseg_list_len": 64,     \
"Start_addr": "0x260000000", "End_addr": "0x280000000",  \
"Size": 536870912}}

--> /eal/memseg_info,1,15
{"/eal/memseg_info": {"Memseg_list_index": 1,   \
"Memseg_index": 15, "Memseg_list_len": 64,      \
"Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
"Size": 536870912}}

4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Command also supports help.
Example:
--> /eal/element_list,help
{"/eal/element_list": "/eal/element_list,<heap-id>,  \
<memseg-list-id>,<memseg-id>"}

--> /eal/element_list,0,0,63
{"/eal/element_list": {"Element_count": 52}}

--> /eal/element_list,0,1,15
{"/eal/element_list": {"Element_count": 52}}

5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
   <elem-start-id>,<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed. Command also supports help.
Example:
--> /eal/element_info,help
{"/eal/element_info": "/eal/element_info,<heap-id>,  \
<memseg-list-id>,<memseg-id>,<elem-start-id>,<elem-end-id>"}

--> /eal/element_info,0,1,15,1,2
{"/eal/element_info": {"element.1": {"msl_id": 1,    \
"ms_id": 15, "memseg_start_addr": "0xb20000000",     \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb201fe680",                 \
"element_end_addr": "0xb20bfe700",                   \
"element_size": 10485888, "element_state": "Busy"},  \
"element.2": {"msl_id": 1, "ms_id": 15,              \
"memseg_start_addr": "0xb20000000",                  \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb20bfe700",                 \
"element_end_addr": "0xb215fe780", "element_size": 10485888, \
"element_state": "Busy"}, "Element_count": 2}}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Fixed compilation error related int-to-pointer-cast
- Changes for code review suggestions

v3:
- Commit message changes
- Renaming end-points
- Changing input parameters to comma-seperated
- Reverting telemetry output buffer size

 lib/eal/common/eal_common_memory.c | 482 ++++++++++++++++++++++++++++-
 1 file changed, 477 insertions(+), 5 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 688dc615d7..e66de6a872 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -26,6 +26,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1113,11 +1114,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_LIST_ARR_REQ		"/eal/memseg_list_array"
+#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1265,6 +1272,454 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+static int
+handle_eal_memseg_list_array_request(const char *cmd __rte_unused,
+				     const char *params __rte_unused,
+				     struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
+				    const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	int ms_idx;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>", EAL_MEMSEG_LIST_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	if (!isdigit(*params))
+		return -1;
+
+	ms_list_idx = strtoul(params, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	uint32_t msl_len;
+	char dlim[2] = ",";
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>,<memseg-id>",
+			 EAL_MEMSEG_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	msl_len = arr->len;
+
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->hugepage_sz;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_int(d, "Size", ms_size);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	char dlim[2] = ",";
+	int elem_count = 0;
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>",
+			 EAL_ELEMENT_LIST_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char dlim[2] = ",";
+	char str[ADDR_STR];
+	char *params_args;
+	char *token;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>,"
+			 "<elem-start-id>,<elem-end-id>",
+			 EAL_ELEMENT_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	start_elem = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	end_elem = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	if (end_elem < start_elem)
+		return -1;
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		rte_tel_data_start_dict(c);
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s.%u", "element", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1279,5 +1734,22 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_ARR_REQ,
+			handle_eal_memseg_list_array_request,
+			"Returns hugepage list. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_INFO_REQ,
+			handle_eal_memseg_list_info_request,
+			"Returns memseg list. Parameters: int memseg_list_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns memseg info. Parameter: int memseg_list_id,int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns element info. Parameters: int heap_id, int memseg_list_id, int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element info. Parameters: int heap_id, memseg_list_id, memseg_id, start_elem_id, end_elem_id");
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v4 1/2] mem: telemetry support for memseg and element information
  2022-05-19  6:30 [PATCH] mem: telemetry support for memseg and element information Amit Prakash Shukla
                   ` (2 preceding siblings ...)
  2022-05-24 10:33 ` [PATCH v3] " Amit Prakash Shukla
@ 2022-05-25 10:33 ` Amit Prakash Shukla
  2022-05-25 10:33   ` [PATCH v4 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
                     ` (3 more replies)
  3 siblings, 4 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-05-25 10:33 UTC (permalink / raw)
  To: Anatoly Burakov; +Cc: dev, jerinj, bruce.richardson, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/memseg_list_array
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/memseg_list_array
{"/eal/memseg_list_array": [0, 1]}

2. /eal/memseg_list_info,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input. Command also
supports help.
Example:
--> /eal/memseg_list_info,help
{"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}

--> /eal/memseg_list_info,1
{"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
 12, 13, 14, 15]}

3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input. Command also
supports help.
Example:
--> /eal/memseg_info,help
{"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>, \
<memseg-id>"}

--> /eal/memseg_info,0,10
{"/eal/memseg_info": {"Memseg_list_index": 0,  \
"Memseg_index": 10, "Memseg_list_len": 64,     \
"Start_addr": "0x260000000", "End_addr": "0x280000000",  \
"Size": 536870912}}

--> /eal/memseg_info,1,15
{"/eal/memseg_info": {"Memseg_list_index": 1,   \
"Memseg_index": 15, "Memseg_list_len": 64,      \
"Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
"Size": 536870912}}

4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Command also supports help.
Example:
--> /eal/element_list,help
{"/eal/element_list": "/eal/element_list,<heap-id>,  \
<memseg-list-id>,<memseg-id>"}

--> /eal/element_list,0,0,63
{"/eal/element_list": {"Element_count": 52}}

--> /eal/element_list,0,1,15
{"/eal/element_list": {"Element_count": 52}}

5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
   <elem-start-id>,<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed. Command also supports help.
Example:
--> /eal/element_info,help
{"/eal/element_info": "/eal/element_info,<heap-id>,  \
<memseg-list-id>,<memseg-id>,<elem-start-id>,<elem-end-id>"}

--> /eal/element_info,0,1,15,1,2
{"/eal/element_info": {"element.1": {"msl_id": 1,    \
"ms_id": 15, "memseg_start_addr": "0xb20000000",     \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb201fe680",                 \
"element_end_addr": "0xb20bfe700",                   \
"element_size": 10485888, "element_state": "Busy"},  \
"element.2": {"msl_id": 1, "ms_id": 15,              \
"memseg_start_addr": "0xb20000000",                  \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb20bfe700",                 \
"element_end_addr": "0xb215fe780", "element_size": 10485888, \
"element_state": "Busy"}, "Element_count": 2}}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Fixed compilation error related int-to-pointer-cast
- Changes for code review suggestions

v3:
- Commit message changes
- Renaming end-points
- Changing input parameters to comma-seperated
- Reverting telemetry output buffer size

v4:
- Patch-2 adds telemetry support to display system memory

 lib/eal/common/eal_common_memory.c | 482 ++++++++++++++++++++++++++++-
 1 file changed, 477 insertions(+), 5 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 688dc615d7..e66de6a872 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -26,6 +26,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1113,11 +1114,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_LIST_ARR_REQ		"/eal/memseg_list_array"
+#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1265,6 +1272,454 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+static int
+handle_eal_memseg_list_array_request(const char *cmd __rte_unused,
+				     const char *params __rte_unused,
+				     struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
+				    const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	int ms_idx;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>", EAL_MEMSEG_LIST_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	if (!isdigit(*params))
+		return -1;
+
+	ms_list_idx = strtoul(params, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	uint32_t msl_len;
+	char dlim[2] = ",";
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<memseg-list-id>,<memseg-id>",
+			 EAL_MEMSEG_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	msl_len = arr->len;
+
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->hugepage_sz;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_int(d, "Size", ms_size);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	char dlim[2] = ",";
+	int elem_count = 0;
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>",
+			 EAL_ELEMENT_LIST_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char dlim[2] = ",";
+	char str[ADDR_STR];
+	char *params_args;
+	char *token;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (strncasecmp(params, "help", strlen(params)) == 0) {
+		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
+		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
+			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>,"
+			 "<elem-start-id>,<elem-end-id>",
+			 EAL_ELEMENT_INFO_REQ);
+		rte_tel_data_string(d, buff);
+		return 0;
+	}
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	start_elem = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	end_elem = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	if (end_elem < start_elem)
+		return -1;
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		rte_tel_data_start_dict(c);
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s.%u", "element", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1279,5 +1734,22 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_ARR_REQ,
+			handle_eal_memseg_list_array_request,
+			"Returns hugepage list. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_INFO_REQ,
+			handle_eal_memseg_list_info_request,
+			"Returns memseg list. Parameters: int memseg_list_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns memseg info. Parameter: int memseg_list_id,int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns element info. Parameters: int heap_id, int memseg_list_id, int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element info. Parameters: int heap_id, memseg_list_id, memseg_id, start_elem_id, end_elem_id");
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v4 2/2] mem: telemetry support for system memory information
  2022-05-25 10:33 ` [PATCH v4 1/2] " Amit Prakash Shukla
@ 2022-05-25 10:33   ` Amit Prakash Shukla
  2022-06-30  5:54     ` Amit Prakash Shukla
  2022-06-14 12:50   ` [PATCH v4 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-05-25 10:33 UTC (permalink / raw)
  To: Anatoly Burakov; +Cc: dev, jerinj, bruce.richardson, Amit Prakash Shukla

Changes adds telemetry support to display system memory information,
allocated using calls malloc, calloc, mmap, etc. This patch
is based on malloc_info. This patch adds following endpoints:

1. /sysmem/sys_heap_list
The commands displays the arenas currently in use.
Example:
--> /sysmem/sys_heap_list
{"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

2. /sysmem/sys_heap_info,<arena-id>
This command displays the information about arena.
Example:
--> /sysmem/sys_heap_info,0
{"/sysmem/sys_heap_info": {"Arena_id": 0, "Allocated_size": 2069934, \
 "Free_count": 4, "Free_size": 223826, "Curr_size": 2293760,         \
 "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                   \
 "Heap_size": 2293760}}
--> /sysmem/sys_heap_info,6
{"/sysmem/sys_heap_info": {"Arena_id": 6, "Allocated_size": 3136, \
 "Free_count": 2, "Free_size": 193472, "Curr_size": 196608,       \
 "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 1,                \
 "Heap_size": 196608}}

The last arena-id in the list gives total of all arenas.

--> /sysmem/sys_heap_info,10
{"/sysmem/sys_heap_info": {"Arena_id": 10, "Allocated_size": 2107774, \
 "Free_count": 20, "Free_size": 1955458, "Curr_size": 4063232,        \
 "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                    \
 "Heap_size": 4063232}}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
 lib/eal/common/eal_common_memory.c | 330 +++++++++++++++++++++++++++++
 1 file changed, 330 insertions(+)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index e66de6a872..a1677082c1 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -8,6 +8,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <inttypes.h>
+#ifdef RTE_EXEC_ENV_LINUX
+#include <malloc.h>
+#endif
 
 #include <rte_fbarray.h>
 #include <rte_memory.h>
@@ -1123,6 +1126,12 @@ rte_eal_memory_init(void)
 #define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
 #define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
 #define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
+
+#ifdef RTE_EXEC_ENV_LINUX
+#define SYSMEMORY_LIST_REQ		"/sysmem/sys_heap_list"
+#define SYSMEMORY_INFO_REQ		"/sysmem/sys_heap_info"
+#endif
+
 #define ADDR_STR			15
 
 
@@ -1720,6 +1729,318 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+#ifdef RTE_EXEC_ENV_LINUX
+#define MAX_SYS_MEM_ARENAS	128
+#define MAX_TAG_CHAR		128
+
+/* Memory size are in bytes. */
+struct mem_stats {
+	uint64_t fast_count; /* Number of free blocks in fast bin. */
+	uint64_t fast_size;  /* Size in bytes of free blocks in fast bin. */
+	uint64_t rest_count; /* Number of free blocks in bin. */
+	uint64_t rest_size;  /* Size in bytes of free blocks in bin. */
+	uint64_t mmap_count; /* Number of mmap blocks. */
+	uint64_t mmap_size;  /* Size in bytes of mmap'd memory. */
+	uint64_t curr_size;  /* Size in bytes allocated by system. */
+	uint64_t heap_size;  /* Heap size in bytes. */
+	uint64_t heap_count; /* Number of heaps. */
+};
+
+struct rte_heap_mem_stats {
+	unsigned int num_active_arena;
+	struct mem_stats stats[MAX_SYS_MEM_ARENAS];
+};
+
+/* This function shall be called to parse only attributes.
+ * Parsing of the "tags" shall be done by the caller.
+ */
+static int
+parse_attr(char *buf, uint32_t *i, char *attr, const char *key)
+{
+	int j = 0;
+	int keymatch = 0;
+
+	attr[j] = '\0';
+
+	while ((buf[*i] != '>') && (j < MAX_TAG_CHAR)) {
+		/* Ignore spaces. */
+		if (buf[*i] == ' ') {
+			attr[j] = '\0';
+			j = 0;
+			(*i)++;
+			continue;
+		}
+
+		/* Attribute key */
+		if (buf[*i] == '=') {
+			attr[j] = '\0';
+			j = 0;
+			(*i)++;
+
+			/* If the key is matched, extract the value. */
+			if (strncmp(attr, key, strlen(key)) != 0)
+				continue;
+			else
+				keymatch = 1;
+		}
+
+		/* Attribute value */
+		if ((buf[*i] == '"') && (keymatch == 1)) {
+			j = 0;
+			(*i)++;
+
+			while ((buf[*i] != '"') && (j < MAX_TAG_CHAR))
+				attr[(j)++] = buf[(*i)++];
+			attr[j] = '\0';
+			(*i)++;
+			return 0;
+		}
+
+		keymatch = 0;
+		attr[(j)++] = buf[(*i)++];
+	}
+
+	(*i)++;
+	return -1;
+}
+
+/* Get the system memory stats into buffer by calling malloc_info().
+ * malloc_info() returns the stats in XML format. Parse the XML to extract
+ * number of heaps, size of each heap, free memory in heap.
+ */
+static int
+parse_heap_mem_stats(struct rte_heap_mem_stats *heap_stats)
+{
+	char tag[MAX_TAG_CHAR] = {0};
+	int old_mem_index = -1;
+	int mem_index = -1;
+	uint32_t i = 0;
+	uint32_t j = 0;
+	size_t length;
+	char *buf;
+	FILE *fp;
+	int ret;
+
+	/* buf is dynamically allocated by open_memstream. */
+	fp = open_memstream(&buf, &length);
+	if (fp == NULL) {
+		RTE_LOG(DEBUG, EAL, "Error: Failed to open memory stream\n");
+		return -1;
+	}
+
+	/* Gets system memory stat's XML format. */
+	ret = malloc_info(0, fp);
+	fclose(fp);
+
+	if (ret != 0) {
+		RTE_LOG(DEBUG, EAL, "Error: malloc_info returned error\n");
+		return -1;
+	}
+
+	while (i < length) {
+		j = 0;
+		tag[j] = '\0';
+
+		/* Ignore newline and spaces. */
+		if ((buf[i] == '\n') || (buf[i] == ' ') || (buf[i] == '/') ||
+		    (buf[i] == '>')) {
+			i++;
+			continue;
+		}
+
+		if (buf[i] == '<') {
+			i++;
+			while ((buf[i] != ' ') && (buf[i] != '>') &&
+			       (j < MAX_TAG_CHAR)) {
+				tag[j++] = buf[i++];
+			}
+
+			if (strncmp(tag, "heap", strlen("heap")) == 0) {
+				old_mem_index = mem_index++;
+				if (mem_index >= MAX_SYS_MEM_ARENAS) {
+					RTE_LOG(DEBUG, EAL, "Memory arena "
+						"exceeded max limit: %d",
+						MAX_SYS_MEM_ARENAS);
+					goto done;
+				}
+				heap_stats->num_active_arena++;
+			}
+
+			continue;
+		}
+
+		if (mem_index < 0) {
+			i++;
+			continue;
+		}
+
+		if (parse_attr(buf, &i, tag, "type") < 0)
+			continue;
+
+		if (strncmp(tag, "fast", strlen("fast")) == 0) {
+			/* For total of all arenas, "heap" tag is not present
+			 * in xml. Below check is to handle that scenarios.
+			 *
+			 * FIXME: mem_index increment shall be independent of
+			 * the tag.
+			 */
+			if (old_mem_index == mem_index) {
+				mem_index++;
+				if (mem_index >= MAX_SYS_MEM_ARENAS) {
+					RTE_LOG(DEBUG, EAL, "Memory arena "
+						"exceeded max limit: %d\n",
+						MAX_SYS_MEM_ARENAS);
+					goto done;
+				}
+				heap_stats->num_active_arena++;
+			}
+			old_mem_index = mem_index;
+
+			if (parse_attr(buf, &i, tag, "count") == 0)
+				heap_stats->stats[mem_index].fast_count =
+							strtoul(tag, NULL, 10);
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].fast_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "rest", strlen("rest")) == 0) {
+			if (parse_attr(buf, &i, tag, "count") == 0)
+				heap_stats->stats[mem_index].rest_count =
+							strtoul(tag, NULL, 10);
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].rest_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "current", strlen("current")) == 0) {
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].curr_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "total", strlen("total")) == 0) {
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].heap_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "subheaps", strlen("subheaps")) == 0) {
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].heap_count =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "mmap", strlen("mmap")) == 0) {
+			if (parse_attr(buf, &i, tag, "count") == 0)
+				heap_stats->stats[mem_index].mmap_count =
+							strtoul(tag, NULL, 10);
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].mmap_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		i++;
+	}
+
+done:
+	/* All done! Let's free the buf. */
+	free(buf);
+	return 0;
+}
+
+static int
+handle_sysmem_list_request(const char *cmd __rte_unused,
+			   const char *params __rte_unused,
+			   struct rte_tel_data *d)
+{
+	struct rte_heap_mem_stats heap_mem_stats;
+	unsigned int num_arena;
+	unsigned int i;
+
+	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
+	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
+		return -1;
+
+	/* Note:
+	 * Total active arenas are (num_active_arena - 1). The last entry in
+	 * the array is total of all arenas.
+	 */
+	num_arena = heap_mem_stats.num_active_arena;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+	for (i = 0; i < num_arena; i++)
+		rte_tel_data_add_array_int(d, i);
+
+	return 0;
+}
+
+static int
+handle_sysmem_info_request(const char *cmd __rte_unused, const char *params,
+			   struct rte_tel_data *d)
+{
+	struct rte_heap_mem_stats heap_mem_stats;
+	unsigned int arena_id;
+	uint64_t free_size;
+	uint64_t free_count;
+	uint64_t allocated_size;
+
+	if (params == NULL || strlen(params) == 0 || !isdigit(*params))
+		return -1;
+
+	arena_id = (unsigned int)strtoul(params, NULL, 10);
+	if (arena_id > UINT32_MAX)
+		return -1;
+
+	if (arena_id >= MAX_SYS_MEM_ARENAS)
+		return -1;
+
+	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
+	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
+		return -1;
+
+	if (arena_id >= heap_mem_stats.num_active_arena) {
+		RTE_LOG(DEBUG, EAL, "Memory arena exceeded max limit: %d\n",
+			MAX_SYS_MEM_ARENAS);
+		return -1;
+	}
+
+	/* Fast and rest account for the total free memory. */
+	free_size = heap_mem_stats.stats[arena_id].fast_size +
+		    heap_mem_stats.stats[arena_id].rest_size;
+
+	free_count = heap_mem_stats.stats[arena_id].fast_count +
+		     heap_mem_stats.stats[arena_id].rest_count;
+
+	/* (System memory - free size) = allocated memory size. */
+	allocated_size = heap_mem_stats.stats[arena_id].curr_size - free_size;
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Arena_id", arena_id);
+	rte_tel_data_add_dict_int(d, "Allocated_size", allocated_size);
+	rte_tel_data_add_dict_u64(d, "Free_count", free_count);
+	rte_tel_data_add_dict_u64(d, "Free_size", free_size);
+	rte_tel_data_add_dict_u64(d, "Curr_size",
+				  heap_mem_stats.stats[arena_id].curr_size);
+	rte_tel_data_add_dict_u64(d, "Mmap_count",
+				  heap_mem_stats.stats[arena_id].mmap_count);
+	rte_tel_data_add_dict_u64(d, "Mmap_size",
+				  heap_mem_stats.stats[arena_id].mmap_size);
+	rte_tel_data_add_dict_u64(d, "Heap_count",
+				  heap_mem_stats.stats[arena_id].heap_count);
+	rte_tel_data_add_dict_u64(d, "Heap_size",
+				  heap_mem_stats.stats[arena_id].heap_size);
+
+	return 0;
+}
+#endif
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1751,5 +2072,14 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
 			handle_eal_element_info_request,
 			"Returns element info. Parameters: int heap_id, memseg_list_id, memseg_id, start_elem_id, end_elem_id");
+
+#ifdef RTE_EXEC_ENV_LINUX
+	rte_telemetry_register_cmd(SYSMEMORY_LIST_REQ,
+			handle_sysmem_list_request,
+			"Returns element information. Takes no parameters");
+	rte_telemetry_register_cmd(SYSMEMORY_INFO_REQ,
+			handle_sysmem_info_request,
+			"Returns element information. Parameters: int arena_id");
+#endif
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v4 1/2] mem: telemetry support for memseg and element information
  2022-05-25 10:33 ` [PATCH v4 1/2] " Amit Prakash Shukla
  2022-05-25 10:33   ` [PATCH v4 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
@ 2022-06-14 12:50   ` Amit Prakash Shukla
  2022-06-30  5:52     ` Amit Prakash Shukla
  2022-09-29  8:29   ` David Marchand
  2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
  3 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-06-14 12:50 UTC (permalink / raw)
  To: Amit Prakash Shukla, Anatoly Burakov
  Cc: dev, Jerin Jacob Kollanukkaran, bruce.richardson

Ping.

> -----Original Message-----
> From: Amit Prakash Shukla <amitprakashs@marvell.com>
> Sent: Wednesday, May 25, 2022 4:04 PM
> To: Anatoly Burakov <anatoly.burakov@intel.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> bruce.richardson@intel.com; Amit Prakash Shukla
> <amitprakashs@marvell.com>
> Subject: [PATCH v4 1/2] mem: telemetry support for memseg and element
> information
> 
> Changes adds telemetry support to display memory occupancy in memseg
> and the information of the elements allocated from a memseg based on
> arguments provided by user. This patch adds following endpoints:
> 
> 1. /eal/memseg_list_array
> The command displays the memseg list from which the memory has been
> allocated.
> Example:
> --> /eal/memseg_list_array
> {"/eal/memseg_list_array": [0, 1]}
> 
> 2. /eal/memseg_list_info,<memseg-list-id>
> The command outputs the memsegs, from which the memory is allocated,
> for the memseg_list given as input. Command also supports help.
> Example:
> --> /eal/memseg_list_info,help
> {"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}
> 
> --> /eal/memseg_list_info,1
> {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \  12, 13, 14, 15]}
> 
> 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> The command outputs the memseg information based on the memseg-list
> and the memseg-id given as input. Command also supports help.
> Example:
> --> /eal/memseg_info,help
> {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>, \ <memseg-
> id>"}
> 
> --> /eal/memseg_info,0,10
> {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> "Memseg_index": 10, "Memseg_list_len": 64,     \
> "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> "Size": 536870912}}
> 
> --> /eal/memseg_info,1,15
> {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> "Memseg_index": 15, "Memseg_list_len": 64,      \
> "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> "Size": 536870912}}
> 
> 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based on the heap-
> id, memseg-list-id and memseg-id given as input.
> Command also supports help.
> Example:
> --> /eal/element_list,help
> {"/eal/element_list": "/eal/element_list,<heap-id>,  \ <memseg-list-
> id>,<memseg-id>"}
> 
> --> /eal/element_list,0,0,63
> {"/eal/element_list": {"Element_count": 52}}
> 
> --> /eal/element_list,0,1,15
> {"/eal/element_list": {"Element_count": 52}}
> 
> 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>    <elem-start-id>,<elem-end-id>
> The command outputs element information like element start address, end
> address, to which memseg it belongs, element state, element size. User can
> give a range of elements to be printed. Command also supports help.
> Example:
> --> /eal/element_info,help
> {"/eal/element_info": "/eal/element_info,<heap-id>,  \ <memseg-list-
> id>,<memseg-id>,<elem-start-id>,<elem-end-id>"}
> 
> --> /eal/element_info,0,1,15,1,2
> {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb201fe680",                 \
> "element_end_addr": "0xb20bfe700",                   \
> "element_size": 10485888, "element_state": "Busy"},  \
> "element.2": {"msl_id": 1, "ms_id": 15,              \
> "memseg_start_addr": "0xb20000000",                  \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb20bfe700",                 \
> "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> "element_state": "Busy"}, "Element_count": 2}}
> 
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Fixed compilation error related int-to-pointer-cast
> - Changes for code review suggestions
> 
> v3:
> - Commit message changes
> - Renaming end-points
> - Changing input parameters to comma-seperated
> - Reverting telemetry output buffer size
> 
> v4:
> - Patch-2 adds telemetry support to display system memory
> 
>  lib/eal/common/eal_common_memory.c | 482
> ++++++++++++++++++++++++++++-
>  1 file changed, 477 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/eal/common/eal_common_memory.c
> b/lib/eal/common/eal_common_memory.c
> index 688dc615d7..e66de6a872 100644
> --- a/lib/eal/common/eal_common_memory.c
> +++ b/lib/eal/common/eal_common_memory.c
> @@ -26,6 +26,7 @@
>  #include "eal_memcfg.h"
>  #include "eal_options.h"
>  #include "malloc_heap.h"
> +#include "malloc_elem.h"
> 
>  /*
>   * Try to mmap *size bytes in /dev/zero. If it is successful, return the @@ -
> 1113,11 +1114,17 @@ rte_eal_memory_init(void)  }
> 
>  #ifndef RTE_EXEC_ENV_WINDOWS
> -#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
> -#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
> -#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
> -#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
> -#define ADDR_STR		15
> +#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
> +#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
> +#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
> +#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
> +#define EAL_MEMSEG_LIST_ARR_REQ
> 	"/eal/memseg_list_array"
> +#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
> +#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
> +#define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
> +#define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
> +#define ADDR_STR			15
> +
> 
>  /* Telemetry callback handler to return heap stats for requested heap id. */
> static int @@ -1265,6 +1272,454 @@
> handle_eal_memzone_list_request(const char *cmd __rte_unused,
>  	return 0;
>  }
> 
> +static int
> +handle_eal_memseg_list_array_request(const char *cmd __rte_unused,
> +				     const char *params __rte_unused,
> +				     struct rte_tel_data *d)
> +{
> +	struct rte_mem_config *mcfg;
> +	int i;
> +
> +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +	rte_mcfg_mem_read_lock();
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +
> +	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
> +		struct rte_memseg_list *msl = &mcfg->memsegs[i];
> +		if (msl->memseg_arr.count == 0)
> +			continue;
> +
> +		rte_tel_data_add_array_int(d, i);
> +	}
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
> +				    const char *params, struct rte_tel_data *d)
> {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	struct rte_fbarray *arr;
> +	uint32_t ms_list_idx;
> +	int ms_idx;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> +			 "%s,<memseg-list-id>",
> EAL_MEMSEG_LIST_INFO_REQ);
> +		rte_tel_data_string(d, buff);
> +		return 0;
> +	}
> +
> +	if (!isdigit(*params))
> +		return -1;
> +
> +	ms_list_idx = strtoul(params, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> +		return -1;
> +
> +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +	rte_mcfg_mem_read_lock();
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	if (msl->memseg_arr.count == 0)
> +		goto done;
> +
> +	arr = &msl->memseg_arr;
> +
> +	ms_idx = rte_fbarray_find_next_used(arr, 0);
> +	while (ms_idx >= 0) {
> +		rte_tel_data_add_array_int(d, ms_idx);
> +		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
> +	}
> +
> +done:
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> +			       const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	uint64_t ms_start_addr, ms_end_addr, ms_size;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct rte_fbarray *arr;
> +	char addr[ADDR_STR];
> +	uint32_t ms_list_idx = 0;
> +	uint32_t ms_idx = 0;
> +	uint32_t msl_len;
> +	char dlim[2] = ",";
> +	char *token;
> +	char *params_args;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> +			 "%s,<memseg-list-id>,<memseg-id>",
> +			 EAL_MEMSEG_INFO_REQ);
> +		rte_tel_data_string(d, buff);
> +		return 0;
> +	}
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);
> +	token = strtok(params_args, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_list_idx = strtoul(token, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +	ms_idx = strtoul(token, NULL, 10);
> +
> +	free(params_args);
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	if (msl->memseg_arr.count == 0) {
> +		rte_mcfg_mem_read_unlock();
> +		return -1;
> +	}
> +
> +	arr = &msl->memseg_arr;
> +	msl_len = arr->len;
> +
> +	ms = rte_fbarray_get(arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +	ms_size = ms->hugepage_sz;
> +
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> +	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> +	rte_tel_data_add_dict_int(d, "Size", ms_size);
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_element_list_request(const char *cmd __rte_unused,
> +				const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct malloc_elem *elem;
> +	struct malloc_heap *heap;
> +	uint64_t ms_start_addr, ms_end_addr;
> +	uint64_t elem_start_addr, elem_end_addr;
> +	uint32_t ms_list_idx = 0;
> +	uint32_t heap_id = 0;
> +	uint32_t ms_idx = 0;
> +	char dlim[2] = ",";
> +	int elem_count = 0;
> +	char *token;
> +	char *params_args;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> +			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>",
> +			 EAL_ELEMENT_LIST_REQ);
> +		rte_tel_data_string(d, buff);
> +		return 0;
> +	}
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);
> +	token = strtok(params_args, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	heap_id = strtoul(token, NULL, 10);
> +	if (heap_id >= RTE_MAX_HEAPS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_list_idx = strtoul(token, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_idx = strtoul(token, NULL, 10);
> +
> +	free(params_args);
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +
> +	heap = &mcfg->malloc_heaps[heap_id];
> +	rte_spinlock_lock(&heap->lock);
> +
> +	elem = heap->first;
> +	while (elem) {
> +		elem_start_addr = (uint64_t)elem;
> +		elem_end_addr =
> +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> >size);
> +
> +		if ((uint64_t)elem_start_addr >= ms_start_addr &&
> +		    (uint64_t)elem_end_addr <= ms_end_addr)
> +			elem_count++;
> +		elem = elem->next;
> +	}
> +
> +	rte_spinlock_unlock(&heap->lock);
> +
> +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_element_info_request(const char *cmd __rte_unused,
> +				const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct malloc_elem *elem;
> +	struct malloc_heap *heap;
> +	struct rte_tel_data *c;
> +	uint64_t ms_start_addr, ms_end_addr;
> +	uint64_t elem_start_addr, elem_end_addr;
> +	uint32_t ms_list_idx = 0;
> +	uint32_t heap_id = 0;
> +	uint32_t ms_idx = 0;
> +	uint32_t start_elem = 0, end_elem = 0;
> +	uint32_t count = 0, elem_count = 0;
> +	char dlim[2] = ",";
> +	char str[ADDR_STR];
> +	char *params_args;
> +	char *token;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> +			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>,"
> +			 "<elem-start-id>,<elem-end-id>",
> +			 EAL_ELEMENT_INFO_REQ);
> +		rte_tel_data_string(d, buff);
> +		return 0;
> +	}
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);
> +	token = strtok(params_args, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	heap_id = strtoul(token, NULL, 10);
> +	if (heap_id >= RTE_MAX_HEAPS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_list_idx = strtoul(token, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_idx = strtoul(token, NULL, 10);
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	start_elem = strtoul(token, NULL, 10);
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	end_elem = strtoul(token, NULL, 10);
> +
> +	free(params_args);
> +
> +	if (end_elem < start_elem)
> +		return -1;
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +
> +	heap = &mcfg->malloc_heaps[heap_id];
> +	rte_spinlock_lock(&heap->lock);
> +
> +	elem = heap->first;
> +	while (elem) {
> +		elem_start_addr = (uint64_t)elem;
> +		elem_end_addr =
> +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> >size);
> +
> +		if (elem_start_addr < ms_start_addr ||
> +				elem_end_addr > ms_end_addr) {
> +			elem = elem->next;
> +			continue;
> +		}
> +
> +		if (count < start_elem) {
> +			elem = elem->next;
> +			count++;
> +			continue;
> +		}
> +
> +		c = rte_tel_data_alloc();
> +		if (c == NULL)
> +			break;
> +
> +		rte_tel_data_start_dict(c);
> +		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
> +		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> +		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> +		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
> +		rte_tel_data_add_dict_string(c, "element_start_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
> +		rte_tel_data_add_dict_string(c, "element_end_addr", str);
> +		rte_tel_data_add_dict_int(c, "element_size", elem->size);
> +		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
> +			 elem->state == 1 ? "Busy" : elem->state == 2 ?
> +			 "Pad" : "Error");
> +		rte_tel_data_add_dict_string(c, "element_state", str);
> +
> +		snprintf(str, ADDR_STR, "%s.%u", "element", count);
> +		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
> +			rte_tel_data_free(c);
> +			break;
> +		}
> +
> +		elem_count++;
> +		count++;
> +		if (count > end_elem)
> +			break;
> +
> +		elem = elem->next;
> +	}
> +
> +	rte_spinlock_unlock(&heap->lock);
> +
> +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> +
> +	return 0;
> +}
> +
>  RTE_INIT(memory_telemetry)
>  {
>  	rte_telemetry_register_cmd(
> @@ -1279,5 +1734,22 @@ RTE_INIT(memory_telemetry)
>  	rte_telemetry_register_cmd(
>  			EAL_HEAP_INFO_REQ,
> handle_eal_heap_info_request,
>  			"Returns malloc heap stats. Parameters: int
> heap_id");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LIST_ARR_REQ,
> +			handle_eal_memseg_list_array_request,
> +			"Returns hugepage list. Takes no parameters");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LIST_INFO_REQ,
> +			handle_eal_memseg_list_info_request,
> +			"Returns memseg list. Parameters: int
> memseg_list_id");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_INFO_REQ,
> handle_eal_memseg_info_request,
> +			"Returns memseg info. Parameter: int
> memseg_list_id,int memseg_id");
> +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> +			handle_eal_element_list_request,
> +			"Returns element info. Parameters: int heap_id, int
> memseg_list_id, int memseg_id");
> +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> +			handle_eal_element_info_request,
> +			"Returns element info. Parameters: int heap_id,
> memseg_list_id,
> +memseg_id, start_elem_id, end_elem_id");
>  }
>  #endif
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v4 1/2] mem: telemetry support for memseg and element information
  2022-06-14 12:50   ` [PATCH v4 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
@ 2022-06-30  5:52     ` Amit Prakash Shukla
  2022-07-21 11:20       ` Amit Prakash Shukla
  0 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-06-30  5:52 UTC (permalink / raw)
  To: Anatoly Burakov, david.marchand, bruce.richardson
  Cc: dev, Jerin Jacob Kollanukkaran

Ping.

> -----Original Message-----
> From: Amit Prakash Shukla <amitprakashs@marvell.com>
> Sent: Tuesday, June 14, 2022 6:21 PM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>; Anatoly Burakov
> <anatoly.burakov@intel.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> bruce.richardson@intel.com
> Subject: RE: [PATCH v4 1/2] mem: telemetry support for memseg and
> element information
> 
> Ping.
> 
> > -----Original Message-----
> > From: Amit Prakash Shukla <amitprakashs@marvell.com>
> > Sent: Wednesday, May 25, 2022 4:04 PM
> > To: Anatoly Burakov <anatoly.burakov@intel.com>
> > Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> > bruce.richardson@intel.com; Amit Prakash Shukla
> > <amitprakashs@marvell.com>
> > Subject: [PATCH v4 1/2] mem: telemetry support for memseg and element
> > information
> >
> > Changes adds telemetry support to display memory occupancy in memseg
> > and the information of the elements allocated from a memseg based on
> > arguments provided by user. This patch adds following endpoints:
> >
> > 1. /eal/memseg_list_array
> > The command displays the memseg list from which the memory has been
> > allocated.
> > Example:
> > --> /eal/memseg_list_array
> > {"/eal/memseg_list_array": [0, 1]}
> >
> > 2. /eal/memseg_list_info,<memseg-list-id>
> > The command outputs the memsegs, from which the memory is allocated,
> > for the memseg_list given as input. Command also supports help.
> > Example:
> > --> /eal/memseg_list_info,help
> > {"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}
> >
> > --> /eal/memseg_list_info,1
> > {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
> > 12, 13, 14, 15]}
> >
> > 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> > The command outputs the memseg information based on the memseg-list
> > and the memseg-id given as input. Command also supports help.
> > Example:
> > --> /eal/memseg_info,help
> > {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>, \ <memseg-
> > id>"}
> >
> > --> /eal/memseg_info,0,10
> > {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> > "Memseg_index": 10, "Memseg_list_len": 64,     \
> > "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> > "Size": 536870912}}
> >
> > --> /eal/memseg_info,1,15
> > {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> > "Memseg_index": 15, "Memseg_list_len": 64,      \
> > "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> > "Size": 536870912}}
> >
> > 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> > The command outputs number of elements in a memseg based on the
> heap-
> > id, memseg-list-id and memseg-id given as input.
> > Command also supports help.
> > Example:
> > --> /eal/element_list,help
> > {"/eal/element_list": "/eal/element_list,<heap-id>,  \ <memseg-list-
> > id>,<memseg-id>"}
> >
> > --> /eal/element_list,0,0,63
> > {"/eal/element_list": {"Element_count": 52}}
> >
> > --> /eal/element_list,0,1,15
> > {"/eal/element_list": {"Element_count": 52}}
> >
> > 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> >    <elem-start-id>,<elem-end-id>
> > The command outputs element information like element start address,
> > end address, to which memseg it belongs, element state, element size.
> > User can give a range of elements to be printed. Command also supports
> help.
> > Example:
> > --> /eal/element_info,help
> > {"/eal/element_info": "/eal/element_info,<heap-id>,  \ <memseg-list-
> > id>,<memseg-id>,<elem-start-id>,<elem-end-id>"}
> >
> > --> /eal/element_info,0,1,15,1,2
> > {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb201fe680",                 \
> > "element_end_addr": "0xb20bfe700",                   \
> > "element_size": 10485888, "element_state": "Busy"},  \
> > "element.2": {"msl_id": 1, "ms_id": 15,              \
> > "memseg_start_addr": "0xb20000000",                  \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb20bfe700",                 \
> > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > "element_state": "Busy"}, "Element_count": 2}}
> >
> > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> > ---
> > v2:
> > - Fixed compilation error related int-to-pointer-cast
> > - Changes for code review suggestions
> >
> > v3:
> > - Commit message changes
> > - Renaming end-points
> > - Changing input parameters to comma-seperated
> > - Reverting telemetry output buffer size
> >
> > v4:
> > - Patch-2 adds telemetry support to display system memory
> >
> >  lib/eal/common/eal_common_memory.c | 482
> > ++++++++++++++++++++++++++++-
> >  1 file changed, 477 insertions(+), 5 deletions(-)
> >
> > diff --git a/lib/eal/common/eal_common_memory.c
> > b/lib/eal/common/eal_common_memory.c
> > index 688dc615d7..e66de6a872 100644
> > --- a/lib/eal/common/eal_common_memory.c
> > +++ b/lib/eal/common/eal_common_memory.c
> > @@ -26,6 +26,7 @@
> >  #include "eal_memcfg.h"
> >  #include "eal_options.h"
> >  #include "malloc_heap.h"
> > +#include "malloc_elem.h"
> >
> >  /*
> >   * Try to mmap *size bytes in /dev/zero. If it is successful, return
> > the @@ -
> > 1113,11 +1114,17 @@ rte_eal_memory_init(void)  }
> >
> >  #ifndef RTE_EXEC_ENV_WINDOWS
> > -#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
> > -#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
> > -#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
> > -#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
> > -#define ADDR_STR		15
> > +#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
> > +#define EAL_MEMZONE_INFO_REQ
> 	"/eal/memzone_info"
> > +#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
> > +#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
> > +#define EAL_MEMSEG_LIST_ARR_REQ
> > 	"/eal/memseg_list_array"
> > +#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
> > +#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
> > +#define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
> > +#define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
> > +#define ADDR_STR			15
> > +
> >
> >  /* Telemetry callback handler to return heap stats for requested heap
> > id. */ static int @@ -1265,6 +1272,454 @@
> > handle_eal_memzone_list_request(const char *cmd __rte_unused,
> >  	return 0;
> >  }
> >
> > +static int
> > +handle_eal_memseg_list_array_request(const char *cmd __rte_unused,
> > +				     const char *params __rte_unused,
> > +				     struct rte_tel_data *d)
> > +{
> > +	struct rte_mem_config *mcfg;
> > +	int i;
> > +
> > +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> > +
> > +	rte_mcfg_mem_read_lock();
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +
> > +	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
> > +		struct rte_memseg_list *msl = &mcfg->memsegs[i];
> > +		if (msl->memseg_arr.count == 0)
> > +			continue;
> > +
> > +		rte_tel_data_add_array_int(d, i);
> > +	}
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
> > +				    const char *params, struct rte_tel_data *d)
> > {
> > +	struct rte_mem_config *mcfg;
> > +	struct rte_memseg_list *msl;
> > +	struct rte_fbarray *arr;
> > +	uint32_t ms_list_idx;
> > +	int ms_idx;
> > +
> > +	if (params == NULL || strlen(params) == 0)
> > +		return -1;
> > +
> > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > +			 "%s,<memseg-list-id>",
> > EAL_MEMSEG_LIST_INFO_REQ);
> > +		rte_tel_data_string(d, buff);
> > +		return 0;
> > +	}
> > +
> > +	if (!isdigit(*params))
> > +		return -1;
> > +
> > +	ms_list_idx = strtoul(params, NULL, 10);
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> > +		return -1;
> > +
> > +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> > +
> > +	rte_mcfg_mem_read_lock();
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	if (msl->memseg_arr.count == 0)
> > +		goto done;
> > +
> > +	arr = &msl->memseg_arr;
> > +
> > +	ms_idx = rte_fbarray_find_next_used(arr, 0);
> > +	while (ms_idx >= 0) {
> > +		rte_tel_data_add_array_int(d, ms_idx);
> > +		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
> > +	}
> > +
> > +done:
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> > +			       const char *params, struct rte_tel_data *d) {
> > +	struct rte_mem_config *mcfg;
> > +	uint64_t ms_start_addr, ms_end_addr, ms_size;
> > +	struct rte_memseg_list *msl;
> > +	const struct rte_memseg *ms;
> > +	struct rte_fbarray *arr;
> > +	char addr[ADDR_STR];
> > +	uint32_t ms_list_idx = 0;
> > +	uint32_t ms_idx = 0;
> > +	uint32_t msl_len;
> > +	char dlim[2] = ",";
> > +	char *token;
> > +	char *params_args;
> > +
> > +	if (params == NULL || strlen(params) == 0)
> > +		return -1;
> > +
> > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > +			 "%s,<memseg-list-id>,<memseg-id>",
> > +			 EAL_MEMSEG_INFO_REQ);
> > +		rte_tel_data_string(d, buff);
> > +		return 0;
> > +	}
> > +
> > +	/* strtok expects char * and param is const char *. Hence on using
> > +	 * params as "const char *" compiler throws warning.
> > +	 */
> > +	params_args = strdup(params);
> > +	token = strtok(params_args, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	ms_list_idx = strtoul(token, NULL, 10);
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	token = strtok(NULL, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +	ms_idx = strtoul(token, NULL, 10);
> > +
> > +	free(params_args);
> > +
> > +	rte_mcfg_mem_read_lock();
> > +
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	if (msl->memseg_arr.count == 0) {
> > +		rte_mcfg_mem_read_unlock();
> > +		return -1;
> > +	}
> > +
> > +	arr = &msl->memseg_arr;
> > +	msl_len = arr->len;
> > +
> > +	ms = rte_fbarray_get(arr, ms_idx);
> > +	if (ms == NULL) {
> > +		rte_mcfg_mem_read_unlock();
> > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > memseg.\n");
> > +		return -1;
> > +	}
> > +
> > +	ms_start_addr = ms->addr_64;
> > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > +	ms_size = ms->hugepage_sz;
> > +
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	rte_tel_data_start_dict(d);
> > +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> > +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> > +	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
> > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> > +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> > +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> > +	rte_tel_data_add_dict_int(d, "Size", ms_size);
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_element_list_request(const char *cmd __rte_unused,
> > +				const char *params, struct rte_tel_data *d) {
> > +	struct rte_mem_config *mcfg;
> > +	struct rte_memseg_list *msl;
> > +	const struct rte_memseg *ms;
> > +	struct malloc_elem *elem;
> > +	struct malloc_heap *heap;
> > +	uint64_t ms_start_addr, ms_end_addr;
> > +	uint64_t elem_start_addr, elem_end_addr;
> > +	uint32_t ms_list_idx = 0;
> > +	uint32_t heap_id = 0;
> > +	uint32_t ms_idx = 0;
> > +	char dlim[2] = ",";
> > +	int elem_count = 0;
> > +	char *token;
> > +	char *params_args;
> > +
> > +	if (params == NULL || strlen(params) == 0)
> > +		return -1;
> > +
> > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > +			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>",
> > +			 EAL_ELEMENT_LIST_REQ);
> > +		rte_tel_data_string(d, buff);
> > +		return 0;
> > +	}
> > +
> > +	/* strtok expects char * and param is const char *. Hence on using
> > +	 * params as "const char *" compiler throws warning.
> > +	 */
> > +	params_args = strdup(params);
> > +	token = strtok(params_args, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	heap_id = strtoul(token, NULL, 10);
> > +	if (heap_id >= RTE_MAX_HEAPS) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	token = strtok(NULL, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	ms_list_idx = strtoul(token, NULL, 10);
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	token = strtok(NULL, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	ms_idx = strtoul(token, NULL, 10);
> > +
> > +	free(params_args);
> > +
> > +	rte_mcfg_mem_read_lock();
> > +
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> > +	if (ms == NULL) {
> > +		rte_mcfg_mem_read_unlock();
> > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > memseg.\n");
> > +		return -1;
> > +	}
> > +
> > +	ms_start_addr = ms->addr_64;
> > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	rte_tel_data_start_dict(d);
> > +
> > +	heap = &mcfg->malloc_heaps[heap_id];
> > +	rte_spinlock_lock(&heap->lock);
> > +
> > +	elem = heap->first;
> > +	while (elem) {
> > +		elem_start_addr = (uint64_t)elem;
> > +		elem_end_addr =
> > +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> > >size);
> > +
> > +		if ((uint64_t)elem_start_addr >= ms_start_addr &&
> > +		    (uint64_t)elem_end_addr <= ms_end_addr)
> > +			elem_count++;
> > +		elem = elem->next;
> > +	}
> > +
> > +	rte_spinlock_unlock(&heap->lock);
> > +
> > +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_element_info_request(const char *cmd __rte_unused,
> > +				const char *params, struct rte_tel_data *d) {
> > +	struct rte_mem_config *mcfg;
> > +	struct rte_memseg_list *msl;
> > +	const struct rte_memseg *ms;
> > +	struct malloc_elem *elem;
> > +	struct malloc_heap *heap;
> > +	struct rte_tel_data *c;
> > +	uint64_t ms_start_addr, ms_end_addr;
> > +	uint64_t elem_start_addr, elem_end_addr;
> > +	uint32_t ms_list_idx = 0;
> > +	uint32_t heap_id = 0;
> > +	uint32_t ms_idx = 0;
> > +	uint32_t start_elem = 0, end_elem = 0;
> > +	uint32_t count = 0, elem_count = 0;
> > +	char dlim[2] = ",";
> > +	char str[ADDR_STR];
> > +	char *params_args;
> > +	char *token;
> > +
> > +	if (params == NULL || strlen(params) == 0)
> > +		return -1;
> > +
> > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > +			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>,"
> > +			 "<elem-start-id>,<elem-end-id>",
> > +			 EAL_ELEMENT_INFO_REQ);
> > +		rte_tel_data_string(d, buff);
> > +		return 0;
> > +	}
> > +
> > +	/* strtok expects char * and param is const char *. Hence on using
> > +	 * params as "const char *" compiler throws warning.
> > +	 */
> > +	params_args = strdup(params);
> > +	token = strtok(params_args, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	heap_id = strtoul(token, NULL, 10);
> > +	if (heap_id >= RTE_MAX_HEAPS) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	token = strtok(NULL, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	ms_list_idx = strtoul(token, NULL, 10);
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	token = strtok(NULL, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	ms_idx = strtoul(token, NULL, 10);
> > +
> > +	token = strtok(NULL, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	start_elem = strtoul(token, NULL, 10);
> > +
> > +	token = strtok(NULL, dlim);
> > +	if (token == NULL || !isdigit(*token)) {
> > +		free(params_args);
> > +		return -1;
> > +	}
> > +
> > +	end_elem = strtoul(token, NULL, 10);
> > +
> > +	free(params_args);
> > +
> > +	if (end_elem < start_elem)
> > +		return -1;
> > +
> > +	rte_mcfg_mem_read_lock();
> > +
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> > +	if (ms == NULL) {
> > +		rte_mcfg_mem_read_unlock();
> > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > memseg.\n");
> > +		return -1;
> > +	}
> > +
> > +	ms_start_addr = ms->addr_64;
> > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > +
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	rte_tel_data_start_dict(d);
> > +
> > +	heap = &mcfg->malloc_heaps[heap_id];
> > +	rte_spinlock_lock(&heap->lock);
> > +
> > +	elem = heap->first;
> > +	while (elem) {
> > +		elem_start_addr = (uint64_t)elem;
> > +		elem_end_addr =
> > +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> > >size);
> > +
> > +		if (elem_start_addr < ms_start_addr ||
> > +				elem_end_addr > ms_end_addr) {
> > +			elem = elem->next;
> > +			continue;
> > +		}
> > +
> > +		if (count < start_elem) {
> > +			elem = elem->next;
> > +			count++;
> > +			continue;
> > +		}
> > +
> > +		c = rte_tel_data_alloc();
> > +		if (c == NULL)
> > +			break;
> > +
> > +		rte_tel_data_start_dict(c);
> > +		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
> > +		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> > +		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> > +		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
> > +		rte_tel_data_add_dict_string(c, "element_start_addr", str);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
> > +		rte_tel_data_add_dict_string(c, "element_end_addr", str);
> > +		rte_tel_data_add_dict_int(c, "element_size", elem->size);
> > +		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
> > +			 elem->state == 1 ? "Busy" : elem->state == 2 ?
> > +			 "Pad" : "Error");
> > +		rte_tel_data_add_dict_string(c, "element_state", str);
> > +
> > +		snprintf(str, ADDR_STR, "%s.%u", "element", count);
> > +		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
> > +			rte_tel_data_free(c);
> > +			break;
> > +		}
> > +
> > +		elem_count++;
> > +		count++;
> > +		if (count > end_elem)
> > +			break;
> > +
> > +		elem = elem->next;
> > +	}
> > +
> > +	rte_spinlock_unlock(&heap->lock);
> > +
> > +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> > +
> > +	return 0;
> > +}
> > +
> >  RTE_INIT(memory_telemetry)
> >  {
> >  	rte_telemetry_register_cmd(
> > @@ -1279,5 +1734,22 @@ RTE_INIT(memory_telemetry)
> >  	rte_telemetry_register_cmd(
> >  			EAL_HEAP_INFO_REQ,
> > handle_eal_heap_info_request,
> >  			"Returns malloc heap stats. Parameters: int
> heap_id");
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_LIST_ARR_REQ,
> > +			handle_eal_memseg_list_array_request,
> > +			"Returns hugepage list. Takes no parameters");
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_LIST_INFO_REQ,
> > +			handle_eal_memseg_list_info_request,
> > +			"Returns memseg list. Parameters: int
> > memseg_list_id");
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_INFO_REQ,
> > handle_eal_memseg_info_request,
> > +			"Returns memseg info. Parameter: int
> > memseg_list_id,int memseg_id");
> > +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> > +			handle_eal_element_list_request,
> > +			"Returns element info. Parameters: int heap_id, int
> > memseg_list_id, int memseg_id");
> > +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> > +			handle_eal_element_info_request,
> > +			"Returns element info. Parameters: int heap_id,
> > memseg_list_id,
> > +memseg_id, start_elem_id, end_elem_id");
> >  }
> >  #endif
> > --
> > 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v4 2/2] mem: telemetry support for system memory information
  2022-05-25 10:33   ` [PATCH v4 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
@ 2022-06-30  5:54     ` Amit Prakash Shukla
  2022-07-21 11:21       ` Amit Prakash Shukla
  0 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-06-30  5:54 UTC (permalink / raw)
  To: Anatoly Burakov, bruce.richardson, david.marchand
  Cc: dev, Jerin Jacob Kollanukkaran

Ping.

> -----Original Message-----
> From: Amit Prakash Shukla <amitprakashs@marvell.com>
> Sent: Wednesday, May 25, 2022 4:04 PM
> To: Anatoly Burakov <anatoly.burakov@intel.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> bruce.richardson@intel.com; Amit Prakash Shukla
> <amitprakashs@marvell.com>
> Subject: [PATCH v4 2/2] mem: telemetry support for system memory
> information
> 
> Changes adds telemetry support to display system memory information,
> allocated using calls malloc, calloc, mmap, etc. This patch is based on
> malloc_info. This patch adds following endpoints:
> 
> 1. /sysmem/sys_heap_list
> The commands displays the arenas currently in use.
> Example:
> --> /sysmem/sys_heap_list
> {"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
> 
> 2. /sysmem/sys_heap_info,<arena-id>
> This command displays the information about arena.
> Example:
> --> /sysmem/sys_heap_info,0
> {"/sysmem/sys_heap_info": {"Arena_id": 0, "Allocated_size": 2069934, \
>  "Free_count": 4, "Free_size": 223826, "Curr_size": 2293760,         \
>  "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                   \
>  "Heap_size": 2293760}}
> --> /sysmem/sys_heap_info,6
> {"/sysmem/sys_heap_info": {"Arena_id": 6, "Allocated_size": 3136, \
>  "Free_count": 2, "Free_size": 193472, "Curr_size": 196608,       \
>  "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 1,                \
>  "Heap_size": 196608}}
> 
> The last arena-id in the list gives total of all arenas.
> 
> --> /sysmem/sys_heap_info,10
> {"/sysmem/sys_heap_info": {"Arena_id": 10, "Allocated_size": 2107774, \
>  "Free_count": 20, "Free_size": 1955458, "Curr_size": 4063232,        \
>  "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                    \
>  "Heap_size": 4063232}}
> 
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
>  lib/eal/common/eal_common_memory.c | 330
> +++++++++++++++++++++++++++++
>  1 file changed, 330 insertions(+)
> 
> diff --git a/lib/eal/common/eal_common_memory.c
> b/lib/eal/common/eal_common_memory.c
> index e66de6a872..a1677082c1 100644
> --- a/lib/eal/common/eal_common_memory.c
> +++ b/lib/eal/common/eal_common_memory.c
> @@ -8,6 +8,9 @@
>  #include <stdlib.h>
>  #include <string.h>
>  #include <inttypes.h>
> +#ifdef RTE_EXEC_ENV_LINUX
> +#include <malloc.h>
> +#endif
> 
>  #include <rte_fbarray.h>
>  #include <rte_memory.h>
> @@ -1123,6 +1126,12 @@ rte_eal_memory_init(void)
>  #define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
>  #define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
>  #define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
> +
> +#ifdef RTE_EXEC_ENV_LINUX
> +#define SYSMEMORY_LIST_REQ		"/sysmem/sys_heap_list"
> +#define SYSMEMORY_INFO_REQ		"/sysmem/sys_heap_info"
> +#endif
> +
>  #define ADDR_STR			15
> 
> 
> @@ -1720,6 +1729,318 @@ handle_eal_element_info_request(const char
> *cmd __rte_unused,
>  	return 0;
>  }
> 
> +#ifdef RTE_EXEC_ENV_LINUX
> +#define MAX_SYS_MEM_ARENAS	128
> +#define MAX_TAG_CHAR		128
> +
> +/* Memory size are in bytes. */
> +struct mem_stats {
> +	uint64_t fast_count; /* Number of free blocks in fast bin. */
> +	uint64_t fast_size;  /* Size in bytes of free blocks in fast bin. */
> +	uint64_t rest_count; /* Number of free blocks in bin. */
> +	uint64_t rest_size;  /* Size in bytes of free blocks in bin. */
> +	uint64_t mmap_count; /* Number of mmap blocks. */
> +	uint64_t mmap_size;  /* Size in bytes of mmap'd memory. */
> +	uint64_t curr_size;  /* Size in bytes allocated by system. */
> +	uint64_t heap_size;  /* Heap size in bytes. */
> +	uint64_t heap_count; /* Number of heaps. */ };
> +
> +struct rte_heap_mem_stats {
> +	unsigned int num_active_arena;
> +	struct mem_stats stats[MAX_SYS_MEM_ARENAS]; };
> +
> +/* This function shall be called to parse only attributes.
> + * Parsing of the "tags" shall be done by the caller.
> + */
> +static int
> +parse_attr(char *buf, uint32_t *i, char *attr, const char *key) {
> +	int j = 0;
> +	int keymatch = 0;
> +
> +	attr[j] = '\0';
> +
> +	while ((buf[*i] != '>') && (j < MAX_TAG_CHAR)) {
> +		/* Ignore spaces. */
> +		if (buf[*i] == ' ') {
> +			attr[j] = '\0';
> +			j = 0;
> +			(*i)++;
> +			continue;
> +		}
> +
> +		/* Attribute key */
> +		if (buf[*i] == '=') {
> +			attr[j] = '\0';
> +			j = 0;
> +			(*i)++;
> +
> +			/* If the key is matched, extract the value. */
> +			if (strncmp(attr, key, strlen(key)) != 0)
> +				continue;
> +			else
> +				keymatch = 1;
> +		}
> +
> +		/* Attribute value */
> +		if ((buf[*i] == '"') && (keymatch == 1)) {
> +			j = 0;
> +			(*i)++;
> +
> +			while ((buf[*i] != '"') && (j < MAX_TAG_CHAR))
> +				attr[(j)++] = buf[(*i)++];
> +			attr[j] = '\0';
> +			(*i)++;
> +			return 0;
> +		}
> +
> +		keymatch = 0;
> +		attr[(j)++] = buf[(*i)++];
> +	}
> +
> +	(*i)++;
> +	return -1;
> +}
> +
> +/* Get the system memory stats into buffer by calling malloc_info().
> + * malloc_info() returns the stats in XML format. Parse the XML to
> +extract
> + * number of heaps, size of each heap, free memory in heap.
> + */
> +static int
> +parse_heap_mem_stats(struct rte_heap_mem_stats *heap_stats) {
> +	char tag[MAX_TAG_CHAR] = {0};
> +	int old_mem_index = -1;
> +	int mem_index = -1;
> +	uint32_t i = 0;
> +	uint32_t j = 0;
> +	size_t length;
> +	char *buf;
> +	FILE *fp;
> +	int ret;
> +
> +	/* buf is dynamically allocated by open_memstream. */
> +	fp = open_memstream(&buf, &length);
> +	if (fp == NULL) {
> +		RTE_LOG(DEBUG, EAL, "Error: Failed to open memory
> stream\n");
> +		return -1;
> +	}
> +
> +	/* Gets system memory stat's XML format. */
> +	ret = malloc_info(0, fp);
> +	fclose(fp);
> +
> +	if (ret != 0) {
> +		RTE_LOG(DEBUG, EAL, "Error: malloc_info returned
> error\n");
> +		return -1;
> +	}
> +
> +	while (i < length) {
> +		j = 0;
> +		tag[j] = '\0';
> +
> +		/* Ignore newline and spaces. */
> +		if ((buf[i] == '\n') || (buf[i] == ' ') || (buf[i] == '/') ||
> +		    (buf[i] == '>')) {
> +			i++;
> +			continue;
> +		}
> +
> +		if (buf[i] == '<') {
> +			i++;
> +			while ((buf[i] != ' ') && (buf[i] != '>') &&
> +			       (j < MAX_TAG_CHAR)) {
> +				tag[j++] = buf[i++];
> +			}
> +
> +			if (strncmp(tag, "heap", strlen("heap")) == 0) {
> +				old_mem_index = mem_index++;
> +				if (mem_index >= MAX_SYS_MEM_ARENAS)
> {
> +					RTE_LOG(DEBUG, EAL, "Memory
> arena "
> +						"exceeded max limit: %d",
> +						MAX_SYS_MEM_ARENAS);
> +					goto done;
> +				}
> +				heap_stats->num_active_arena++;
> +			}
> +
> +			continue;
> +		}
> +
> +		if (mem_index < 0) {
> +			i++;
> +			continue;
> +		}
> +
> +		if (parse_attr(buf, &i, tag, "type") < 0)
> +			continue;
> +
> +		if (strncmp(tag, "fast", strlen("fast")) == 0) {
> +			/* For total of all arenas, "heap" tag is not present
> +			 * in xml. Below check is to handle that scenarios.
> +			 *
> +			 * FIXME: mem_index increment shall be
> independent of
> +			 * the tag.
> +			 */
> +			if (old_mem_index == mem_index) {
> +				mem_index++;
> +				if (mem_index >= MAX_SYS_MEM_ARENAS)
> {
> +					RTE_LOG(DEBUG, EAL, "Memory
> arena "
> +						"exceeded max limit: %d\n",
> +						MAX_SYS_MEM_ARENAS);
> +					goto done;
> +				}
> +				heap_stats->num_active_arena++;
> +			}
> +			old_mem_index = mem_index;
> +
> +			if (parse_attr(buf, &i, tag, "count") == 0)
> +				heap_stats->stats[mem_index].fast_count =
> +							strtoul(tag, NULL, 10);
> +			if (parse_attr(buf, &i, tag, "size") == 0)
> +				heap_stats->stats[mem_index].fast_size =
> +							strtoul(tag, NULL, 10);
> +			continue;
> +		}
> +
> +		if (strncmp(tag, "rest", strlen("rest")) == 0) {
> +			if (parse_attr(buf, &i, tag, "count") == 0)
> +				heap_stats->stats[mem_index].rest_count =
> +							strtoul(tag, NULL, 10);
> +			if (parse_attr(buf, &i, tag, "size") == 0)
> +				heap_stats->stats[mem_index].rest_size =
> +							strtoul(tag, NULL, 10);
> +			continue;
> +		}
> +
> +		if (strncmp(tag, "current", strlen("current")) == 0) {
> +			if (parse_attr(buf, &i, tag, "size") == 0)
> +				heap_stats->stats[mem_index].curr_size =
> +							strtoul(tag, NULL, 10);
> +			continue;
> +		}
> +
> +		if (strncmp(tag, "total", strlen("total")) == 0) {
> +			if (parse_attr(buf, &i, tag, "size") == 0)
> +				heap_stats->stats[mem_index].heap_size =
> +							strtoul(tag, NULL, 10);
> +			continue;
> +		}
> +
> +		if (strncmp(tag, "subheaps", strlen("subheaps")) == 0) {
> +			if (parse_attr(buf, &i, tag, "size") == 0)
> +				heap_stats->stats[mem_index].heap_count
> =
> +							strtoul(tag, NULL, 10);
> +			continue;
> +		}
> +
> +		if (strncmp(tag, "mmap", strlen("mmap")) == 0) {
> +			if (parse_attr(buf, &i, tag, "count") == 0)
> +				heap_stats-
> >stats[mem_index].mmap_count =
> +							strtoul(tag, NULL, 10);
> +			if (parse_attr(buf, &i, tag, "size") == 0)
> +				heap_stats->stats[mem_index].mmap_size
> =
> +							strtoul(tag, NULL, 10);
> +			continue;
> +		}
> +
> +		i++;
> +	}
> +
> +done:
> +	/* All done! Let's free the buf. */
> +	free(buf);
> +	return 0;
> +}
> +
> +static int
> +handle_sysmem_list_request(const char *cmd __rte_unused,
> +			   const char *params __rte_unused,
> +			   struct rte_tel_data *d)
> +{
> +	struct rte_heap_mem_stats heap_mem_stats;
> +	unsigned int num_arena;
> +	unsigned int i;
> +
> +	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
> +	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
> +		return -1;
> +
> +	/* Note:
> +	 * Total active arenas are (num_active_arena - 1). The last entry in
> +	 * the array is total of all arenas.
> +	 */
> +	num_arena = heap_mem_stats.num_active_arena;
> +
> +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +	for (i = 0; i < num_arena; i++)
> +		rte_tel_data_add_array_int(d, i);
> +
> +	return 0;
> +}
> +
> +static int
> +handle_sysmem_info_request(const char *cmd __rte_unused, const char
> *params,
> +			   struct rte_tel_data *d)
> +{
> +	struct rte_heap_mem_stats heap_mem_stats;
> +	unsigned int arena_id;
> +	uint64_t free_size;
> +	uint64_t free_count;
> +	uint64_t allocated_size;
> +
> +	if (params == NULL || strlen(params) == 0 || !isdigit(*params))
> +		return -1;
> +
> +	arena_id = (unsigned int)strtoul(params, NULL, 10);
> +	if (arena_id > UINT32_MAX)
> +		return -1;
> +
> +	if (arena_id >= MAX_SYS_MEM_ARENAS)
> +		return -1;
> +
> +	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
> +	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
> +		return -1;
> +
> +	if (arena_id >= heap_mem_stats.num_active_arena) {
> +		RTE_LOG(DEBUG, EAL, "Memory arena exceeded max limit:
> %d\n",
> +			MAX_SYS_MEM_ARENAS);
> +		return -1;
> +	}
> +
> +	/* Fast and rest account for the total free memory. */
> +	free_size = heap_mem_stats.stats[arena_id].fast_size +
> +		    heap_mem_stats.stats[arena_id].rest_size;
> +
> +	free_count = heap_mem_stats.stats[arena_id].fast_count +
> +		     heap_mem_stats.stats[arena_id].rest_count;
> +
> +	/* (System memory - free size) = allocated memory size. */
> +	allocated_size = heap_mem_stats.stats[arena_id].curr_size -
> free_size;
> +
> +	rte_tel_data_start_dict(d);
> +	rte_tel_data_add_dict_int(d, "Arena_id", arena_id);
> +	rte_tel_data_add_dict_int(d, "Allocated_size", allocated_size);
> +	rte_tel_data_add_dict_u64(d, "Free_count", free_count);
> +	rte_tel_data_add_dict_u64(d, "Free_size", free_size);
> +	rte_tel_data_add_dict_u64(d, "Curr_size",
> +
> heap_mem_stats.stats[arena_id].curr_size);
> +	rte_tel_data_add_dict_u64(d, "Mmap_count",
> +
> heap_mem_stats.stats[arena_id].mmap_count);
> +	rte_tel_data_add_dict_u64(d, "Mmap_size",
> +
> heap_mem_stats.stats[arena_id].mmap_size);
> +	rte_tel_data_add_dict_u64(d, "Heap_count",
> +
> heap_mem_stats.stats[arena_id].heap_count);
> +	rte_tel_data_add_dict_u64(d, "Heap_size",
> +
> heap_mem_stats.stats[arena_id].heap_size);
> +
> +	return 0;
> +}
> +#endif
> +
>  RTE_INIT(memory_telemetry)
>  {
>  	rte_telemetry_register_cmd(
> @@ -1751,5 +2072,14 @@ RTE_INIT(memory_telemetry)
>  	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
>  			handle_eal_element_info_request,
>  			"Returns element info. Parameters: int heap_id,
> memseg_list_id, memseg_id, start_elem_id, end_elem_id");
> +
> +#ifdef RTE_EXEC_ENV_LINUX
> +	rte_telemetry_register_cmd(SYSMEMORY_LIST_REQ,
> +			handle_sysmem_list_request,
> +			"Returns element information. Takes no
> parameters");
> +	rte_telemetry_register_cmd(SYSMEMORY_INFO_REQ,
> +			handle_sysmem_info_request,
> +			"Returns element information. Parameters: int
> arena_id"); #endif
>  }
>  #endif
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v4 1/2] mem: telemetry support for memseg and element information
  2022-06-30  5:52     ` Amit Prakash Shukla
@ 2022-07-21 11:20       ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-07-21 11:20 UTC (permalink / raw)
  To: Anatoly Burakov, david.marchand, bruce.richardson
  Cc: dev, Jerin Jacob Kollanukkaran

Ping for review or feedback for the updated patch.

Thanks,
Amit Shukla

> -----Original Message-----
> From: Amit Prakash Shukla
> Sent: Thursday, June 30, 2022 11:22 AM
> To: Anatoly Burakov <anatoly.burakov@intel.com>;
> david.marchand@redhat.com; bruce.richardson@intel.com
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>
> Subject: RE: [PATCH v4 1/2] mem: telemetry support for memseg and
> element information
> 
> Ping.
> 
> > -----Original Message-----
> > From: Amit Prakash Shukla <amitprakashs@marvell.com>
> > Sent: Tuesday, June 14, 2022 6:21 PM
> > To: Amit Prakash Shukla <amitprakashs@marvell.com>; Anatoly Burakov
> > <anatoly.burakov@intel.com>
> > Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> > bruce.richardson@intel.com
> > Subject: RE: [PATCH v4 1/2] mem: telemetry support for memseg and
> > element information
> >
> > Ping.
> >
> > > -----Original Message-----
> > > From: Amit Prakash Shukla <amitprakashs@marvell.com>
> > > Sent: Wednesday, May 25, 2022 4:04 PM
> > > To: Anatoly Burakov <anatoly.burakov@intel.com>
> > > Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> > > bruce.richardson@intel.com; Amit Prakash Shukla
> > > <amitprakashs@marvell.com>
> > > Subject: [PATCH v4 1/2] mem: telemetry support for memseg and
> > > element information
> > >
> > > Changes adds telemetry support to display memory occupancy in
> memseg
> > > and the information of the elements allocated from a memseg based on
> > > arguments provided by user. This patch adds following endpoints:
> > >
> > > 1. /eal/memseg_list_array
> > > The command displays the memseg list from which the memory has been
> > > allocated.
> > > Example:
> > > --> /eal/memseg_list_array
> > > {"/eal/memseg_list_array": [0, 1]}
> > >
> > > 2. /eal/memseg_list_info,<memseg-list-id>
> > > The command outputs the memsegs, from which the memory is
> allocated,
> > > for the memseg_list given as input. Command also supports help.
> > > Example:
> > > --> /eal/memseg_list_info,help
> > > {"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}
> > >
> > > --> /eal/memseg_list_info,1
> > > {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
> > > 12, 13, 14, 15]}
> > >
> > > 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> > > The command outputs the memseg information based on the memseg-
> list
> > > and the memseg-id given as input. Command also supports help.
> > > Example:
> > > --> /eal/memseg_info,help
> > > {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>, \
> <memseg-
> > > id>"}
> > >
> > > --> /eal/memseg_info,0,10
> > > {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> > > "Memseg_index": 10, "Memseg_list_len": 64,     \
> > > "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> > > "Size": 536870912}}
> > >
> > > --> /eal/memseg_info,1,15
> > > {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> > > "Memseg_index": 15, "Memseg_list_len": 64,      \
> > > "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> > > "Size": 536870912}}
> > >
> > > 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> > > The command outputs number of elements in a memseg based on the
> > heap-
> > > id, memseg-list-id and memseg-id given as input.
> > > Command also supports help.
> > > Example:
> > > --> /eal/element_list,help
> > > {"/eal/element_list": "/eal/element_list,<heap-id>,  \ <memseg-list-
> > > id>,<memseg-id>"}
> > >
> > > --> /eal/element_list,0,0,63
> > > {"/eal/element_list": {"Element_count": 52}}
> > >
> > > --> /eal/element_list,0,1,15
> > > {"/eal/element_list": {"Element_count": 52}}
> > >
> > > 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> > >    <elem-start-id>,<elem-end-id>
> > > The command outputs element information like element start address,
> > > end address, to which memseg it belongs, element state, element size.
> > > User can give a range of elements to be printed. Command also
> > > supports
> > help.
> > > Example:
> > > --> /eal/element_info,help
> > > {"/eal/element_info": "/eal/element_info,<heap-id>,  \ <memseg-list-
> > > id>,<memseg-id>,<elem-start-id>,<elem-end-id>"}
> > >
> > > --> /eal/element_info,0,1,15,1,2
> > > {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> > > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > > "memseg_end_addr": "0xb40000000",                    \
> > > "element_start_addr": "0xb201fe680",                 \
> > > "element_end_addr": "0xb20bfe700",                   \
> > > "element_size": 10485888, "element_state": "Busy"},  \
> > > "element.2": {"msl_id": 1, "ms_id": 15,              \
> > > "memseg_start_addr": "0xb20000000",                  \
> > > "memseg_end_addr": "0xb40000000",                    \
> > > "element_start_addr": "0xb20bfe700",                 \
> > > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > > "element_state": "Busy"}, "Element_count": 2}}
> > >
> > > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> > > ---
> > > v2:
> > > - Fixed compilation error related int-to-pointer-cast
> > > - Changes for code review suggestions
> > >
> > > v3:
> > > - Commit message changes
> > > - Renaming end-points
> > > - Changing input parameters to comma-seperated
> > > - Reverting telemetry output buffer size
> > >
> > > v4:
> > > - Patch-2 adds telemetry support to display system memory
> > >
> > >  lib/eal/common/eal_common_memory.c | 482
> > > ++++++++++++++++++++++++++++-
> > >  1 file changed, 477 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/lib/eal/common/eal_common_memory.c
> > > b/lib/eal/common/eal_common_memory.c
> > > index 688dc615d7..e66de6a872 100644
> > > --- a/lib/eal/common/eal_common_memory.c
> > > +++ b/lib/eal/common/eal_common_memory.c
> > > @@ -26,6 +26,7 @@
> > >  #include "eal_memcfg.h"
> > >  #include "eal_options.h"
> > >  #include "malloc_heap.h"
> > > +#include "malloc_elem.h"
> > >
> > >  /*
> > >   * Try to mmap *size bytes in /dev/zero. If it is successful,
> > > return the @@ -
> > > 1113,11 +1114,17 @@ rte_eal_memory_init(void)  }
> > >
> > >  #ifndef RTE_EXEC_ENV_WINDOWS
> > > -#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
> > > -#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
> > > -#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
> > > -#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
> > > -#define ADDR_STR		15
> > > +#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
> > > +#define EAL_MEMZONE_INFO_REQ
> > 	"/eal/memzone_info"
> > > +#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
> > > +#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
> > > +#define EAL_MEMSEG_LIST_ARR_REQ
> > > 	"/eal/memseg_list_array"
> > > +#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
> > > +#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
> > > +#define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
> > > +#define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
> > > +#define ADDR_STR			15
> > > +
> > >
> > >  /* Telemetry callback handler to return heap stats for requested
> > > heap id. */ static int @@ -1265,6 +1272,454 @@
> > > handle_eal_memzone_list_request(const char *cmd __rte_unused,
> > >  	return 0;
> > >  }
> > >
> > > +static int
> > > +handle_eal_memseg_list_array_request(const char *cmd
> __rte_unused,
> > > +				     const char *params __rte_unused,
> > > +				     struct rte_tel_data *d)
> > > +{
> > > +	struct rte_mem_config *mcfg;
> > > +	int i;
> > > +
> > > +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> > > +
> > > +	rte_mcfg_mem_read_lock();
> > > +	mcfg = rte_eal_get_configuration()->mem_config;
> > > +
> > > +	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
> > > +		struct rte_memseg_list *msl = &mcfg->memsegs[i];
> > > +		if (msl->memseg_arr.count == 0)
> > > +			continue;
> > > +
> > > +		rte_tel_data_add_array_int(d, i);
> > > +	}
> > > +	rte_mcfg_mem_read_unlock();
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int
> > > +handle_eal_memseg_list_info_request(const char *cmd
> __rte_unused,
> > > +				    const char *params, struct rte_tel_data *d)
> > > {
> > > +	struct rte_mem_config *mcfg;
> > > +	struct rte_memseg_list *msl;
> > > +	struct rte_fbarray *arr;
> > > +	uint32_t ms_list_idx;
> > > +	int ms_idx;
> > > +
> > > +	if (params == NULL || strlen(params) == 0)
> > > +		return -1;
> > > +
> > > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > > +			 "%s,<memseg-list-id>",
> > > EAL_MEMSEG_LIST_INFO_REQ);
> > > +		rte_tel_data_string(d, buff);
> > > +		return 0;
> > > +	}
> > > +
> > > +	if (!isdigit(*params))
> > > +		return -1;
> > > +
> > > +	ms_list_idx = strtoul(params, NULL, 10);
> > > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> > > +		return -1;
> > > +
> > > +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> > > +
> > > +	rte_mcfg_mem_read_lock();
> > > +	mcfg = rte_eal_get_configuration()->mem_config;
> > > +	msl = &mcfg->memsegs[ms_list_idx];
> > > +	if (msl->memseg_arr.count == 0)
> > > +		goto done;
> > > +
> > > +	arr = &msl->memseg_arr;
> > > +
> > > +	ms_idx = rte_fbarray_find_next_used(arr, 0);
> > > +	while (ms_idx >= 0) {
> > > +		rte_tel_data_add_array_int(d, ms_idx);
> > > +		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
> > > +	}
> > > +
> > > +done:
> > > +	rte_mcfg_mem_read_unlock();
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int
> > > +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> > > +			       const char *params, struct rte_tel_data *d) {
> > > +	struct rte_mem_config *mcfg;
> > > +	uint64_t ms_start_addr, ms_end_addr, ms_size;
> > > +	struct rte_memseg_list *msl;
> > > +	const struct rte_memseg *ms;
> > > +	struct rte_fbarray *arr;
> > > +	char addr[ADDR_STR];
> > > +	uint32_t ms_list_idx = 0;
> > > +	uint32_t ms_idx = 0;
> > > +	uint32_t msl_len;
> > > +	char dlim[2] = ",";
> > > +	char *token;
> > > +	char *params_args;
> > > +
> > > +	if (params == NULL || strlen(params) == 0)
> > > +		return -1;
> > > +
> > > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > > +			 "%s,<memseg-list-id>,<memseg-id>",
> > > +			 EAL_MEMSEG_INFO_REQ);
> > > +		rte_tel_data_string(d, buff);
> > > +		return 0;
> > > +	}
> > > +
> > > +	/* strtok expects char * and param is const char *. Hence on using
> > > +	 * params as "const char *" compiler throws warning.
> > > +	 */
> > > +	params_args = strdup(params);
> > > +	token = strtok(params_args, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_list_idx = strtoul(token, NULL, 10);
> > > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	token = strtok(NULL, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +	ms_idx = strtoul(token, NULL, 10);
> > > +
> > > +	free(params_args);
> > > +
> > > +	rte_mcfg_mem_read_lock();
> > > +
> > > +	mcfg = rte_eal_get_configuration()->mem_config;
> > > +	msl = &mcfg->memsegs[ms_list_idx];
> > > +	if (msl->memseg_arr.count == 0) {
> > > +		rte_mcfg_mem_read_unlock();
> > > +		return -1;
> > > +	}
> > > +
> > > +	arr = &msl->memseg_arr;
> > > +	msl_len = arr->len;
> > > +
> > > +	ms = rte_fbarray_get(arr, ms_idx);
> > > +	if (ms == NULL) {
> > > +		rte_mcfg_mem_read_unlock();
> > > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > > memseg.\n");
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_start_addr = ms->addr_64;
> > > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > > +	ms_size = ms->hugepage_sz;
> > > +
> > > +	rte_mcfg_mem_read_unlock();
> > > +
> > > +	rte_tel_data_start_dict(d);
> > > +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> > > +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> > > +	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
> > > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> > > +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> > > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> > > +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> > > +	rte_tel_data_add_dict_int(d, "Size", ms_size);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int
> > > +handle_eal_element_list_request(const char *cmd __rte_unused,
> > > +				const char *params, struct rte_tel_data *d) {
> > > +	struct rte_mem_config *mcfg;
> > > +	struct rte_memseg_list *msl;
> > > +	const struct rte_memseg *ms;
> > > +	struct malloc_elem *elem;
> > > +	struct malloc_heap *heap;
> > > +	uint64_t ms_start_addr, ms_end_addr;
> > > +	uint64_t elem_start_addr, elem_end_addr;
> > > +	uint32_t ms_list_idx = 0;
> > > +	uint32_t heap_id = 0;
> > > +	uint32_t ms_idx = 0;
> > > +	char dlim[2] = ",";
> > > +	int elem_count = 0;
> > > +	char *token;
> > > +	char *params_args;
> > > +
> > > +	if (params == NULL || strlen(params) == 0)
> > > +		return -1;
> > > +
> > > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > > +			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>",
> > > +			 EAL_ELEMENT_LIST_REQ);
> > > +		rte_tel_data_string(d, buff);
> > > +		return 0;
> > > +	}
> > > +
> > > +	/* strtok expects char * and param is const char *. Hence on using
> > > +	 * params as "const char *" compiler throws warning.
> > > +	 */
> > > +	params_args = strdup(params);
> > > +	token = strtok(params_args, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	heap_id = strtoul(token, NULL, 10);
> > > +	if (heap_id >= RTE_MAX_HEAPS) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	token = strtok(NULL, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_list_idx = strtoul(token, NULL, 10);
> > > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	token = strtok(NULL, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_idx = strtoul(token, NULL, 10);
> > > +
> > > +	free(params_args);
> > > +
> > > +	rte_mcfg_mem_read_lock();
> > > +
> > > +	mcfg = rte_eal_get_configuration()->mem_config;
> > > +	msl = &mcfg->memsegs[ms_list_idx];
> > > +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> > > +	if (ms == NULL) {
> > > +		rte_mcfg_mem_read_unlock();
> > > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > > memseg.\n");
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_start_addr = ms->addr_64;
> > > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > > +	rte_mcfg_mem_read_unlock();
> > > +
> > > +	rte_tel_data_start_dict(d);
> > > +
> > > +	heap = &mcfg->malloc_heaps[heap_id];
> > > +	rte_spinlock_lock(&heap->lock);
> > > +
> > > +	elem = heap->first;
> > > +	while (elem) {
> > > +		elem_start_addr = (uint64_t)elem;
> > > +		elem_end_addr =
> > > +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> > > >size);
> > > +
> > > +		if ((uint64_t)elem_start_addr >= ms_start_addr &&
> > > +		    (uint64_t)elem_end_addr <= ms_end_addr)
> > > +			elem_count++;
> > > +		elem = elem->next;
> > > +	}
> > > +
> > > +	rte_spinlock_unlock(&heap->lock);
> > > +
> > > +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int
> > > +handle_eal_element_info_request(const char *cmd __rte_unused,
> > > +				const char *params, struct rte_tel_data *d) {
> > > +	struct rte_mem_config *mcfg;
> > > +	struct rte_memseg_list *msl;
> > > +	const struct rte_memseg *ms;
> > > +	struct malloc_elem *elem;
> > > +	struct malloc_heap *heap;
> > > +	struct rte_tel_data *c;
> > > +	uint64_t ms_start_addr, ms_end_addr;
> > > +	uint64_t elem_start_addr, elem_end_addr;
> > > +	uint32_t ms_list_idx = 0;
> > > +	uint32_t heap_id = 0;
> > > +	uint32_t ms_idx = 0;
> > > +	uint32_t start_elem = 0, end_elem = 0;
> > > +	uint32_t count = 0, elem_count = 0;
> > > +	char dlim[2] = ",";
> > > +	char str[ADDR_STR];
> > > +	char *params_args;
> > > +	char *token;
> > > +
> > > +	if (params == NULL || strlen(params) == 0)
> > > +		return -1;
> > > +
> > > +	if (strncasecmp(params, "help", strlen(params)) == 0) {
> > > +		char buff[RTE_TEL_MAX_SINGLE_STRING_LEN];
> > > +		snprintf(buff, RTE_TEL_MAX_SINGLE_STRING_LEN,
> > > +			 "%s,<heap-id>,<memseg-list-id>,<memseg-id>,"
> > > +			 "<elem-start-id>,<elem-end-id>",
> > > +			 EAL_ELEMENT_INFO_REQ);
> > > +		rte_tel_data_string(d, buff);
> > > +		return 0;
> > > +	}
> > > +
> > > +	/* strtok expects char * and param is const char *. Hence on using
> > > +	 * params as "const char *" compiler throws warning.
> > > +	 */
> > > +	params_args = strdup(params);
> > > +	token = strtok(params_args, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	heap_id = strtoul(token, NULL, 10);
> > > +	if (heap_id >= RTE_MAX_HEAPS) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	token = strtok(NULL, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_list_idx = strtoul(token, NULL, 10);
> > > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	token = strtok(NULL, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_idx = strtoul(token, NULL, 10);
> > > +
> > > +	token = strtok(NULL, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	start_elem = strtoul(token, NULL, 10);
> > > +
> > > +	token = strtok(NULL, dlim);
> > > +	if (token == NULL || !isdigit(*token)) {
> > > +		free(params_args);
> > > +		return -1;
> > > +	}
> > > +
> > > +	end_elem = strtoul(token, NULL, 10);
> > > +
> > > +	free(params_args);
> > > +
> > > +	if (end_elem < start_elem)
> > > +		return -1;
> > > +
> > > +	rte_mcfg_mem_read_lock();
> > > +
> > > +	mcfg = rte_eal_get_configuration()->mem_config;
> > > +	msl = &mcfg->memsegs[ms_list_idx];
> > > +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> > > +	if (ms == NULL) {
> > > +		rte_mcfg_mem_read_unlock();
> > > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > > memseg.\n");
> > > +		return -1;
> > > +	}
> > > +
> > > +	ms_start_addr = ms->addr_64;
> > > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > > +
> > > +	rte_mcfg_mem_read_unlock();
> > > +
> > > +	rte_tel_data_start_dict(d);
> > > +
> > > +	heap = &mcfg->malloc_heaps[heap_id];
> > > +	rte_spinlock_lock(&heap->lock);
> > > +
> > > +	elem = heap->first;
> > > +	while (elem) {
> > > +		elem_start_addr = (uint64_t)elem;
> > > +		elem_end_addr =
> > > +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> > > >size);
> > > +
> > > +		if (elem_start_addr < ms_start_addr ||
> > > +				elem_end_addr > ms_end_addr) {
> > > +			elem = elem->next;
> > > +			continue;
> > > +		}
> > > +
> > > +		if (count < start_elem) {
> > > +			elem = elem->next;
> > > +			count++;
> > > +			continue;
> > > +		}
> > > +
> > > +		c = rte_tel_data_alloc();
> > > +		if (c == NULL)
> > > +			break;
> > > +
> > > +		rte_tel_data_start_dict(c);
> > > +		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
> > > +		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
> > > +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> > > +		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
> > > +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> > > +		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
> > > +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
> > > +		rte_tel_data_add_dict_string(c, "element_start_addr", str);
> > > +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
> > > +		rte_tel_data_add_dict_string(c, "element_end_addr", str);
> > > +		rte_tel_data_add_dict_int(c, "element_size", elem->size);
> > > +		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
> > > +			 elem->state == 1 ? "Busy" : elem->state == 2 ?
> > > +			 "Pad" : "Error");
> > > +		rte_tel_data_add_dict_string(c, "element_state", str);
> > > +
> > > +		snprintf(str, ADDR_STR, "%s.%u", "element", count);
> > > +		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
> > > +			rte_tel_data_free(c);
> > > +			break;
> > > +		}
> > > +
> > > +		elem_count++;
> > > +		count++;
> > > +		if (count > end_elem)
> > > +			break;
> > > +
> > > +		elem = elem->next;
> > > +	}
> > > +
> > > +	rte_spinlock_unlock(&heap->lock);
> > > +
> > > +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  RTE_INIT(memory_telemetry)
> > >  {
> > >  	rte_telemetry_register_cmd(
> > > @@ -1279,5 +1734,22 @@ RTE_INIT(memory_telemetry)
> > >  	rte_telemetry_register_cmd(
> > >  			EAL_HEAP_INFO_REQ,
> > > handle_eal_heap_info_request,
> > >  			"Returns malloc heap stats. Parameters: int
> > heap_id");
> > > +	rte_telemetry_register_cmd(
> > > +			EAL_MEMSEG_LIST_ARR_REQ,
> > > +			handle_eal_memseg_list_array_request,
> > > +			"Returns hugepage list. Takes no parameters");
> > > +	rte_telemetry_register_cmd(
> > > +			EAL_MEMSEG_LIST_INFO_REQ,
> > > +			handle_eal_memseg_list_info_request,
> > > +			"Returns memseg list. Parameters: int
> > > memseg_list_id");
> > > +	rte_telemetry_register_cmd(
> > > +			EAL_MEMSEG_INFO_REQ,
> > > handle_eal_memseg_info_request,
> > > +			"Returns memseg info. Parameter: int
> > > memseg_list_id,int memseg_id");
> > > +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> > > +			handle_eal_element_list_request,
> > > +			"Returns element info. Parameters: int heap_id, int
> > > memseg_list_id, int memseg_id");
> > > +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> > > +			handle_eal_element_info_request,
> > > +			"Returns element info. Parameters: int heap_id,
> > > memseg_list_id,
> > > +memseg_id, start_elem_id, end_elem_id");
> > >  }
> > >  #endif
> > > --
> > > 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v4 2/2] mem: telemetry support for system memory information
  2022-06-30  5:54     ` Amit Prakash Shukla
@ 2022-07-21 11:21       ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-07-21 11:21 UTC (permalink / raw)
  To: Anatoly Burakov, bruce.richardson, david.marchand
  Cc: dev, Jerin Jacob Kollanukkaran

Ping for review or feedback for the patch.

Thanks,
Amit Shukla

> -----Original Message-----
> From: Amit Prakash Shukla
> Sent: Thursday, June 30, 2022 11:24 AM
> To: Anatoly Burakov <anatoly.burakov@intel.com>;
> bruce.richardson@intel.com; david.marchand@redhat.com
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>
> Subject: RE: [PATCH v4 2/2] mem: telemetry support for system memory
> information
> 
> Ping.
> 
> > -----Original Message-----
> > From: Amit Prakash Shukla <amitprakashs@marvell.com>
> > Sent: Wednesday, May 25, 2022 4:04 PM
> > To: Anatoly Burakov <anatoly.burakov@intel.com>
> > Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> > bruce.richardson@intel.com; Amit Prakash Shukla
> > <amitprakashs@marvell.com>
> > Subject: [PATCH v4 2/2] mem: telemetry support for system memory
> > information
> >
> > Changes adds telemetry support to display system memory information,
> > allocated using calls malloc, calloc, mmap, etc. This patch is based
> > on malloc_info. This patch adds following endpoints:
> >
> > 1. /sysmem/sys_heap_list
> > The commands displays the arenas currently in use.
> > Example:
> > --> /sysmem/sys_heap_list
> > {"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
> >
> > 2. /sysmem/sys_heap_info,<arena-id>
> > This command displays the information about arena.
> > Example:
> > --> /sysmem/sys_heap_info,0
> > {"/sysmem/sys_heap_info": {"Arena_id": 0, "Allocated_size": 2069934, \
> >  "Free_count": 4, "Free_size": 223826, "Curr_size": 2293760,         \
> >  "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                   \
> >  "Heap_size": 2293760}}
> > --> /sysmem/sys_heap_info,6
> > {"/sysmem/sys_heap_info": {"Arena_id": 6, "Allocated_size": 3136, \
> >  "Free_count": 2, "Free_size": 193472, "Curr_size": 196608,       \
> >  "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 1,                \
> >  "Heap_size": 196608}}
> >
> > The last arena-id in the list gives total of all arenas.
> >
> > --> /sysmem/sys_heap_info,10
> > {"/sysmem/sys_heap_info": {"Arena_id": 10, "Allocated_size": 2107774, \
> >  "Free_count": 20, "Free_size": 1955458, "Curr_size": 4063232,        \
> >  "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                    \
> >  "Heap_size": 4063232}}
> >
> > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> > ---
> >  lib/eal/common/eal_common_memory.c | 330
> > +++++++++++++++++++++++++++++
> >  1 file changed, 330 insertions(+)
> >
> > diff --git a/lib/eal/common/eal_common_memory.c
> > b/lib/eal/common/eal_common_memory.c
> > index e66de6a872..a1677082c1 100644
> > --- a/lib/eal/common/eal_common_memory.c
> > +++ b/lib/eal/common/eal_common_memory.c
> > @@ -8,6 +8,9 @@
> >  #include <stdlib.h>
> >  #include <string.h>
> >  #include <inttypes.h>
> > +#ifdef RTE_EXEC_ENV_LINUX
> > +#include <malloc.h>
> > +#endif
> >
> >  #include <rte_fbarray.h>
> >  #include <rte_memory.h>
> > @@ -1123,6 +1126,12 @@ rte_eal_memory_init(void)
> >  #define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
> >  #define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
> >  #define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
> > +
> > +#ifdef RTE_EXEC_ENV_LINUX
> > +#define SYSMEMORY_LIST_REQ		"/sysmem/sys_heap_list"
> > +#define SYSMEMORY_INFO_REQ		"/sysmem/sys_heap_info"
> > +#endif
> > +
> >  #define ADDR_STR			15
> >
> >
> > @@ -1720,6 +1729,318 @@ handle_eal_element_info_request(const char
> > *cmd __rte_unused,
> >  	return 0;
> >  }
> >
> > +#ifdef RTE_EXEC_ENV_LINUX
> > +#define MAX_SYS_MEM_ARENAS	128
> > +#define MAX_TAG_CHAR		128
> > +
> > +/* Memory size are in bytes. */
> > +struct mem_stats {
> > +	uint64_t fast_count; /* Number of free blocks in fast bin. */
> > +	uint64_t fast_size;  /* Size in bytes of free blocks in fast bin. */
> > +	uint64_t rest_count; /* Number of free blocks in bin. */
> > +	uint64_t rest_size;  /* Size in bytes of free blocks in bin. */
> > +	uint64_t mmap_count; /* Number of mmap blocks. */
> > +	uint64_t mmap_size;  /* Size in bytes of mmap'd memory. */
> > +	uint64_t curr_size;  /* Size in bytes allocated by system. */
> > +	uint64_t heap_size;  /* Heap size in bytes. */
> > +	uint64_t heap_count; /* Number of heaps. */ };
> > +
> > +struct rte_heap_mem_stats {
> > +	unsigned int num_active_arena;
> > +	struct mem_stats stats[MAX_SYS_MEM_ARENAS]; };
> > +
> > +/* This function shall be called to parse only attributes.
> > + * Parsing of the "tags" shall be done by the caller.
> > + */
> > +static int
> > +parse_attr(char *buf, uint32_t *i, char *attr, const char *key) {
> > +	int j = 0;
> > +	int keymatch = 0;
> > +
> > +	attr[j] = '\0';
> > +
> > +	while ((buf[*i] != '>') && (j < MAX_TAG_CHAR)) {
> > +		/* Ignore spaces. */
> > +		if (buf[*i] == ' ') {
> > +			attr[j] = '\0';
> > +			j = 0;
> > +			(*i)++;
> > +			continue;
> > +		}
> > +
> > +		/* Attribute key */
> > +		if (buf[*i] == '=') {
> > +			attr[j] = '\0';
> > +			j = 0;
> > +			(*i)++;
> > +
> > +			/* If the key is matched, extract the value. */
> > +			if (strncmp(attr, key, strlen(key)) != 0)
> > +				continue;
> > +			else
> > +				keymatch = 1;
> > +		}
> > +
> > +		/* Attribute value */
> > +		if ((buf[*i] == '"') && (keymatch == 1)) {
> > +			j = 0;
> > +			(*i)++;
> > +
> > +			while ((buf[*i] != '"') && (j < MAX_TAG_CHAR))
> > +				attr[(j)++] = buf[(*i)++];
> > +			attr[j] = '\0';
> > +			(*i)++;
> > +			return 0;
> > +		}
> > +
> > +		keymatch = 0;
> > +		attr[(j)++] = buf[(*i)++];
> > +	}
> > +
> > +	(*i)++;
> > +	return -1;
> > +}
> > +
> > +/* Get the system memory stats into buffer by calling malloc_info().
> > + * malloc_info() returns the stats in XML format. Parse the XML to
> > +extract
> > + * number of heaps, size of each heap, free memory in heap.
> > + */
> > +static int
> > +parse_heap_mem_stats(struct rte_heap_mem_stats *heap_stats) {
> > +	char tag[MAX_TAG_CHAR] = {0};
> > +	int old_mem_index = -1;
> > +	int mem_index = -1;
> > +	uint32_t i = 0;
> > +	uint32_t j = 0;
> > +	size_t length;
> > +	char *buf;
> > +	FILE *fp;
> > +	int ret;
> > +
> > +	/* buf is dynamically allocated by open_memstream. */
> > +	fp = open_memstream(&buf, &length);
> > +	if (fp == NULL) {
> > +		RTE_LOG(DEBUG, EAL, "Error: Failed to open memory
> > stream\n");
> > +		return -1;
> > +	}
> > +
> > +	/* Gets system memory stat's XML format. */
> > +	ret = malloc_info(0, fp);
> > +	fclose(fp);
> > +
> > +	if (ret != 0) {
> > +		RTE_LOG(DEBUG, EAL, "Error: malloc_info returned
> > error\n");
> > +		return -1;
> > +	}
> > +
> > +	while (i < length) {
> > +		j = 0;
> > +		tag[j] = '\0';
> > +
> > +		/* Ignore newline and spaces. */
> > +		if ((buf[i] == '\n') || (buf[i] == ' ') || (buf[i] == '/') ||
> > +		    (buf[i] == '>')) {
> > +			i++;
> > +			continue;
> > +		}
> > +
> > +		if (buf[i] == '<') {
> > +			i++;
> > +			while ((buf[i] != ' ') && (buf[i] != '>') &&
> > +			       (j < MAX_TAG_CHAR)) {
> > +				tag[j++] = buf[i++];
> > +			}
> > +
> > +			if (strncmp(tag, "heap", strlen("heap")) == 0) {
> > +				old_mem_index = mem_index++;
> > +				if (mem_index >= MAX_SYS_MEM_ARENAS)
> > {
> > +					RTE_LOG(DEBUG, EAL, "Memory
> > arena "
> > +						"exceeded max limit: %d",
> > +						MAX_SYS_MEM_ARENAS);
> > +					goto done;
> > +				}
> > +				heap_stats->num_active_arena++;
> > +			}
> > +
> > +			continue;
> > +		}
> > +
> > +		if (mem_index < 0) {
> > +			i++;
> > +			continue;
> > +		}
> > +
> > +		if (parse_attr(buf, &i, tag, "type") < 0)
> > +			continue;
> > +
> > +		if (strncmp(tag, "fast", strlen("fast")) == 0) {
> > +			/* For total of all arenas, "heap" tag is not present
> > +			 * in xml. Below check is to handle that scenarios.
> > +			 *
> > +			 * FIXME: mem_index increment shall be
> > independent of
> > +			 * the tag.
> > +			 */
> > +			if (old_mem_index == mem_index) {
> > +				mem_index++;
> > +				if (mem_index >= MAX_SYS_MEM_ARENAS)
> > {
> > +					RTE_LOG(DEBUG, EAL, "Memory
> > arena "
> > +						"exceeded max limit: %d\n",
> > +						MAX_SYS_MEM_ARENAS);
> > +					goto done;
> > +				}
> > +				heap_stats->num_active_arena++;
> > +			}
> > +			old_mem_index = mem_index;
> > +
> > +			if (parse_attr(buf, &i, tag, "count") == 0)
> > +				heap_stats->stats[mem_index].fast_count =
> > +							strtoul(tag, NULL, 10);
> > +			if (parse_attr(buf, &i, tag, "size") == 0)
> > +				heap_stats->stats[mem_index].fast_size =
> > +							strtoul(tag, NULL, 10);
> > +			continue;
> > +		}
> > +
> > +		if (strncmp(tag, "rest", strlen("rest")) == 0) {
> > +			if (parse_attr(buf, &i, tag, "count") == 0)
> > +				heap_stats->stats[mem_index].rest_count =
> > +							strtoul(tag, NULL, 10);
> > +			if (parse_attr(buf, &i, tag, "size") == 0)
> > +				heap_stats->stats[mem_index].rest_size =
> > +							strtoul(tag, NULL, 10);
> > +			continue;
> > +		}
> > +
> > +		if (strncmp(tag, "current", strlen("current")) == 0) {
> > +			if (parse_attr(buf, &i, tag, "size") == 0)
> > +				heap_stats->stats[mem_index].curr_size =
> > +							strtoul(tag, NULL, 10);
> > +			continue;
> > +		}
> > +
> > +		if (strncmp(tag, "total", strlen("total")) == 0) {
> > +			if (parse_attr(buf, &i, tag, "size") == 0)
> > +				heap_stats->stats[mem_index].heap_size =
> > +							strtoul(tag, NULL, 10);
> > +			continue;
> > +		}
> > +
> > +		if (strncmp(tag, "subheaps", strlen("subheaps")) == 0) {
> > +			if (parse_attr(buf, &i, tag, "size") == 0)
> > +				heap_stats->stats[mem_index].heap_count
> > =
> > +							strtoul(tag, NULL, 10);
> > +			continue;
> > +		}
> > +
> > +		if (strncmp(tag, "mmap", strlen("mmap")) == 0) {
> > +			if (parse_attr(buf, &i, tag, "count") == 0)
> > +				heap_stats-
> > >stats[mem_index].mmap_count =
> > +							strtoul(tag, NULL, 10);
> > +			if (parse_attr(buf, &i, tag, "size") == 0)
> > +				heap_stats->stats[mem_index].mmap_size
> > =
> > +							strtoul(tag, NULL, 10);
> > +			continue;
> > +		}
> > +
> > +		i++;
> > +	}
> > +
> > +done:
> > +	/* All done! Let's free the buf. */
> > +	free(buf);
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_sysmem_list_request(const char *cmd __rte_unused,
> > +			   const char *params __rte_unused,
> > +			   struct rte_tel_data *d)
> > +{
> > +	struct rte_heap_mem_stats heap_mem_stats;
> > +	unsigned int num_arena;
> > +	unsigned int i;
> > +
> > +	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
> > +	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
> > +		return -1;
> > +
> > +	/* Note:
> > +	 * Total active arenas are (num_active_arena - 1). The last entry in
> > +	 * the array is total of all arenas.
> > +	 */
> > +	num_arena = heap_mem_stats.num_active_arena;
> > +
> > +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> > +	for (i = 0; i < num_arena; i++)
> > +		rte_tel_data_add_array_int(d, i);
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_sysmem_info_request(const char *cmd __rte_unused, const
> char
> > *params,
> > +			   struct rte_tel_data *d)
> > +{
> > +	struct rte_heap_mem_stats heap_mem_stats;
> > +	unsigned int arena_id;
> > +	uint64_t free_size;
> > +	uint64_t free_count;
> > +	uint64_t allocated_size;
> > +
> > +	if (params == NULL || strlen(params) == 0 || !isdigit(*params))
> > +		return -1;
> > +
> > +	arena_id = (unsigned int)strtoul(params, NULL, 10);
> > +	if (arena_id > UINT32_MAX)
> > +		return -1;
> > +
> > +	if (arena_id >= MAX_SYS_MEM_ARENAS)
> > +		return -1;
> > +
> > +	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
> > +	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
> > +		return -1;
> > +
> > +	if (arena_id >= heap_mem_stats.num_active_arena) {
> > +		RTE_LOG(DEBUG, EAL, "Memory arena exceeded max limit:
> > %d\n",
> > +			MAX_SYS_MEM_ARENAS);
> > +		return -1;
> > +	}
> > +
> > +	/* Fast and rest account for the total free memory. */
> > +	free_size = heap_mem_stats.stats[arena_id].fast_size +
> > +		    heap_mem_stats.stats[arena_id].rest_size;
> > +
> > +	free_count = heap_mem_stats.stats[arena_id].fast_count +
> > +		     heap_mem_stats.stats[arena_id].rest_count;
> > +
> > +	/* (System memory - free size) = allocated memory size. */
> > +	allocated_size = heap_mem_stats.stats[arena_id].curr_size -
> > free_size;
> > +
> > +	rte_tel_data_start_dict(d);
> > +	rte_tel_data_add_dict_int(d, "Arena_id", arena_id);
> > +	rte_tel_data_add_dict_int(d, "Allocated_size", allocated_size);
> > +	rte_tel_data_add_dict_u64(d, "Free_count", free_count);
> > +	rte_tel_data_add_dict_u64(d, "Free_size", free_size);
> > +	rte_tel_data_add_dict_u64(d, "Curr_size",
> > +
> > heap_mem_stats.stats[arena_id].curr_size);
> > +	rte_tel_data_add_dict_u64(d, "Mmap_count",
> > +
> > heap_mem_stats.stats[arena_id].mmap_count);
> > +	rte_tel_data_add_dict_u64(d, "Mmap_size",
> > +
> > heap_mem_stats.stats[arena_id].mmap_size);
> > +	rte_tel_data_add_dict_u64(d, "Heap_count",
> > +
> > heap_mem_stats.stats[arena_id].heap_count);
> > +	rte_tel_data_add_dict_u64(d, "Heap_size",
> > +
> > heap_mem_stats.stats[arena_id].heap_size);
> > +
> > +	return 0;
> > +}
> > +#endif
> > +
> >  RTE_INIT(memory_telemetry)
> >  {
> >  	rte_telemetry_register_cmd(
> > @@ -1751,5 +2072,14 @@ RTE_INIT(memory_telemetry)
> >  	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> >  			handle_eal_element_info_request,
> >  			"Returns element info. Parameters: int heap_id,
> memseg_list_id,
> > memseg_id, start_elem_id, end_elem_id");
> > +
> > +#ifdef RTE_EXEC_ENV_LINUX
> > +	rte_telemetry_register_cmd(SYSMEMORY_LIST_REQ,
> > +			handle_sysmem_list_request,
> > +			"Returns element information. Takes no
> > parameters");
> > +	rte_telemetry_register_cmd(SYSMEMORY_INFO_REQ,
> > +			handle_sysmem_info_request,
> > +			"Returns element information. Parameters: int
> > arena_id"); #endif
> >  }
> >  #endif
> > --
> > 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v4 1/2] mem: telemetry support for memseg and element information
  2022-05-25 10:33 ` [PATCH v4 1/2] " Amit Prakash Shukla
  2022-05-25 10:33   ` [PATCH v4 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
  2022-06-14 12:50   ` [PATCH v4 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
@ 2022-09-29  8:29   ` David Marchand
  2022-09-29 11:30     ` [EXT] " Amit Prakash Shukla
  2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
  3 siblings, 1 reply; 42+ messages in thread
From: David Marchand @ 2022-09-29  8:29 UTC (permalink / raw)
  To: Amit Prakash Shukla, Anatoly Burakov, bruce.richardson,
	Ciara Power, Dmitry Kozlyuk
  Cc: dev, jerinj

Added more people involved in the dpdk mem allocator, and telemetry.

On Wed, May 25, 2022 at 12:34 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> Changes adds telemetry support to display memory occupancy
> in memseg and the information of the elements allocated from
> a memseg based on arguments provided by user. This patch
> adds following endpoints:
>
> 1. /eal/memseg_list_array
> The command displays the memseg list from which the memory
> has been allocated.
> Example:
> --> /eal/memseg_list_array
> {"/eal/memseg_list_array": [0, 1]}
>
> 2. /eal/memseg_list_info,<memseg-list-id>
> The command outputs the memsegs, from which the memory is
> allocated, for the memseg_list given as input. Command also
> supports help.
> Example:
> --> /eal/memseg_list_info,help
> {"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}

We already have something using the top level /help command.
This proposed addition does not add much info.

--> /help,/eal/memseg_list_info
{"/help": {"/eal/memseg_list_info": "Returns memseg list. Parameters:
int memseg_list_id"}}
--> /eal/memseg_list_info,help
{"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}

Please, remove it.


I think this series is useful though I did not enter into detail.
If nobody has objection, I will merge it once the above comment is handled.


>
> --> /eal/memseg_list_info,1
> {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
>  12, 13, 14, 15]}
>
> 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> The command outputs the memseg information based on the
> memseg-list and the memseg-id given as input. Command also
> supports help.
> Example:
> --> /eal/memseg_info,help
> {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>, \
> <memseg-id>"}
>
> --> /eal/memseg_info,0,10
> {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> "Memseg_index": 10, "Memseg_list_len": 64,     \
> "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> "Size": 536870912}}
>
> --> /eal/memseg_info,1,15
> {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> "Memseg_index": 15, "Memseg_list_len": 64,      \
> "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> "Size": 536870912}}
>
> 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based
> on the heap-id, memseg-list-id and memseg-id given as input.
> Command also supports help.
> Example:
> --> /eal/element_list,help
> {"/eal/element_list": "/eal/element_list,<heap-id>,  \
> <memseg-list-id>,<memseg-id>"}
>
> --> /eal/element_list,0,0,63
> {"/eal/element_list": {"Element_count": 52}}
>
> --> /eal/element_list,0,1,15
> {"/eal/element_list": {"Element_count": 52}}
>
> 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>    <elem-start-id>,<elem-end-id>
> The command outputs element information like element start
> address, end address, to which memseg it belongs, element
> state, element size. User can give a range of elements to be
> printed. Command also supports help.
> Example:
> --> /eal/element_info,help
> {"/eal/element_info": "/eal/element_info,<heap-id>,  \
> <memseg-list-id>,<memseg-id>,<elem-start-id>,<elem-end-id>"}
>
> --> /eal/element_info,0,1,15,1,2
> {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb201fe680",                 \
> "element_end_addr": "0xb20bfe700",                   \
> "element_size": 10485888, "element_state": "Busy"},  \
> "element.2": {"msl_id": 1, "ms_id": 15,              \
> "memseg_start_addr": "0xb20000000",                  \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb20bfe700",                 \
> "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> "element_state": "Busy"}, "Element_count": 2}}
>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>


-- 
David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v4 1/2] mem: telemetry support for memseg and element information
  2022-09-29  8:29   ` David Marchand
@ 2022-09-29 11:30     ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-09-29 11:30 UTC (permalink / raw)
  To: David Marchand, Anatoly Burakov, bruce.richardson, Ciara Power,
	Dmitry Kozlyuk
  Cc: dev, Jerin Jacob Kollanukkaran

Hi David,

Thanks for the feedback. I will do the suggested changes in next version of the patch.

-Amit Shukla

> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Thursday, September 29, 2022 2:00 PM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>; Anatoly Burakov
> <anatoly.burakov@intel.com>; bruce.richardson@intel.com; Ciara Power
> <ciara.power@intel.com>; Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>
> Subject: [EXT] Re: [PATCH v4 1/2] mem: telemetry support for memseg and
> element information
> 
> External Email
> 
> ----------------------------------------------------------------------
> Added more people involved in the dpdk mem allocator, and telemetry.
> 
> On Wed, May 25, 2022 at 12:34 PM Amit Prakash Shukla
> <amitprakashs@marvell.com> wrote:
> >
> > Changes adds telemetry support to display memory occupancy in memseg
> > and the information of the elements allocated from a memseg based on
> > arguments provided by user. This patch adds following endpoints:
> >
> > 1. /eal/memseg_list_array
> > The command displays the memseg list from which the memory has been
> > allocated.
> > Example:
> > --> /eal/memseg_list_array
> > {"/eal/memseg_list_array": [0, 1]}
> >
> > 2. /eal/memseg_list_info,<memseg-list-id>
> > The command outputs the memsegs, from which the memory is allocated,
> > for the memseg_list given as input. Command also supports help.
> > Example:
> > --> /eal/memseg_list_info,help
> > {"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}
> 
> We already have something using the top level /help command.
> This proposed addition does not add much info.
> 
> --> /help,/eal/memseg_list_info
> {"/help": {"/eal/memseg_list_info": "Returns memseg list. Parameters:
> int memseg_list_id"}}
> --> /eal/memseg_list_info,help
> {"/eal/memseg_list_info": "/eal/memseg_list_info,<memseg-list-id>"}
> 
> Please, remove it.
> 
> 
> I think this series is useful though I did not enter into detail.
> If nobody has objection, I will merge it once the above comment is handled.
> 
> 
> >
> > --> /eal/memseg_list_info,1
> > {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
> > 12, 13, 14, 15]}
> >
> > 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> > The command outputs the memseg information based on the memseg-list
> > and the memseg-id given as input. Command also supports help.
> > Example:
> > --> /eal/memseg_info,help
> > {"/eal/memseg_info": "/eal/memseg_info,<memseg-list-id>, \
> > <memseg-id>"}
> >
> > --> /eal/memseg_info,0,10
> > {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> > "Memseg_index": 10, "Memseg_list_len": 64,     \
> > "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> > "Size": 536870912}}
> >
> > --> /eal/memseg_info,1,15
> > {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> > "Memseg_index": 15, "Memseg_list_len": 64,      \
> > "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> > "Size": 536870912}}
> >
> > 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> > The command outputs number of elements in a memseg based on the
> > heap-id, memseg-list-id and memseg-id given as input.
> > Command also supports help.
> > Example:
> > --> /eal/element_list,help
> > {"/eal/element_list": "/eal/element_list,<heap-id>,  \
> > <memseg-list-id>,<memseg-id>"}
> >
> > --> /eal/element_list,0,0,63
> > {"/eal/element_list": {"Element_count": 52}}
> >
> > --> /eal/element_list,0,1,15
> > {"/eal/element_list": {"Element_count": 52}}
> >
> > 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> >    <elem-start-id>,<elem-end-id>
> > The command outputs element information like element start address,
> > end address, to which memseg it belongs, element state, element size.
> > User can give a range of elements to be printed. Command also supports
> > help.
> > Example:
> > --> /eal/element_info,help
> > {"/eal/element_info": "/eal/element_info,<heap-id>,  \
> > <memseg-list-id>,<memseg-id>,<elem-start-id>,<elem-end-id>"}
> >
> > --> /eal/element_info,0,1,15,1,2
> > {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb201fe680",                 \
> > "element_end_addr": "0xb20bfe700",                   \
> > "element_size": 10485888, "element_state": "Busy"},  \
> > "element.2": {"msl_id": 1, "ms_id": 15,              \
> > "memseg_start_addr": "0xb20000000",                  \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb20bfe700",                 \
> > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > "element_state": "Busy"}, "Element_count": 2}}
> >
> > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> 
> 
> --
> David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-05-25 10:33 ` [PATCH v4 1/2] " Amit Prakash Shukla
                     ` (2 preceding siblings ...)
  2022-09-29  8:29   ` David Marchand
@ 2022-09-29 11:43   ` Amit Prakash Shukla
  2022-09-29 11:43     ` [PATCH v5 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
                       ` (4 more replies)
  3 siblings, 5 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-09-29 11:43 UTC (permalink / raw)
  To: Anatoly Burakov
  Cc: dev, jerinj, david.marchand, bruce.richardson, ciara.power,
	dmitry.kozliuk, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/memseg_list_array
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/memseg_list_array
{"/eal/memseg_list_array": [0, 1]}

2. /eal/memseg_list_info,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input.
Example:
--> /eal/memseg_list_info,1
{"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
 12, 13, 14, 15]}

3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input.
Example:
--> /eal/memseg_info,0,10
{"/eal/memseg_info": {"Memseg_list_index": 0,  \
"Memseg_index": 10, "Memseg_list_len": 64,     \
"Start_addr": "0x260000000", "End_addr": "0x280000000",  \
"Size": 536870912}}

--> /eal/memseg_info,1,15
{"/eal/memseg_info": {"Memseg_list_index": 1,   \
"Memseg_index": 15, "Memseg_list_len": 64,      \
"Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
"Size": 536870912}}

4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Example:
--> /eal/element_list,0,0,63
{"/eal/element_list": {"Element_count": 52}}

--> /eal/element_list,0,1,15
{"/eal/element_list": {"Element_count": 52}}

5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
   <elem-start-id>,<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed.
Example:
--> /eal/element_info,0,1,15,1,2
{"/eal/element_info": {"element.1": {"msl_id": 1,    \
"ms_id": 15, "memseg_start_addr": "0xb20000000",     \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb201fe680",                 \
"element_end_addr": "0xb20bfe700",                   \
"element_size": 10485888, "element_state": "Busy"},  \
"element.2": {"msl_id": 1, "ms_id": 15,              \
"memseg_start_addr": "0xb20000000",                  \
"memseg_end_addr": "0xb40000000",                    \
"element_start_addr": "0xb20bfe700",                 \
"element_end_addr": "0xb215fe780", "element_size": 10485888, \
"element_state": "Busy"}, "Element_count": 2}}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Fixed compilation error related int-to-pointer-cast
- Changes for code review suggestions

v3:
- Commit message changes
- Renaming end-points
- Changing input parameters to comma-seperated
- Reverting telemetry output buffer size

v4:
- Patch-2 adds telemetry support to display system memory

v5:
- Removed command help related changes

 lib/eal/common/eal_common_memory.c | 447 ++++++++++++++++++++++++++++-
 1 file changed, 442 insertions(+), 5 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 688dc615d7..6b863979e9 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -3,6 +3,7 @@
  */
 
 #include <errno.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -26,6 +27,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1113,11 +1115,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_LIST_ARR_REQ		"/eal/memseg_list_array"
+#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1265,6 +1273,418 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+static int
+handle_eal_memseg_list_array_request(const char *cmd __rte_unused,
+				     const char *params __rte_unused,
+				     struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
+				    const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	int ms_idx;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	if (!isdigit(*params))
+		return -1;
+
+	ms_list_idx = strtoul(params, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	uint32_t msl_len;
+	char dlim[2] = ",";
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	msl_len = arr->len;
+
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->hugepage_sz;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_int(d, "Size", ms_size);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	char dlim[2] = ",";
+	int elem_count = 0;
+	char *token;
+	char *params_args;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char dlim[2] = ",";
+	char str[ADDR_STR];
+	char *params_args;
+	char *token;
+
+	if (params == NULL || strlen(params) == 0)
+		return -1;
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	token = strtok(params_args, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	heap_id = strtoul(token, NULL, 10);
+	if (heap_id >= RTE_MAX_HEAPS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_list_idx = strtoul(token, NULL, 10);
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
+		free(params_args);
+		return -1;
+	}
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	ms_idx = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	start_elem = strtoul(token, NULL, 10);
+
+	token = strtok(NULL, dlim);
+	if (token == NULL || !isdigit(*token)) {
+		free(params_args);
+		return -1;
+	}
+
+	end_elem = strtoul(token, NULL, 10);
+
+	free(params_args);
+
+	if (end_elem < start_elem)
+		return -1;
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		rte_tel_data_start_dict(c);
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s.%u", "element", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1279,5 +1699,22 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_ARR_REQ,
+			handle_eal_memseg_list_array_request,
+			"Returns hugepage list. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_INFO_REQ,
+			handle_eal_memseg_list_info_request,
+			"Returns memseg list. Parameters: int memseg_list_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns memseg info. Parameter: int memseg_list_id,int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns element info. Parameters: int heap_id, int memseg_list_id, int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element info. Parameters: int heap_id, memseg_list_id, memseg_id, start_elem_id, end_elem_id");
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v5 2/2] mem: telemetry support for system memory information
  2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
@ 2022-09-29 11:43     ` Amit Prakash Shukla
  2022-10-07 19:46       ` David Marchand
  2022-10-06  7:07     ` [PATCH v5 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-09-29 11:43 UTC (permalink / raw)
  To: Anatoly Burakov
  Cc: dev, jerinj, david.marchand, bruce.richardson, ciara.power,
	dmitry.kozliuk, Amit Prakash Shukla

Changes adds telemetry support to display system memory information,
allocated using calls malloc, calloc, mmap, etc. This patch
is based on malloc_info. This patch adds following endpoints:

1. /sysmem/sys_heap_list
The commands displays the arenas currently in use.
Example:
--> /sysmem/sys_heap_list
{"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

2. /sysmem/sys_heap_info,<arena-id>
This command displays the information about arena.
Example:
--> /sysmem/sys_heap_info,0
{"/sysmem/sys_heap_info": {"Arena_id": 0, "Allocated_size": 2069934, \
 "Free_count": 4, "Free_size": 223826, "Curr_size": 2293760,         \
 "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                   \
 "Heap_size": 2293760}}
--> /sysmem/sys_heap_info,6
{"/sysmem/sys_heap_info": {"Arena_id": 6, "Allocated_size": 3136, \
 "Free_count": 2, "Free_size": 193472, "Curr_size": 196608,       \
 "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 1,                \
 "Heap_size": 196608}}

The last arena-id in the list gives total of all arenas.

--> /sysmem/sys_heap_info,10
{"/sysmem/sys_heap_info": {"Arena_id": 10, "Allocated_size": 2107774, \
 "Free_count": 20, "Free_size": 1955458, "Curr_size": 4063232,        \
 "Mmap_count": 0, "Mmap_size": 0, "Heap_count": 0,                    \
 "Heap_size": 4063232}}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
 lib/eal/common/eal_common_memory.c | 330 +++++++++++++++++++++++++++++
 1 file changed, 330 insertions(+)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 6b863979e9..b5326119f0 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -9,6 +9,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <inttypes.h>
+#ifdef RTE_EXEC_ENV_LINUX
+#include <malloc.h>
+#endif
 
 #include <rte_fbarray.h>
 #include <rte_memory.h>
@@ -1124,6 +1127,12 @@ rte_eal_memory_init(void)
 #define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
 #define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
 #define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
+
+#ifdef RTE_EXEC_ENV_LINUX
+#define SYSMEMORY_LIST_REQ		"/sysmem/sys_heap_list"
+#define SYSMEMORY_INFO_REQ		"/sysmem/sys_heap_info"
+#endif
+
 #define ADDR_STR			15
 
 
@@ -1685,6 +1694,318 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+#ifdef RTE_EXEC_ENV_LINUX
+#define MAX_SYS_MEM_ARENAS	128
+#define MAX_TAG_CHAR		128
+
+/* Memory size are in bytes. */
+struct mem_stats {
+	uint64_t fast_count; /* Number of free blocks in fast bin. */
+	uint64_t fast_size;  /* Size in bytes of free blocks in fast bin. */
+	uint64_t rest_count; /* Number of free blocks in bin. */
+	uint64_t rest_size;  /* Size in bytes of free blocks in bin. */
+	uint64_t mmap_count; /* Number of mmap blocks. */
+	uint64_t mmap_size;  /* Size in bytes of mmap'd memory. */
+	uint64_t curr_size;  /* Size in bytes allocated by system. */
+	uint64_t heap_size;  /* Heap size in bytes. */
+	uint64_t heap_count; /* Number of heaps. */
+};
+
+struct rte_heap_mem_stats {
+	unsigned int num_active_arena;
+	struct mem_stats stats[MAX_SYS_MEM_ARENAS];
+};
+
+/* This function shall be called to parse only attributes.
+ * Parsing of the "tags" shall be done by the caller.
+ */
+static int
+parse_attr(char *buf, uint32_t *i, char *attr, const char *key)
+{
+	int j = 0;
+	int keymatch = 0;
+
+	attr[j] = '\0';
+
+	while ((buf[*i] != '>') && (j < MAX_TAG_CHAR)) {
+		/* Ignore spaces. */
+		if (buf[*i] == ' ') {
+			attr[j] = '\0';
+			j = 0;
+			(*i)++;
+			continue;
+		}
+
+		/* Attribute key */
+		if (buf[*i] == '=') {
+			attr[j] = '\0';
+			j = 0;
+			(*i)++;
+
+			/* If the key is matched, extract the value. */
+			if (strncmp(attr, key, strlen(key)) != 0)
+				continue;
+			else
+				keymatch = 1;
+		}
+
+		/* Attribute value */
+		if ((buf[*i] == '"') && (keymatch == 1)) {
+			j = 0;
+			(*i)++;
+
+			while ((buf[*i] != '"') && (j < MAX_TAG_CHAR))
+				attr[(j)++] = buf[(*i)++];
+			attr[j] = '\0';
+			(*i)++;
+			return 0;
+		}
+
+		keymatch = 0;
+		attr[(j)++] = buf[(*i)++];
+	}
+
+	(*i)++;
+	return -1;
+}
+
+/* Get the system memory stats into buffer by calling malloc_info().
+ * malloc_info() returns the stats in XML format. Parse the XML to extract
+ * number of heaps, size of each heap, free memory in heap.
+ */
+static int
+parse_heap_mem_stats(struct rte_heap_mem_stats *heap_stats)
+{
+	char tag[MAX_TAG_CHAR] = {0};
+	int old_mem_index = -1;
+	int mem_index = -1;
+	uint32_t i = 0;
+	uint32_t j = 0;
+	size_t length;
+	char *buf;
+	FILE *fp;
+	int ret;
+
+	/* buf is dynamically allocated by open_memstream. */
+	fp = open_memstream(&buf, &length);
+	if (fp == NULL) {
+		RTE_LOG(DEBUG, EAL, "Error: Failed to open memory stream\n");
+		return -1;
+	}
+
+	/* Gets system memory stat's XML format. */
+	ret = malloc_info(0, fp);
+	fclose(fp);
+
+	if (ret != 0) {
+		RTE_LOG(DEBUG, EAL, "Error: malloc_info returned error\n");
+		return -1;
+	}
+
+	while (i < length) {
+		j = 0;
+		tag[j] = '\0';
+
+		/* Ignore newline and spaces. */
+		if ((buf[i] == '\n') || (buf[i] == ' ') || (buf[i] == '/') ||
+		    (buf[i] == '>')) {
+			i++;
+			continue;
+		}
+
+		if (buf[i] == '<') {
+			i++;
+			while ((buf[i] != ' ') && (buf[i] != '>') &&
+			       (j < MAX_TAG_CHAR)) {
+				tag[j++] = buf[i++];
+			}
+
+			if (strncmp(tag, "heap", strlen("heap")) == 0) {
+				old_mem_index = mem_index++;
+				if (mem_index >= MAX_SYS_MEM_ARENAS) {
+					RTE_LOG(DEBUG, EAL, "Memory arena "
+						"exceeded max limit: %d",
+						MAX_SYS_MEM_ARENAS);
+					goto done;
+				}
+				heap_stats->num_active_arena++;
+			}
+
+			continue;
+		}
+
+		if (mem_index < 0) {
+			i++;
+			continue;
+		}
+
+		if (parse_attr(buf, &i, tag, "type") < 0)
+			continue;
+
+		if (strncmp(tag, "fast", strlen("fast")) == 0) {
+			/* For total of all arenas, "heap" tag is not present
+			 * in xml. Below check is to handle that scenarios.
+			 *
+			 * FIXME: mem_index increment shall be independent of
+			 * the tag.
+			 */
+			if (old_mem_index == mem_index) {
+				mem_index++;
+				if (mem_index >= MAX_SYS_MEM_ARENAS) {
+					RTE_LOG(DEBUG, EAL, "Memory arena "
+						"exceeded max limit: %d\n",
+						MAX_SYS_MEM_ARENAS);
+					goto done;
+				}
+				heap_stats->num_active_arena++;
+			}
+			old_mem_index = mem_index;
+
+			if (parse_attr(buf, &i, tag, "count") == 0)
+				heap_stats->stats[mem_index].fast_count =
+							strtoul(tag, NULL, 10);
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].fast_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "rest", strlen("rest")) == 0) {
+			if (parse_attr(buf, &i, tag, "count") == 0)
+				heap_stats->stats[mem_index].rest_count =
+							strtoul(tag, NULL, 10);
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].rest_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "current", strlen("current")) == 0) {
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].curr_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "total", strlen("total")) == 0) {
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].heap_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "subheaps", strlen("subheaps")) == 0) {
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].heap_count =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		if (strncmp(tag, "mmap", strlen("mmap")) == 0) {
+			if (parse_attr(buf, &i, tag, "count") == 0)
+				heap_stats->stats[mem_index].mmap_count =
+							strtoul(tag, NULL, 10);
+			if (parse_attr(buf, &i, tag, "size") == 0)
+				heap_stats->stats[mem_index].mmap_size =
+							strtoul(tag, NULL, 10);
+			continue;
+		}
+
+		i++;
+	}
+
+done:
+	/* All done! Let's free the buf. */
+	free(buf);
+	return 0;
+}
+
+static int
+handle_sysmem_list_request(const char *cmd __rte_unused,
+			   const char *params __rte_unused,
+			   struct rte_tel_data *d)
+{
+	struct rte_heap_mem_stats heap_mem_stats;
+	unsigned int num_arena;
+	unsigned int i;
+
+	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
+	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
+		return -1;
+
+	/* Note:
+	 * Total active arenas are (num_active_arena - 1). The last entry in
+	 * the array is total of all arenas.
+	 */
+	num_arena = heap_mem_stats.num_active_arena;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+	for (i = 0; i < num_arena; i++)
+		rte_tel_data_add_array_int(d, i);
+
+	return 0;
+}
+
+static int
+handle_sysmem_info_request(const char *cmd __rte_unused, const char *params,
+			   struct rte_tel_data *d)
+{
+	struct rte_heap_mem_stats heap_mem_stats;
+	unsigned int arena_id;
+	uint64_t free_size;
+	uint64_t free_count;
+	uint64_t allocated_size;
+
+	if (params == NULL || strlen(params) == 0 || !isdigit(*params))
+		return -1;
+
+	arena_id = (unsigned int)strtoul(params, NULL, 10);
+	if (arena_id > UINT32_MAX)
+		return -1;
+
+	if (arena_id >= MAX_SYS_MEM_ARENAS)
+		return -1;
+
+	memset(&heap_mem_stats, 0, sizeof(struct rte_heap_mem_stats));
+	if (parse_heap_mem_stats(&heap_mem_stats) != 0)
+		return -1;
+
+	if (arena_id >= heap_mem_stats.num_active_arena) {
+		RTE_LOG(DEBUG, EAL, "Memory arena exceeded max limit: %d\n",
+			MAX_SYS_MEM_ARENAS);
+		return -1;
+	}
+
+	/* Fast and rest account for the total free memory. */
+	free_size = heap_mem_stats.stats[arena_id].fast_size +
+		    heap_mem_stats.stats[arena_id].rest_size;
+
+	free_count = heap_mem_stats.stats[arena_id].fast_count +
+		     heap_mem_stats.stats[arena_id].rest_count;
+
+	/* (System memory - free size) = allocated memory size. */
+	allocated_size = heap_mem_stats.stats[arena_id].curr_size - free_size;
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Arena_id", arena_id);
+	rte_tel_data_add_dict_int(d, "Allocated_size", allocated_size);
+	rte_tel_data_add_dict_u64(d, "Free_count", free_count);
+	rte_tel_data_add_dict_u64(d, "Free_size", free_size);
+	rte_tel_data_add_dict_u64(d, "Curr_size",
+				  heap_mem_stats.stats[arena_id].curr_size);
+	rte_tel_data_add_dict_u64(d, "Mmap_count",
+				  heap_mem_stats.stats[arena_id].mmap_count);
+	rte_tel_data_add_dict_u64(d, "Mmap_size",
+				  heap_mem_stats.stats[arena_id].mmap_size);
+	rte_tel_data_add_dict_u64(d, "Heap_count",
+				  heap_mem_stats.stats[arena_id].heap_count);
+	rte_tel_data_add_dict_u64(d, "Heap_size",
+				  heap_mem_stats.stats[arena_id].heap_size);
+
+	return 0;
+}
+#endif
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1716,5 +2037,14 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
 			handle_eal_element_info_request,
 			"Returns element info. Parameters: int heap_id, memseg_list_id, memseg_id, start_elem_id, end_elem_id");
+
+#ifdef RTE_EXEC_ENV_LINUX
+	rte_telemetry_register_cmd(SYSMEMORY_LIST_REQ,
+			handle_sysmem_list_request,
+			"Returns element information. Takes no parameters");
+	rte_telemetry_register_cmd(SYSMEMORY_INFO_REQ,
+			handle_sysmem_info_request,
+			"Returns element information. Parameters: int arena_id");
+#endif
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
  2022-09-29 11:43     ` [PATCH v5 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
@ 2022-10-06  7:07     ` Amit Prakash Shukla
  2022-10-07 19:52       ` David Marchand
  2022-10-07 19:48     ` David Marchand
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-10-06  7:07 UTC (permalink / raw)
  To: David Marchand
  Cc: dev, Jerin Jacob Kollanukkaran, Anatoly Burakov,
	bruce.richardson, ciara.power, dmitry.kozliuk

Hi David,

If no other review comments, could you please pick this series for 22.11 rc1 ?

Thanks,
Amit Shukla

> -----Original Message-----
> From: Amit Prakash Shukla <amitprakashs@marvell.com>
> Sent: Thursday, September 29, 2022 5:13 PM
> To: Anatoly Burakov <anatoly.burakov@intel.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> david.marchand@redhat.com; bruce.richardson@intel.com;
> ciara.power@intel.com; dmitry.kozliuk@gmail.com; Amit Prakash Shukla
> <amitprakashs@marvell.com>
> Subject: [PATCH v5 1/2] mem: telemetry support for memseg and element
> information
> 
> Changes adds telemetry support to display memory occupancy in memseg
> and the information of the elements allocated from a memseg based on
> arguments provided by user. This patch adds following endpoints:
> 
> 1. /eal/memseg_list_array
> The command displays the memseg list from which the memory has been
> allocated.
> Example:
> --> /eal/memseg_list_array
> {"/eal/memseg_list_array": [0, 1]}
> 
> 2. /eal/memseg_list_info,<memseg-list-id>
> The command outputs the memsegs, from which the memory is allocated,
> for the memseg_list given as input.
> Example:
> --> /eal/memseg_list_info,1
> {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \  12, 13, 14, 15]}
> 
> 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> The command outputs the memseg information based on the memseg-list
> and the memseg-id given as input.
> Example:
> --> /eal/memseg_info,0,10
> {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> "Memseg_index": 10, "Memseg_list_len": 64,     \
> "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> "Size": 536870912}}
> 
> --> /eal/memseg_info,1,15
> {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> "Memseg_index": 15, "Memseg_list_len": 64,      \
> "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> "Size": 536870912}}
> 
> 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based on the heap-
> id, memseg-list-id and memseg-id given as input.
> Example:
> --> /eal/element_list,0,0,63
> {"/eal/element_list": {"Element_count": 52}}
> 
> --> /eal/element_list,0,1,15
> {"/eal/element_list": {"Element_count": 52}}
> 
> 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>    <elem-start-id>,<elem-end-id>
> The command outputs element information like element start address, end
> address, to which memseg it belongs, element state, element size. User can
> give a range of elements to be printed.
> Example:
> --> /eal/element_info,0,1,15,1,2
> {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb201fe680",                 \
> "element_end_addr": "0xb20bfe700",                   \
> "element_size": 10485888, "element_state": "Busy"},  \
> "element.2": {"msl_id": 1, "ms_id": 15,              \
> "memseg_start_addr": "0xb20000000",                  \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb20bfe700",                 \
> "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> "element_state": "Busy"}, "Element_count": 2}}
> 
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Fixed compilation error related int-to-pointer-cast
> - Changes for code review suggestions
> 
> v3:
> - Commit message changes
> - Renaming end-points
> - Changing input parameters to comma-seperated
> - Reverting telemetry output buffer size
> 
> v4:
> - Patch-2 adds telemetry support to display system memory
> 
> v5:
> - Removed command help related changes
> 
>  lib/eal/common/eal_common_memory.c | 447
> ++++++++++++++++++++++++++++-
>  1 file changed, 442 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/eal/common/eal_common_memory.c
> b/lib/eal/common/eal_common_memory.c
> index 688dc615d7..6b863979e9 100644
> --- a/lib/eal/common/eal_common_memory.c
> +++ b/lib/eal/common/eal_common_memory.c
> @@ -3,6 +3,7 @@
>   */
> 
>  #include <errno.h>
> +#include <ctype.h>
>  #include <stdio.h>
>  #include <stdint.h>
>  #include <stdlib.h>
> @@ -26,6 +27,7 @@
>  #include "eal_memcfg.h"
>  #include "eal_options.h"
>  #include "malloc_heap.h"
> +#include "malloc_elem.h"
> 
>  /*
>   * Try to mmap *size bytes in /dev/zero. If it is successful, return the @@ -
> 1113,11 +1115,17 @@ rte_eal_memory_init(void)  }
> 
>  #ifndef RTE_EXEC_ENV_WINDOWS
> -#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
> -#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
> -#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
> -#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
> -#define ADDR_STR		15
> +#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
> +#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
> +#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
> +#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
> +#define EAL_MEMSEG_LIST_ARR_REQ
> 	"/eal/memseg_list_array"
> +#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
> +#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
> +#define EAL_ELEMENT_LIST_REQ		"/eal/element_list"
> +#define EAL_ELEMENT_INFO_REQ		"/eal/element_info"
> +#define ADDR_STR			15
> +
> 
>  /* Telemetry callback handler to return heap stats for requested heap id. */
> static int @@ -1265,6 +1273,418 @@
> handle_eal_memzone_list_request(const char *cmd __rte_unused,
>  	return 0;
>  }
> 
> +static int
> +handle_eal_memseg_list_array_request(const char *cmd __rte_unused,
> +				     const char *params __rte_unused,
> +				     struct rte_tel_data *d)
> +{
> +	struct rte_mem_config *mcfg;
> +	int i;
> +
> +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +	rte_mcfg_mem_read_lock();
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +
> +	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
> +		struct rte_memseg_list *msl = &mcfg->memsegs[i];
> +		if (msl->memseg_arr.count == 0)
> +			continue;
> +
> +		rte_tel_data_add_array_int(d, i);
> +	}
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
> +				    const char *params, struct rte_tel_data *d)
> {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	struct rte_fbarray *arr;
> +	uint32_t ms_list_idx;
> +	int ms_idx;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	if (!isdigit(*params))
> +		return -1;
> +
> +	ms_list_idx = strtoul(params, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> +		return -1;
> +
> +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +	rte_mcfg_mem_read_lock();
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	if (msl->memseg_arr.count == 0)
> +		goto done;
> +
> +	arr = &msl->memseg_arr;
> +
> +	ms_idx = rte_fbarray_find_next_used(arr, 0);
> +	while (ms_idx >= 0) {
> +		rte_tel_data_add_array_int(d, ms_idx);
> +		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
> +	}
> +
> +done:
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> +			       const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	uint64_t ms_start_addr, ms_end_addr, ms_size;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct rte_fbarray *arr;
> +	char addr[ADDR_STR];
> +	uint32_t ms_list_idx = 0;
> +	uint32_t ms_idx = 0;
> +	uint32_t msl_len;
> +	char dlim[2] = ",";
> +	char *token;
> +	char *params_args;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);
> +	token = strtok(params_args, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_list_idx = strtoul(token, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +	ms_idx = strtoul(token, NULL, 10);
> +
> +	free(params_args);
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	if (msl->memseg_arr.count == 0) {
> +		rte_mcfg_mem_read_unlock();
> +		return -1;
> +	}
> +
> +	arr = &msl->memseg_arr;
> +	msl_len = arr->len;
> +
> +	ms = rte_fbarray_get(arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +	ms_size = ms->hugepage_sz;
> +
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> +	rte_tel_data_add_dict_int(d, "Memseg_list_len", msl_len);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> +	rte_tel_data_add_dict_int(d, "Size", ms_size);
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_element_list_request(const char *cmd __rte_unused,
> +				const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct malloc_elem *elem;
> +	struct malloc_heap *heap;
> +	uint64_t ms_start_addr, ms_end_addr;
> +	uint64_t elem_start_addr, elem_end_addr;
> +	uint32_t ms_list_idx = 0;
> +	uint32_t heap_id = 0;
> +	uint32_t ms_idx = 0;
> +	char dlim[2] = ",";
> +	int elem_count = 0;
> +	char *token;
> +	char *params_args;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);
> +	token = strtok(params_args, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	heap_id = strtoul(token, NULL, 10);
> +	if (heap_id >= RTE_MAX_HEAPS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_list_idx = strtoul(token, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_idx = strtoul(token, NULL, 10);
> +
> +	free(params_args);
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +
> +	heap = &mcfg->malloc_heaps[heap_id];
> +	rte_spinlock_lock(&heap->lock);
> +
> +	elem = heap->first;
> +	while (elem) {
> +		elem_start_addr = (uint64_t)elem;
> +		elem_end_addr =
> +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> >size);
> +
> +		if ((uint64_t)elem_start_addr >= ms_start_addr &&
> +		    (uint64_t)elem_end_addr <= ms_end_addr)
> +			elem_count++;
> +		elem = elem->next;
> +	}
> +
> +	rte_spinlock_unlock(&heap->lock);
> +
> +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_element_info_request(const char *cmd __rte_unused,
> +				const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct malloc_elem *elem;
> +	struct malloc_heap *heap;
> +	struct rte_tel_data *c;
> +	uint64_t ms_start_addr, ms_end_addr;
> +	uint64_t elem_start_addr, elem_end_addr;
> +	uint32_t ms_list_idx = 0;
> +	uint32_t heap_id = 0;
> +	uint32_t ms_idx = 0;
> +	uint32_t start_elem = 0, end_elem = 0;
> +	uint32_t count = 0, elem_count = 0;
> +	char dlim[2] = ",";
> +	char str[ADDR_STR];
> +	char *params_args;
> +	char *token;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);
> +	token = strtok(params_args, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	heap_id = strtoul(token, NULL, 10);
> +	if (heap_id >= RTE_MAX_HEAPS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_list_idx = strtoul(token, NULL, 10);
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	ms_idx = strtoul(token, NULL, 10);
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	start_elem = strtoul(token, NULL, 10);
> +
> +	token = strtok(NULL, dlim);
> +	if (token == NULL || !isdigit(*token)) {
> +		free(params_args);
> +		return -1;
> +	}
> +
> +	end_elem = strtoul(token, NULL, 10);
> +
> +	free(params_args);
> +
> +	if (end_elem < start_elem)
> +		return -1;
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +
> +	heap = &mcfg->malloc_heaps[heap_id];
> +	rte_spinlock_lock(&heap->lock);
> +
> +	elem = heap->first;
> +	while (elem) {
> +		elem_start_addr = (uint64_t)elem;
> +		elem_end_addr =
> +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> >size);
> +
> +		if (elem_start_addr < ms_start_addr ||
> +				elem_end_addr > ms_end_addr) {
> +			elem = elem->next;
> +			continue;
> +		}
> +
> +		if (count < start_elem) {
> +			elem = elem->next;
> +			count++;
> +			continue;
> +		}
> +
> +		c = rte_tel_data_alloc();
> +		if (c == NULL)
> +			break;
> +
> +		rte_tel_data_start_dict(c);
> +		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
> +		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> +		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> +		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
> +		rte_tel_data_add_dict_string(c, "element_start_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
> +		rte_tel_data_add_dict_string(c, "element_end_addr", str);
> +		rte_tel_data_add_dict_int(c, "element_size", elem->size);
> +		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
> +			 elem->state == 1 ? "Busy" : elem->state == 2 ?
> +			 "Pad" : "Error");
> +		rte_tel_data_add_dict_string(c, "element_state", str);
> +
> +		snprintf(str, ADDR_STR, "%s.%u", "element", count);
> +		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
> +			rte_tel_data_free(c);
> +			break;
> +		}
> +
> +		elem_count++;
> +		count++;
> +		if (count > end_elem)
> +			break;
> +
> +		elem = elem->next;
> +	}
> +
> +	rte_spinlock_unlock(&heap->lock);
> +
> +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> +
> +	return 0;
> +}
> +
>  RTE_INIT(memory_telemetry)
>  {
>  	rte_telemetry_register_cmd(
> @@ -1279,5 +1699,22 @@ RTE_INIT(memory_telemetry)
>  	rte_telemetry_register_cmd(
>  			EAL_HEAP_INFO_REQ,
> handle_eal_heap_info_request,
>  			"Returns malloc heap stats. Parameters: int
> heap_id");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LIST_ARR_REQ,
> +			handle_eal_memseg_list_array_request,
> +			"Returns hugepage list. Takes no parameters");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LIST_INFO_REQ,
> +			handle_eal_memseg_list_info_request,
> +			"Returns memseg list. Parameters: int
> memseg_list_id");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_INFO_REQ,
> handle_eal_memseg_info_request,
> +			"Returns memseg info. Parameter: int
> memseg_list_id,int memseg_id");
> +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> +			handle_eal_element_list_request,
> +			"Returns element info. Parameters: int heap_id, int
> memseg_list_id, int memseg_id");
> +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> +			handle_eal_element_info_request,
> +			"Returns element info. Parameters: int heap_id,
> memseg_list_id,
> +memseg_id, start_elem_id, end_elem_id");
>  }
>  #endif
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v5 2/2] mem: telemetry support for system memory information
  2022-09-29 11:43     ` [PATCH v5 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
@ 2022-10-07 19:46       ` David Marchand
  2022-10-11  7:10         ` [EXT] " Amit Prakash Shukla
  0 siblings, 1 reply; 42+ messages in thread
From: David Marchand @ 2022-10-07 19:46 UTC (permalink / raw)
  To: Amit Prakash Shukla, Thomas Monjalon, Anatoly Burakov, dmitry.kozliuk
  Cc: dev, jerinj, bruce.richardson, ciara.power

On Thu, Sep 29, 2022 at 1:44 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> Changes adds telemetry support to display system memory information,
> allocated using calls malloc, calloc, mmap, etc. This patch
> is based on malloc_info. This patch adds following endpoints:

malloc_info is a GNU extension.
It is not available in musl and it breaks compilation in Alpine Linux.
So I can't take this patch.


>
> 1. /sysmem/sys_heap_list
> The commands displays the arenas currently in use.
> Example:
> --> /sysmem/sys_heap_list
> {"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
>

I am unsure about the command names.

Those commands are really low level and tied to glibc malloc.
It is unlikely we will have an unified naming with other libc/OS.

I would prefer another pair of eyes, especially on this patch.
Dmitry, Anatoly?


-- 
David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
  2022-09-29 11:43     ` [PATCH v5 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
  2022-10-06  7:07     ` [PATCH v5 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
@ 2022-10-07 19:48     ` David Marchand
  2022-10-11  7:22       ` [EXT] " Amit Prakash Shukla
  2022-10-20 11:40     ` Dmitry Kozlyuk
  2022-10-25 11:51     ` [PATCH v6] " Amit Prakash Shukla
  4 siblings, 1 reply; 42+ messages in thread
From: David Marchand @ 2022-10-07 19:48 UTC (permalink / raw)
  To: Amit Prakash Shukla, Anatoly Burakov, dmitry.kozliuk
  Cc: dev, jerinj, bruce.richardson, ciara.power, Thomas Monjalon

On Thu, Sep 29, 2022 at 1:43 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
> 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based
> on the heap-id, memseg-list-id and memseg-id given as input.
> Example:
> --> /eal/element_list,0,0,63
> {"/eal/element_list": {"Element_count": 52}}
>
> --> /eal/element_list,0,1,15
> {"/eal/element_list": {"Element_count": 52}}
>
> 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>    <elem-start-id>,<elem-end-id>
> The command outputs element information like element start
> address, end address, to which memseg it belongs, element
> state, element size. User can give a range of elements to be
> printed.
> Example:
> --> /eal/element_info,0,1,15,1,2
> {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb201fe680",                 \
> "element_end_addr": "0xb20bfe700",                   \
> "element_size": 10485888, "element_state": "Busy"},  \
> "element.2": {"msl_id": 1, "ms_id": 15,              \
> "memseg_start_addr": "0xb20000000",                  \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb20bfe700",                 \
> "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> "element_state": "Busy"}, "Element_count": 2}}
>

element is too generic.
Just look at the command name: /eal/element_XXX.
What is an EAL element?


-- 
David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-10-06  7:07     ` [PATCH v5 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
@ 2022-10-07 19:52       ` David Marchand
  0 siblings, 0 replies; 42+ messages in thread
From: David Marchand @ 2022-10-07 19:52 UTC (permalink / raw)
  To: Amit Prakash Shukla
  Cc: dev, Jerin Jacob Kollanukkaran, Anatoly Burakov,
	bruce.richardson, ciara.power, dmitry.kozliuk

On Thu, Oct 6, 2022 at 9:07 AM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> Hi David,
>
> If no other review comments, could you please pick this series for 22.11 rc1 ?

I had a better look and sent some comments.
We can still consider this series for rc2 in any case.


-- 
David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v5 2/2] mem: telemetry support for system memory information
  2022-10-07 19:46       ` David Marchand
@ 2022-10-11  7:10         ` Amit Prakash Shukla
  2022-10-20 19:18           ` Dmitry Kozlyuk
  0 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-10-11  7:10 UTC (permalink / raw)
  To: David Marchand, Thomas Monjalon, Anatoly Burakov, dmitry.kozliuk
  Cc: dev, Jerin Jacob Kollanukkaran, bruce.richardson, ciara.power

Thanks David for the feedback. Please find the proposed fixed inline.

> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Saturday, October 8, 2022 1:17 AM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>; Thomas Monjalon
> <thomas@monjalon.net>; Anatoly Burakov <anatoly.burakov@intel.com>;
> dmitry.kozliuk@gmail.com
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> bruce.richardson@intel.com; ciara.power@intel.com
> Subject: [EXT] Re: [PATCH v5 2/2] mem: telemetry support for system
> memory information
> 
> External Email
> 
> ----------------------------------------------------------------------
> On Thu, Sep 29, 2022 at 1:44 PM Amit Prakash Shukla
> <amitprakashs@marvell.com> wrote:
> >
> > Changes adds telemetry support to display system memory information,
> > allocated using calls malloc, calloc, mmap, etc. This patch is based
> > on malloc_info. This patch adds following endpoints:
> 
> malloc_info is a GNU extension.
> It is not available in musl and it breaks compilation in Alpine Linux.
> So I can't take this patch.

Shall we limit this for Glibc at compile time ?

+#if defined __GLIBC__ && defined __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 10)
        /* Gets system memory stat's XML format. */
        ret = malloc_info(0, fp);
+#endif
+#else
+       RTE_LOG(DEBUG, EAL, "Error: malloc_info not supported by libc\n");
+       fclose(fp);
+       return -1;
+#endif

I will send out a v6 if the above solution is fine.

> 
> 
> >
> > 1. /sysmem/sys_heap_list
> > The commands displays the arenas currently in use.
> > Example:
> > --> /sysmem/sys_heap_list
> > {"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
> >
> 
> I am unsure about the command names.
> 
> Those commands are really low level and tied to glibc malloc.
> It is unlikely we will have an unified naming with other libc/OS.
> 
> I would prefer another pair of eyes, especially on this patch.
> Dmitry, Anatoly?
> 
> 
> --
> David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-10-07 19:48     ` David Marchand
@ 2022-10-11  7:22       ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-10-11  7:22 UTC (permalink / raw)
  To: David Marchand, Anatoly Burakov, dmitry.kozliuk
  Cc: dev, Jerin Jacob Kollanukkaran, bruce.richardson, ciara.power,
	Thomas Monjalon

Thanks David for the feedback.

> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Saturday, October 8, 2022 1:19 AM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>; Anatoly Burakov
> <anatoly.burakov@intel.com>; dmitry.kozliuk@gmail.com
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> bruce.richardson@intel.com; ciara.power@intel.com; Thomas Monjalon
> <thomas@monjalon.net>
> Subject: [EXT] Re: [PATCH v5 1/2] mem: telemetry support for memseg and
> element information
> 
> External Email
> 
> ----------------------------------------------------------------------
> On Thu, Sep 29, 2022 at 1:43 PM Amit Prakash Shukla
> <amitprakashs@marvell.com> wrote:
> > 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> > The command outputs number of elements in a memseg based on the
> > heap-id, memseg-list-id and memseg-id given as input.
> > Example:
> > --> /eal/element_list,0,0,63
> > {"/eal/element_list": {"Element_count": 52}}
> >
> > --> /eal/element_list,0,1,15
> > {"/eal/element_list": {"Element_count": 52}}
> >
> > 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> >    <elem-start-id>,<elem-end-id>
> > The command outputs element information like element start address,
> > end address, to which memseg it belongs, element state, element size.
> > User can give a range of elements to be printed.
> > Example:
> > --> /eal/element_info,0,1,15,1,2
> > {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb201fe680",                 \
> > "element_end_addr": "0xb20bfe700",                   \
> > "element_size": 10485888, "element_state": "Busy"},  \
> > "element.2": {"msl_id": 1, "ms_id": 15,              \
> > "memseg_start_addr": "0xb20000000",                  \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb20bfe700",                 \
> > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > "element_state": "Busy"}, "Element_count": 2}}
> >
> 
> element is too generic.
> Just look at the command name: /eal/element_XXX.
> What is an EAL element?

Sure, we can rename the commands to /eal/mem_element_XXX  in v6 ?

> 
> 
> --
> David Marchand

- Amit Shukla

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
                       ` (2 preceding siblings ...)
  2022-10-07 19:48     ` David Marchand
@ 2022-10-20 11:40     ` Dmitry Kozlyuk
  2022-10-21 19:26       ` [EXT] " Amit Prakash Shukla
  2022-10-25 11:51     ` [PATCH v6] " Amit Prakash Shukla
  4 siblings, 1 reply; 42+ messages in thread
From: Dmitry Kozlyuk @ 2022-10-20 11:40 UTC (permalink / raw)
  To: Amit Prakash Shukla
  Cc: Anatoly Burakov, dev, jerinj, david.marchand, bruce.richardson,
	ciara.power

2022-09-29 17:13 (UTC+0530), Amit Prakash Shukla:
> Changes adds telemetry support to display memory occupancy
> in memseg and the information of the elements allocated from
> a memseg based on arguments provided by user. This patch
> adds following endpoints:
> 
> 1. /eal/memseg_list_array
> The command displays the memseg list from which the memory
> has been allocated.
> Example:
> --> /eal/memseg_list_array  
> {"/eal/memseg_list_array": [0, 1]}
> 
> 2. /eal/memseg_list_info,<memseg-list-id>
> The command outputs the memsegs, from which the memory is
> allocated, for the memseg_list given as input.
> Example:
> --> /eal/memseg_list_info,1  
> {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
>  12, 13, 14, 15]}

MSL has more properties worth reporting.
Also note that by default

	#define RTE_MAX_MEMSEG_PER_LIST 8192

which means that the array will not fit into the output buffer (16KB).
Large number of memsegs is quite possible with 2MB hugepages.
I suggest to have a request for MSL properties, including length,
and this request be a separate one.
If this one fails due to insufficient buffer,
the user will at least know the range of possible indices.

> 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> The command outputs the memseg information based on the
> memseg-list and the memseg-id given as input.
> Example:
> --> /eal/memseg_info,0,10  
> {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> "Memseg_index": 10, "Memseg_list_len": 64,     \
> "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> "Size": 536870912}}

"Memseg_list_len" is neither a property or an identifier of a memseg.
Important memseg fields are missing, like socket, hugepage_sz, and flags.
Note that "Size" displays hugepage_sz, but this is not correct:
for external memory memseg is not necessarily a single page.
Size and hugepage size fields must be distinct.

> 
> --> /eal/memseg_info,1,15  
> {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> "Memseg_index": 15, "Memseg_list_len": 64,      \
> "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> "Size": 536870912}}
> 
> 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based
> on the heap-id, memseg-list-id and memseg-id given as input.
> Example:
> --> /eal/element_list,0,0,63  
> {"/eal/element_list": {"Element_count": 52}}

How does the user learn heap_id?
There probably should be /eal/heap_id returning a list of heap IDs.

Please use a consistent naming scheme for requests returning ID lists.
Currently MSL have "_array" suffix but memsegs and elements don't.

> --> /eal/element_list,0,1,15  
> {"/eal/element_list": {"Element_count": 52}}
> 
> 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>    <elem-start-id>,<elem-end-id>
> The command outputs element information like element start
> address, end address, to which memseg it belongs, element
> state, element size. User can give a range of elements to be
> printed.
> Example:
> --> /eal/element_info,0,1,15,1,2  
> {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb201fe680",                 \
> "element_end_addr": "0xb20bfe700",                   \
> "element_size": 10485888, "element_state": "Busy"},  \
> "element.2": {"msl_id": 1, "ms_id": 15,              \
> "memseg_start_addr": "0xb20000000",                  \
> "memseg_end_addr": "0xb40000000",                    \
> "element_start_addr": "0xb20bfe700",                 \
> "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> "element_state": "Busy"}, "Element_count": 2}}

How this request is going to be used?
Elements don't have permanent IDs like MSL/memseg index or heap ID.
Heap layout may change between /eal/element_list and this request.
Maybe instead there should be a filter by address
with maybe a context parameter (like "grep -C")?
The proposed API is not bad at all by itself,
I'm asking to make sure it solves the task in the best way.

[...]

> +static int
> +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> +			       const char *params, struct rte_tel_data *d)
> +{
> +	struct rte_mem_config *mcfg;
> +	uint64_t ms_start_addr, ms_end_addr, ms_size;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct rte_fbarray *arr;
> +	char addr[ADDR_STR];
> +	uint32_t ms_list_idx = 0;
> +	uint32_t ms_idx = 0;
> +	uint32_t msl_len;
> +	char dlim[2] = ",";
> +	char *token;
> +	char *params_args;
> +
> +	if (params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);

Please check the allocation result hear and in the rest of the handlers.

It would be nice to have a local helper to parse N integer params,
this would reduce and simplify the code:

static int
parse_params(const char *params, int *vals, size_t vals_n);

[...]
>  RTE_INIT(memory_telemetry)
>  {
>  	rte_telemetry_register_cmd(
> @@ -1279,5 +1699,22 @@ RTE_INIT(memory_telemetry)
>  	rte_telemetry_register_cmd(
>  			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
>  			"Returns malloc heap stats. Parameters: int heap_id");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LIST_ARR_REQ,
> +			handle_eal_memseg_list_array_request,
> +			"Returns hugepage list. Takes no parameters");

"hugepage list" -> "array of memseg list IDs"

> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LIST_INFO_REQ,
> +			handle_eal_memseg_list_info_request,
> +			"Returns memseg list. Parameters: int memseg_list_id");

"memseg list" -> "memseg list info"

> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
> +			"Returns memseg info. Parameter: int memseg_list_id,int memseg_id");
> +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> +			handle_eal_element_list_request,
> +			"Returns element info. Parameters: int heap_id, int memseg_list_id, int memseg_id");

"element info" -> "array of heap element IDs".

> +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> +			handle_eal_element_info_request,
> +			"Returns element info. Parameters: int heap_id, memseg_list_id, memseg_id, start_elem_id, end_elem_id");
>  }
>  #endif

Please make parameter descriptions consistent ("int x, int y" vs "int x, y").


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [EXT] Re: [PATCH v5 2/2] mem: telemetry support for system memory information
  2022-10-11  7:10         ` [EXT] " Amit Prakash Shukla
@ 2022-10-20 19:18           ` Dmitry Kozlyuk
  2022-10-20 19:50             ` Stephen Hemminger
  0 siblings, 1 reply; 42+ messages in thread
From: Dmitry Kozlyuk @ 2022-10-20 19:18 UTC (permalink / raw)
  To: Amit Prakash Shukla
  Cc: David Marchand, Thomas Monjalon, Anatoly Burakov, dev,
	Jerin Jacob Kollanukkaran, bruce.richardson, ciara.power

2022-10-11 07:10 (UTC+0000), Amit Prakash Shukla:
> Thanks David for the feedback. Please find the proposed fixed inline.
> 
> > -----Original Message-----
> > From: David Marchand <david.marchand@redhat.com>
> > Sent: Saturday, October 8, 2022 1:17 AM
> > To: Amit Prakash Shukla <amitprakashs@marvell.com>; Thomas Monjalon
> > <thomas@monjalon.net>; Anatoly Burakov <anatoly.burakov@intel.com>;
> > dmitry.kozliuk@gmail.com
> > Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> > bruce.richardson@intel.com; ciara.power@intel.com
> > Subject: [EXT] Re: [PATCH v5 2/2] mem: telemetry support for system
> > memory information
> > 
> > External Email
> > 
> > ----------------------------------------------------------------------
> > On Thu, Sep 29, 2022 at 1:44 PM Amit Prakash Shukla
> > <amitprakashs@marvell.com> wrote:  
> > >
> > > Changes adds telemetry support to display system memory information,
> > > allocated using calls malloc, calloc, mmap, etc. This patch is based
> > > on malloc_info. This patch adds following endpoints:  
> > 
> > malloc_info is a GNU extension.
> > It is not available in musl and it breaks compilation in Alpine Linux.
> > So I can't take this patch.  
> 
> Shall we limit this for Glibc at compile time ?
> 
> +#if defined __GLIBC__ && defined __GLIBC_PREREQ
> +#if __GLIBC_PREREQ(2, 10)
>         /* Gets system memory stat's XML format. */
>         ret = malloc_info(0, fp);
> +#endif
> +#else
> +       RTE_LOG(DEBUG, EAL, "Error: malloc_info not supported by libc\n");
> +       fclose(fp);
> +       return -1;
> +#endif
> 
> I will send out a v6 if the above solution is fine.
> 
> > 
> >   
> > >
> > > 1. /sysmem/sys_heap_list
> > > The commands displays the arenas currently in use.
> > > Example:  
> > > --> /sysmem/sys_heap_list  
> > > {"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
> > >  
> > 
> > I am unsure about the command names.
> > 
> > Those commands are really low level and tied to glibc malloc.
> > It is unlikely we will have an unified naming with other libc/OS.
> > 
> > I would prefer another pair of eyes, especially on this patch.
> > Dmitry, Anatoly?

I agree with David.

Microsoft CRT provides completely different statistics.
I can't say for FreeBSD.
Even if GNU libc is used, the process can be run with jemalloc, for example,
and this statistics become meaningless then.
What is "system" memory, anyway? It can be acquired bypassing malloc,
it can be hugepages mmap'd without DPDK, etc.

What is the task this API must solve?
My guess is that monitoring needs to know how much physical memory
1) the process uses and 2) how much it can use, so on Linux this API
could be implemented using getrusage() and getrlimit().
I don't think that a fully portable implementation is possible,
but at least API will be unified.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [EXT] Re: [PATCH v5 2/2] mem: telemetry support for system memory information
  2022-10-20 19:18           ` Dmitry Kozlyuk
@ 2022-10-20 19:50             ` Stephen Hemminger
  0 siblings, 0 replies; 42+ messages in thread
From: Stephen Hemminger @ 2022-10-20 19:50 UTC (permalink / raw)
  To: Dmitry Kozlyuk
  Cc: Amit Prakash Shukla, David Marchand, Thomas Monjalon,
	Anatoly Burakov, dev, Jerin Jacob Kollanukkaran,
	bruce.richardson, ciara.power

On Thu, 20 Oct 2022 22:18:27 +0300
Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote:

> > 
> > I will send out a v6 if the above solution is fine.
> >   
> > > 
> > >     
> > > >
> > > > 1. /sysmem/sys_heap_list
> > > > The commands displays the arenas currently in use.
> > > > Example:    
> > > > --> /sysmem/sys_heap_list    
> > > > {"/sysmem/sys_heap_list": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
> > > >    
> > > 
> > > I am unsure about the command names.
> > > 
> > > Those commands are really low level and tied to glibc malloc.
> > > It is unlikely we will have an unified naming with other libc/OS.
> > > 
> > > I would prefer another pair of eyes, especially on this patch.
> > > Dmitry, Anatoly?  
> 
> I agree with David.
> 
> Microsoft CRT provides completely different statistics.
> I can't say for FreeBSD.
> Even if GNU libc is used, the process can be run with jemalloc, for example,
> and this statistics become meaningless then.
> What is "system" memory, anyway? It can be acquired bypassing malloc,
> it can be hugepages mmap'd without DPDK, etc.
> 
> What is the task this API must solve?
> My guess is that monitoring needs to know how much physical memory
> 1) the process uses and 2) how much it can use, so on Linux this API
> could be implemented using getrusage() and getrlimit().
> I don't think that a fully portable implementation is possible,
> but at least API will be unified.


NAK
You are opening a mess here.
The malloc_info() exporting XML also means you have to parse the crap.

Telemetry to should stick to the DPDK environment and not try to support
looking at other parts of the system. Otherwise, it risks becoming
tied to one OS and version. 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-10-20 11:40     ` Dmitry Kozlyuk
@ 2022-10-21 19:26       ` Amit Prakash Shukla
  2022-10-21 20:07         ` Dmitry Kozlyuk
  0 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-10-21 19:26 UTC (permalink / raw)
  To: Dmitry Kozlyuk
  Cc: Anatoly Burakov, dev, Jerin Jacob Kollanukkaran, david.marchand,
	bruce.richardson, ciara.power

Thanks Dmitry for the feedback. Please find my reply in-line.

> -----Original Message-----
> From: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
> Sent: Thursday, October 20, 2022 5:11 PM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>
> Cc: Anatoly Burakov <anatoly.burakov@intel.com>; dev@dpdk.org; Jerin
> Jacob Kollanukkaran <jerinj@marvell.com>; david.marchand@redhat.com;
> bruce.richardson@intel.com; ciara.power@intel.com
> Subject: [EXT] Re: [PATCH v5 1/2] mem: telemetry support for memseg and
> element information
> 
> External Email
> 
> ----------------------------------------------------------------------
> 2022-09-29 17:13 (UTC+0530), Amit Prakash Shukla:
> > Changes adds telemetry support to display memory occupancy in memseg
> > and the information of the elements allocated from a memseg based on
> > arguments provided by user. This patch adds following endpoints:
> >
> > 1. /eal/memseg_list_array
> > The command displays the memseg list from which the memory has been
> > allocated.
> > Example:
> > --> /eal/memseg_list_array
> > {"/eal/memseg_list_array": [0, 1]}
> >
> > 2. /eal/memseg_list_info,<memseg-list-id>
> > The command outputs the memsegs, from which the memory is allocated,
> > for the memseg_list given as input.
> > Example:
> > --> /eal/memseg_list_info,1
> > {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
> > 12, 13, 14, 15]}
> 
> MSL has more properties worth reporting.
> Also note that by default
> 
> 	#define RTE_MAX_MEMSEG_PER_LIST 8192
> 
> which means that the array will not fit into the output buffer (16KB).
> Large number of memsegs is quite possible with 2MB hugepages.
> I suggest to have a request for MSL properties, including length, and this
> request be a separate one.
> If this one fails due to insufficient buffer, the user will at least know the
> range of possible indices.

Agreed. Will implement new request for MSL properties in v6.

> 
> > 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> > The command outputs the memseg information based on the memseg-list
> > and the memseg-id given as input.
> > Example:
> > --> /eal/memseg_info,0,10
> > {"/eal/memseg_info": {"Memseg_list_index": 0,  \
> > "Memseg_index": 10, "Memseg_list_len": 64,     \
> > "Start_addr": "0x260000000", "End_addr": "0x280000000",  \
> > "Size": 536870912}}
> 
> "Memseg_list_len" is neither a property or an identifier of a memseg.

Idea to print Memseg_list_len was to display total number of memsegs in the MSL, 
But I agree with you that it makes more sense to be printed in new request for
MSL properties.

> Important memseg fields are missing, like socket, hugepage_sz, and flags.
> Note that "Size" displays hugepage_sz, but this is not correct:
> for external memory memseg is not necessarily a single page.
> Size and hugepage size fields must be distinct.

Sure, will add it in v6.

> 
> >
> > --> /eal/memseg_info,1,15
> > {"/eal/memseg_info": {"Memseg_list_index": 1,   \
> > "Memseg_index": 15, "Memseg_list_len": 64,      \
> > "Start_addr": "0xb20000000", "End_addr": "0xb40000000",  \
> > "Size": 536870912}}
> >
> > 4. /eal/element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> > The command outputs number of elements in a memseg based on the
> > heap-id, memseg-list-id and memseg-id given as input.
> > Example:
> > --> /eal/element_list,0,0,63
> > {"/eal/element_list": {"Element_count": 52}}
> 
> How does the user learn heap_id?
> There probably should be /eal/heap_id returning a list of heap IDs.

Request for list of active heap Id's is already present. 
" /eal/heap_list"

> 
> Please use a consistent naming scheme for requests returning ID lists.
> Currently MSL have "_array" suffix but memsegs and elements don't.

Sure

> 
> > --> /eal/element_list,0,1,15
> > {"/eal/element_list": {"Element_count": 52}}
> >
> > 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> >    <elem-start-id>,<elem-end-id>
> > The command outputs element information like element start address,
> > end address, to which memseg it belongs, element state, element size.
> > User can give a range of elements to be printed.
> > Example:
> > --> /eal/element_info,0,1,15,1,2
> > {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb201fe680",                 \
> > "element_end_addr": "0xb20bfe700",                   \
> > "element_size": 10485888, "element_state": "Busy"},  \
> > "element.2": {"msl_id": 1, "ms_id": 15,              \
> > "memseg_start_addr": "0xb20000000",                  \
> > "memseg_end_addr": "0xb40000000",                    \
> > "element_start_addr": "0xb20bfe700",                 \
> > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > "element_state": "Busy"}, "Element_count": 2}}
> 
> How this request is going to be used?
> Elements don't have permanent IDs like MSL/memseg index or heap ID.
> Heap layout may change between /eal/element_list and this request.

Idea here was to print information related to memory element. This information
Can be printed for a single element or for a range of elements.

> Maybe instead there should be a filter by address with maybe a context
> parameter (like "grep -C")?

You mean that the user shall be able to grep for a memory address to check
which element it belongs to ? If my understanding is correct, can I implement
it as new request post rc2 and keep this request as-is?

> The proposed API is not bad at all by itself, I'm asking to make sure it solves
> the task in the best way.
> 
> [...]
> 
> > +static int
> > +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> > +			       const char *params, struct rte_tel_data *d) {
> > +	struct rte_mem_config *mcfg;
> > +	uint64_t ms_start_addr, ms_end_addr, ms_size;
> > +	struct rte_memseg_list *msl;
> > +	const struct rte_memseg *ms;
> > +	struct rte_fbarray *arr;
> > +	char addr[ADDR_STR];
> > +	uint32_t ms_list_idx = 0;
> > +	uint32_t ms_idx = 0;
> > +	uint32_t msl_len;
> > +	char dlim[2] = ",";
> > +	char *token;
> > +	char *params_args;
> > +
> > +	if (params == NULL || strlen(params) == 0)
> > +		return -1;
> > +
> > +	/* strtok expects char * and param is const char *. Hence on using
> > +	 * params as "const char *" compiler throws warning.
> > +	 */
> > +	params_args = strdup(params);
> 
> Please check the allocation result hear and in the rest of the handlers.

Sure, will do it in v6.

> 
> It would be nice to have a local helper to parse N integer params, this would
> reduce and simplify the code:
> 
> static int
> parse_params(const char *params, int *vals, size_t vals_n);
> 
Sure.

> [...]
> >  RTE_INIT(memory_telemetry)
> >  {
> >  	rte_telemetry_register_cmd(
> > @@ -1279,5 +1699,22 @@ RTE_INIT(memory_telemetry)
> >  	rte_telemetry_register_cmd(
> >  			EAL_HEAP_INFO_REQ,
> handle_eal_heap_info_request,
> >  			"Returns malloc heap stats. Parameters: int
> heap_id");
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_LIST_ARR_REQ,
> > +			handle_eal_memseg_list_array_request,
> > +			"Returns hugepage list. Takes no parameters");
> 
> "hugepage list" -> "array of memseg list IDs"
> 
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_LIST_INFO_REQ,
> > +			handle_eal_memseg_list_info_request,
> > +			"Returns memseg list. Parameters: int
> memseg_list_id");
> 
> "memseg list" -> "memseg list info"
> 
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_INFO_REQ,
> handle_eal_memseg_info_request,
> > +			"Returns memseg info. Parameter: int
> memseg_list_id,int memseg_id");
> > +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> > +			handle_eal_element_list_request,
> > +			"Returns element info. Parameters: int heap_id, int
> > +memseg_list_id, int memseg_id");
> 
> "element info" -> "array of heap element IDs".
> 
> > +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> > +			handle_eal_element_info_request,
> > +			"Returns element info. Parameters: int heap_id,
> memseg_list_id,
> > +memseg_id, start_elem_id, end_elem_id");
> >  }
> >  #endif
> 
> Please make parameter descriptions consistent ("int x, int y" vs "int x, y").
Sure.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [EXT] Re: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-10-21 19:26       ` [EXT] " Amit Prakash Shukla
@ 2022-10-21 20:07         ` Dmitry Kozlyuk
  2022-10-25  7:25           ` Amit Prakash Shukla
  0 siblings, 1 reply; 42+ messages in thread
From: Dmitry Kozlyuk @ 2022-10-21 20:07 UTC (permalink / raw)
  To: Amit Prakash Shukla
  Cc: Anatoly Burakov, dev, Jerin Jacob Kollanukkaran, david.marchand,
	bruce.richardson, ciara.power

Hi Amit,

2022-10-21 19:26 (UTC+0000), Amit Prakash Shukla:
[...]
> > How does the user learn heap_id?
> > There probably should be /eal/heap_id returning a list of heap IDs.  
> 
> Request for list of active heap Id's is already present. 
> " /eal/heap_list"

My bad!

> > > --> /eal/element_list,0,1,15  
> > > {"/eal/element_list": {"Element_count": 52}}
> > >
> > > 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> > >    <elem-start-id>,<elem-end-id>
> > > The command outputs element information like element start address,
> > > end address, to which memseg it belongs, element state, element size.
> > > User can give a range of elements to be printed.
> > > Example:  
> > > --> /eal/element_info,0,1,15,1,2  
> > > {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> > > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > > "memseg_end_addr": "0xb40000000",                    \
> > > "element_start_addr": "0xb201fe680",                 \
> > > "element_end_addr": "0xb20bfe700",                   \
> > > "element_size": 10485888, "element_state": "Busy"},  \
> > > "element.2": {"msl_id": 1, "ms_id": 15,              \
> > > "memseg_start_addr": "0xb20000000",                  \
> > > "memseg_end_addr": "0xb40000000",                    \
> > > "element_start_addr": "0xb20bfe700",                 \
> > > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > > "element_state": "Busy"}, "Element_count": 2}}  
> > 
> > How this request is going to be used?
> > Elements don't have permanent IDs like MSL/memseg index or heap ID.
> > Heap layout may change between /eal/element_list and this request.  
> 
> Idea here was to print information related to memory element. This information
> Can be printed for a single element or for a range of elements.

I understand what this request does, the question is: what info the user has
initially, what they want to learn, and whether the request helps them.
For example, if the user wants to understand
which elements hold the known hugepage from being freed,
then your request is good as it is.
On the other hand, if the user initially has an address from some debug print
and wants to know if it's free, and if not, what's there,
then my suggestion about query by address is more suitable.
Or maybe both are good to have eventually.
 
> > Maybe instead there should be a filter by address with maybe a context
> > parameter (like "grep -C")?  
> 
> You mean that the user shall be able to grep for a memory address to check
> which element it belongs to ? If my understanding is correct, can I implement
> it as new request post rc2 and keep this request as-is?

Yes, this is what I mean.
AFAIU, rc1 is API freeze, and telemetry is API, so the new request must wait.
If the current request helps solving actual issues, of course let's have it.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v5 1/2] mem: telemetry support for memseg and element information
  2022-10-21 20:07         ` Dmitry Kozlyuk
@ 2022-10-25  7:25           ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-10-25  7:25 UTC (permalink / raw)
  To: Dmitry Kozlyuk
  Cc: Anatoly Burakov, dev, Jerin Jacob Kollanukkaran, david.marchand,
	bruce.richardson, ciara.power

Hi Dmitry,

Sure, will implement 2 new request (1. Msl properties, 2. Address lookup) in a separate patch. 
I will work on other review suggestions as part of v6.

Thanks,
Amit Shukla

> -----Original Message-----
> From: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
> Sent: Saturday, October 22, 2022 1:38 AM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>
> Cc: Anatoly Burakov <anatoly.burakov@intel.com>; dev@dpdk.org; Jerin
> Jacob Kollanukkaran <jerinj@marvell.com>; david.marchand@redhat.com;
> bruce.richardson@intel.com; ciara.power@intel.com
> Subject: Re: [EXT] Re: [PATCH v5 1/2] mem: telemetry support for memseg
> and element information
> 
> Hi Amit,
> 
> 2022-10-21 19:26 (UTC+0000), Amit Prakash Shukla:
> [...]
> > > How does the user learn heap_id?
> > > There probably should be /eal/heap_id returning a list of heap IDs.
> >
> > Request for list of active heap Id's is already present.
> > " /eal/heap_list"
> 
> My bad!
> 
> > > > --> /eal/element_list,0,1,15
> > > > {"/eal/element_list": {"Element_count": 52}}
> > > >
> > > > 5. /eal/element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> > > >    <elem-start-id>,<elem-end-id>
> > > > The command outputs element information like element start
> > > > address, end address, to which memseg it belongs, element state,
> element size.
> > > > User can give a range of elements to be printed.
> > > > Example:
> > > > --> /eal/element_info,0,1,15,1,2
> > > > {"/eal/element_info": {"element.1": {"msl_id": 1,    \
> > > > "ms_id": 15, "memseg_start_addr": "0xb20000000",     \
> > > > "memseg_end_addr": "0xb40000000",                    \
> > > > "element_start_addr": "0xb201fe680",                 \
> > > > "element_end_addr": "0xb20bfe700",                   \
> > > > "element_size": 10485888, "element_state": "Busy"},  \
> > > > "element.2": {"msl_id": 1, "ms_id": 15,              \
> > > > "memseg_start_addr": "0xb20000000",                  \
> > > > "memseg_end_addr": "0xb40000000",                    \
> > > > "element_start_addr": "0xb20bfe700",                 \
> > > > "element_end_addr": "0xb215fe780", "element_size": 10485888, \
> > > > "element_state": "Busy"}, "Element_count": 2}}
> > >
> > > How this request is going to be used?
> > > Elements don't have permanent IDs like MSL/memseg index or heap ID.
> > > Heap layout may change between /eal/element_list and this request.
> >
> > Idea here was to print information related to memory element. This
> > information Can be printed for a single element or for a range of elements.
> 
> I understand what this request does, the question is: what info the user has
> initially, what they want to learn, and whether the request helps them.
> For example, if the user wants to understand which elements hold the
> known hugepage from being freed, then your request is good as it is.
> On the other hand, if the user initially has an address from some debug print
> and wants to know if it's free, and if not, what's there, then my suggestion
> about query by address is more suitable.
> Or maybe both are good to have eventually.
> 
> > > Maybe instead there should be a filter by address with maybe a
> > > context parameter (like "grep -C")?
> >
> > You mean that the user shall be able to grep for a memory address to
> > check which element it belongs to ? If my understanding is correct,
> > can I implement it as new request post rc2 and keep this request as-is?
> 
> Yes, this is what I mean.
> AFAIU, rc1 is API freeze, and telemetry is API, so the new request must wait.
> If the current request helps solving actual issues, of course let's have it.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v6] mem: telemetry support for memseg and element information
  2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
                       ` (3 preceding siblings ...)
  2022-10-20 11:40     ` Dmitry Kozlyuk
@ 2022-10-25 11:51     ` Amit Prakash Shukla
  2022-10-25 13:02       ` [PATCH v7] " Amit Prakash Shukla
  4 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-10-25 11:51 UTC (permalink / raw)
  To: Anatoly Burakov
  Cc: dev, jerinj, david.marchand, bruce.richardson, ciara.power,
	dmitry.kozliuk, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/memseg_lists
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/memseg_lists
{"/eal/memseg_lists": [0, 1]}

2. /eal/memseg_list_info,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input.
Example:
--> /eal/memseg_list_info,0
{"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
 12, 13, 14, 15]}

3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input.
Example:
--> /eal/memseg_info,0,10
{"/eal/memseg_info": {"Memseg_list_index": 0, \
"Memseg_index": 10, "Start_addr": "0x101600000", \
"End_addr": "0x101800000", "Size": 2097152, "Hugepage_size": 2097152, \
"Socket_id": 0, "flags": 0}}

--> /eal/memseg_info,0,15
{"/eal/memseg_info": {"Memseg_list_index": 0, "Memseg_index": 15, \
"Start_addr": "0x102000000", "End_addr": "0x102200000", \
"Size": 2097152, "Hugepage_size": 2097152, "Socket_id": 0, "flags": 0}}

4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Example:
--> /eal/mem_element_list,0,0,10
{"/eal/mem_element_list": {"Element_count": 52}}

--> /eal/mem_element_list,0,1,15
{"/eal/mem_element_list": {"Element_count": 52}}

5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
   <elem-start-id>,<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed.
Example:
--> /eal/mem_element_info,0,0,15,1,2
{"/eal/mem_element_info": {"element_1": {"msl_id": 0, "ms_id": 15, \
"memseg_start_addr": "0x102000000", "memseg_end_addr": "0x102200000", \
"element_start_addr": "0x102000b00", "element_end_addr": "0x102003380", \
"element_size": 10368, "element_state": "Busy"}, "element_2": \
{"msl_id": 0, "ms_id": 15, "memseg_start_addr": "0x102000000", \
"memseg_end_addr": "0x102200000", "element_start_addr": "0x102003380", \
"element_end_addr": "0x102005c00", "element_size": 10368, \
"element_state": "Busy"}, "Element_count": 2}}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Fixed compilation error related int-to-pointer-cast
- Changes for code review suggestions

v3:
- Commit message changes
- Renaming end-points
- Changing input parameters to comma-seperated
- Reverting telemetry output buffer size

v4:
- Patch-2 adds telemetry support to display system memory

v5:
- Removed command help related changes

v6:
- Changes for code review suggestions
- Dropped Patch-2 from the series

 lib/eal/common/eal_common_memory.c | 387 ++++++++++++++++++++++++++++-
 1 file changed, 382 insertions(+), 5 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 688dc615d7..f43dbf2f12 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -3,6 +3,7 @@
  */
 
 #include <errno.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -26,6 +27,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1113,11 +1115,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_LISTS_REQ		"/eal/memseg_lists"
+#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ELEMENT_LIST_REQ		"/eal/mem_element_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/mem_element_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1265,6 +1273,358 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+/* n_vals is the number of params to be parsed. */
+static int
+parse_params(const char *params, uint32_t *vals, size_t n_vals)
+{
+	char dlim[2] = ",";
+	char *params_args;
+	size_t count = 0;
+	char *token;
+
+	if (vals == NULL || params == NULL || strlen(params) == 0)
+		return -1;
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	if (params_args == NULL)
+		return -1;
+
+	token = strtok(params_args, dlim);
+	while (token && isdigit(*token) && count < n_vals) {
+		vals[count++] = strtoul(token, NULL, 10);
+		token = strtok(NULL, dlim);
+	}
+
+	free(params_args);
+
+	if (count < n_vals)
+		return -1;
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_lists_request(const char *cmd __rte_unused,
+				const char *params __rte_unused,
+				struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
+				    const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	int ms_idx;
+	uint32_t vals[1]; /* size of an array == num params to be parsed. */
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	ms_list_idx = vals[0];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size, hugepage_size;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	int32_t ms_socket_id;
+	uint32_t ms_flags;
+	uint32_t vals[2]; /* size of an array == num params to be parsed. */
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	ms_list_idx = vals[0];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[1];
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->len;
+	hugepage_size = ms->hugepage_sz;
+	ms_socket_id = ms->socket_id;
+	ms_flags = ms->flags;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_u64(d, "Size", ms_size);
+	rte_tel_data_add_dict_u64(d, "Hugepage_size", hugepage_size);
+	rte_tel_data_add_dict_int(d, "Socket_id", ms_socket_id);
+	rte_tel_data_add_dict_int(d, "flags", ms_flags);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	int elem_count = 0;
+	uint32_t vals[3]; /* size of an array == num params to be parsed. */
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	heap_id = vals[0];
+	if (heap_id >= RTE_MAX_HEAPS)
+		return -1;
+
+	ms_list_idx = vals[1];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[2];
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char str[ADDR_STR];
+	uint32_t vals[5]; /* size of an array == num params to be parsed. */
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	heap_id = vals[0];
+	if (heap_id >= RTE_MAX_HEAPS)
+		return -1;
+
+	ms_list_idx = vals[1];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[2];
+	start_elem = vals[3];
+	end_elem = vals[4];
+
+	if (end_elem < start_elem)
+		return -1;
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		rte_tel_data_start_dict(c);
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s_%u", "element", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1279,5 +1639,22 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LISTS_REQ,
+			handle_eal_memseg_lists_request,
+			"Returns array of memseg list IDs. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_INFO_REQ,
+			handle_eal_memseg_list_info_request,
+			"Returns memseg list info. Parameters: int memseg_list_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns memseg info. Parameter: int memseg_list_id,int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns array of heap element IDs. Parameters: int heap_id, int memseg_list_id, int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element info. Parameters: int heap_id, int memseg_list_id, int memseg_id, int start_elem_id, int end_elem_id");
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v7] mem: telemetry support for memseg and element information
  2022-10-25 11:51     ` [PATCH v6] " Amit Prakash Shukla
@ 2022-10-25 13:02       ` Amit Prakash Shukla
  2022-12-06 11:46         ` Amit Prakash Shukla
                           ` (3 more replies)
  0 siblings, 4 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-10-25 13:02 UTC (permalink / raw)
  To: Anatoly Burakov
  Cc: dev, jerinj, david.marchand, bruce.richardson, ciara.power,
	dmitry.kozliuk, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/memseg_lists
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/memseg_lists
{"/eal/memseg_lists": [0, 1]}

2. /eal/memseg_list_info,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input.
Example:
--> /eal/memseg_list_info,0
{"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
 12, 13, 14, 15]}

3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input.
Example:
--> /eal/memseg_info,0,10
{"/eal/memseg_info": {"Memseg_list_index": 0, \
"Memseg_index": 10, "Start_addr": "0x101600000", \
"End_addr": "0x101800000", "Size": 2097152, "Hugepage_size": 2097152, \
"Socket_id": 0, "flags": 0}}

--> /eal/memseg_info,0,15
{"/eal/memseg_info": {"Memseg_list_index": 0, "Memseg_index": 15, \
"Start_addr": "0x102000000", "End_addr": "0x102200000", \
"Size": 2097152, "Hugepage_size": 2097152, "Socket_id": 0, "flags": 0}}

4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Example:
--> /eal/mem_element_list,0,0,10
{"/eal/mem_element_list": {"Element_count": 52}}

--> /eal/mem_element_list,0,1,15
{"/eal/mem_element_list": {"Element_count": 52}}

5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
   <elem-start-id>,<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed.
Example:
--> /eal/mem_element_info,0,0,15,1,2
{"/eal/mem_element_info": {"element_1": {"msl_id": 0, "ms_id": 15, \
"memseg_start_addr": "0x102000000", "memseg_end_addr": "0x102200000", \
"element_start_addr": "0x102000b00", "element_end_addr": "0x102003380", \
"element_size": 10368, "element_state": "Busy"}, "element_2": \
{"msl_id": 0, "ms_id": 15, "memseg_start_addr": "0x102000000", \
"memseg_end_addr": "0x102200000", "element_start_addr": "0x102003380", \
"element_end_addr": "0x102005c00", "element_size": 10368, \
"element_state": "Busy"}, "Element_count": 2}}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Fixed compilation error related int-to-pointer-cast
- Changes for code review suggestions

v3:
- Commit message changes
- Renaming end-points
- Changing input parameters to comma-seperated
- Reverting telemetry output buffer size

v4:
- Patch-2 adds telemetry support to display system memory

v5:
- Removed command help related changes

v6:
- Changes for code review suggestions
- Dropped Patch-2 from the series

v7:
- Fixed compilation error

 lib/eal/common/eal_common_memory.c | 391 ++++++++++++++++++++++++++++-
 1 file changed, 386 insertions(+), 5 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index 688dc615d7..bce18046ce 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -3,6 +3,7 @@
  */
 
 #include <errno.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -26,6 +27,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1113,11 +1115,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_LISTS_REQ		"/eal/memseg_lists"
+#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ELEMENT_LIST_REQ		"/eal/mem_element_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/mem_element_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1265,6 +1273,362 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+/* n_vals is the number of params to be parsed. */
+static int
+parse_params(const char *params, uint32_t *vals, size_t n_vals)
+{
+	char dlim[2] = ",";
+	char *params_args;
+	size_t count = 0;
+	char *token;
+
+	if (vals == NULL || params == NULL || strlen(params) == 0)
+		return -1;
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	if (params_args == NULL)
+		return -1;
+
+	token = strtok(params_args, dlim);
+	while (token && isdigit(*token) && count < n_vals) {
+		vals[count++] = strtoul(token, NULL, 10);
+		token = strtok(NULL, dlim);
+	}
+
+	free(params_args);
+
+	if (count < n_vals)
+		return -1;
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_lists_request(const char *cmd __rte_unused,
+				const char *params __rte_unused,
+				struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
+				    const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	int ms_idx;
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[1] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	ms_list_idx = vals[0];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size, hugepage_size;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	int32_t ms_socket_id;
+	uint32_t ms_flags;
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[2] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	ms_list_idx = vals[0];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[1];
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->len;
+	hugepage_size = ms->hugepage_sz;
+	ms_socket_id = ms->socket_id;
+	ms_flags = ms->flags;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_u64(d, "Size", ms_size);
+	rte_tel_data_add_dict_u64(d, "Hugepage_size", hugepage_size);
+	rte_tel_data_add_dict_int(d, "Socket_id", ms_socket_id);
+	rte_tel_data_add_dict_int(d, "flags", ms_flags);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	int elem_count = 0;
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[3] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	heap_id = vals[0];
+	if (heap_id >= RTE_MAX_HEAPS)
+		return -1;
+
+	ms_list_idx = vals[1];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[2];
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char str[ADDR_STR];
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[5] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	heap_id = vals[0];
+	if (heap_id >= RTE_MAX_HEAPS)
+		return -1;
+
+	ms_list_idx = vals[1];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[2];
+	start_elem = vals[3];
+	end_elem = vals[4];
+
+	if (end_elem < start_elem)
+		return -1;
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		rte_tel_data_start_dict(c);
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s_%u", "element", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1279,5 +1643,22 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LISTS_REQ,
+			handle_eal_memseg_lists_request,
+			"Returns array of memseg list IDs. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_INFO_REQ,
+			handle_eal_memseg_list_info_request,
+			"Returns memseg list info. Parameters: int memseg_list_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns memseg info. Parameter: int memseg_list_id,int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns array of heap element IDs. Parameters: int heap_id, int memseg_list_id, int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element info. Parameters: int heap_id, int memseg_list_id, int memseg_id, int start_elem_id, int end_elem_id");
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v7] mem: telemetry support for memseg and element information
  2022-10-25 13:02       ` [PATCH v7] " Amit Prakash Shukla
@ 2022-12-06 11:46         ` Amit Prakash Shukla
  2023-01-30 10:18           ` Amit Prakash Shukla
  2023-02-20 11:10         ` Thomas Monjalon
                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2022-12-06 11:46 UTC (permalink / raw)
  To: david.marchand
  Cc: dev, Jerin Jacob Kollanukkaran, bruce.richardson, ciara.power,
	dmitry.kozliuk, Anatoly Burakov, Amit Prakash Shukla

Ping.

> -----Original Message-----
> From: Amit Prakash Shukla <amitprakashs@marvell.com>
> Sent: Tuesday, October 25, 2022 6:32 PM
> To: Anatoly Burakov <anatoly.burakov@intel.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> david.marchand@redhat.com; bruce.richardson@intel.com;
> ciara.power@intel.com; dmitry.kozliuk@gmail.com; Amit Prakash Shukla
> <amitprakashs@marvell.com>
> Subject: [PATCH v7] mem: telemetry support for memseg and element
> information
> 
> Changes adds telemetry support to display memory occupancy in memseg
> and the information of the elements allocated from a memseg based on
> arguments provided by user. This patch adds following endpoints:
> 
> 1. /eal/memseg_lists
> The command displays the memseg list from which the memory has been
> allocated.
> Example:
> --> /eal/memseg_lists
> {"/eal/memseg_lists": [0, 1]}
> 
> 2. /eal/memseg_list_info,<memseg-list-id>
> The command outputs the memsegs, from which the memory is allocated,
> for the memseg_list given as input.
> Example:
> --> /eal/memseg_list_info,0
> {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \  12, 13, 14, 15]}
> 
> 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> The command outputs the memseg information based on the memseg-list
> and the memseg-id given as input.
> Example:
> --> /eal/memseg_info,0,10
> {"/eal/memseg_info": {"Memseg_list_index": 0, \
> "Memseg_index": 10, "Start_addr": "0x101600000", \
> "End_addr": "0x101800000", "Size": 2097152, "Hugepage_size": 2097152, \
> "Socket_id": 0, "flags": 0}}
> 
> --> /eal/memseg_info,0,15
> {"/eal/memseg_info": {"Memseg_list_index": 0, "Memseg_index": 15, \
> "Start_addr": "0x102000000", "End_addr": "0x102200000", \
> "Size": 2097152, "Hugepage_size": 2097152, "Socket_id": 0, "flags": 0}}
> 
> 4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based on the heap-
> id, memseg-list-id and memseg-id given as input.
> Example:
> --> /eal/mem_element_list,0,0,10
> {"/eal/mem_element_list": {"Element_count": 52}}
> 
> --> /eal/mem_element_list,0,1,15
> {"/eal/mem_element_list": {"Element_count": 52}}
> 
> 5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>    <elem-start-id>,<elem-end-id>
> The command outputs element information like element start address, end
> address, to which memseg it belongs, element state, element size. User can
> give a range of elements to be printed.
> Example:
> --> /eal/mem_element_info,0,0,15,1,2
> {"/eal/mem_element_info": {"element_1": {"msl_id": 0, "ms_id": 15, \
> "memseg_start_addr": "0x102000000", "memseg_end_addr":
> "0x102200000", \
> "element_start_addr": "0x102000b00", "element_end_addr":
> "0x102003380", \
> "element_size": 10368, "element_state": "Busy"}, "element_2": \
> {"msl_id": 0, "ms_id": 15, "memseg_start_addr": "0x102000000", \
> "memseg_end_addr": "0x102200000", "element_start_addr":
> "0x102003380", \
> "element_end_addr": "0x102005c00", "element_size": 10368, \
> "element_state": "Busy"}, "Element_count": 2}}
> 
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Fixed compilation error related int-to-pointer-cast
> - Changes for code review suggestions
> 
> v3:
> - Commit message changes
> - Renaming end-points
> - Changing input parameters to comma-seperated
> - Reverting telemetry output buffer size
> 
> v4:
> - Patch-2 adds telemetry support to display system memory
> 
> v5:
> - Removed command help related changes
> 
> v6:
> - Changes for code review suggestions
> - Dropped Patch-2 from the series
> 
> v7:
> - Fixed compilation error
> 
>  lib/eal/common/eal_common_memory.c | 391
> ++++++++++++++++++++++++++++-
>  1 file changed, 386 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/eal/common/eal_common_memory.c
> b/lib/eal/common/eal_common_memory.c
> index 688dc615d7..bce18046ce 100644
> --- a/lib/eal/common/eal_common_memory.c
> +++ b/lib/eal/common/eal_common_memory.c
> @@ -3,6 +3,7 @@
>   */
> 
>  #include <errno.h>
> +#include <ctype.h>
>  #include <stdio.h>
>  #include <stdint.h>
>  #include <stdlib.h>
> @@ -26,6 +27,7 @@
>  #include "eal_memcfg.h"
>  #include "eal_options.h"
>  #include "malloc_heap.h"
> +#include "malloc_elem.h"
> 
>  /*
>   * Try to mmap *size bytes in /dev/zero. If it is successful, return the @@ -
> 1113,11 +1115,17 @@ rte_eal_memory_init(void)  }
> 
>  #ifndef RTE_EXEC_ENV_WINDOWS
> -#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
> -#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
> -#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
> -#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
> -#define ADDR_STR		15
> +#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
> +#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
> +#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
> +#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
> +#define EAL_MEMSEG_LISTS_REQ		"/eal/memseg_lists"
> +#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
> +#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
> +#define EAL_ELEMENT_LIST_REQ		"/eal/mem_element_list"
> +#define EAL_ELEMENT_INFO_REQ		"/eal/mem_element_info"
> +#define ADDR_STR			15
> +
> 
>  /* Telemetry callback handler to return heap stats for requested heap id. */
> static int @@ -1265,6 +1273,362 @@
> handle_eal_memzone_list_request(const char *cmd __rte_unused,
>  	return 0;
>  }
> 
> +/* n_vals is the number of params to be parsed. */ static int
> +parse_params(const char *params, uint32_t *vals, size_t n_vals) {
> +	char dlim[2] = ",";
> +	char *params_args;
> +	size_t count = 0;
> +	char *token;
> +
> +	if (vals == NULL || params == NULL || strlen(params) == 0)
> +		return -1;
> +
> +	/* strtok expects char * and param is const char *. Hence on using
> +	 * params as "const char *" compiler throws warning.
> +	 */
> +	params_args = strdup(params);
> +	if (params_args == NULL)
> +		return -1;
> +
> +	token = strtok(params_args, dlim);
> +	while (token && isdigit(*token) && count < n_vals) {
> +		vals[count++] = strtoul(token, NULL, 10);
> +		token = strtok(NULL, dlim);
> +	}
> +
> +	free(params_args);
> +
> +	if (count < n_vals)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_memseg_lists_request(const char *cmd __rte_unused,
> +				const char *params __rte_unused,
> +				struct rte_tel_data *d)
> +{
> +	struct rte_mem_config *mcfg;
> +	int i;
> +
> +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +	rte_mcfg_mem_read_lock();
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +
> +	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
> +		struct rte_memseg_list *msl = &mcfg->memsegs[i];
> +		if (msl->memseg_arr.count == 0)
> +			continue;
> +
> +		rte_tel_data_add_array_int(d, i);
> +	}
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
> +				    const char *params, struct rte_tel_data *d)
> {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	struct rte_fbarray *arr;
> +	uint32_t ms_list_idx;
> +	int ms_idx;
> +	/* size of an array == num params to be parsed. */
> +	uint32_t vals[1] = {0};
> +
> +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> +		return -1;
> +
> +	ms_list_idx = vals[0];
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> +		return -1;
> +
> +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> +
> +	rte_mcfg_mem_read_lock();
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	if (msl->memseg_arr.count == 0)
> +		goto done;
> +
> +	arr = &msl->memseg_arr;
> +
> +	ms_idx = rte_fbarray_find_next_used(arr, 0);
> +	while (ms_idx >= 0) {
> +		rte_tel_data_add_array_int(d, ms_idx);
> +		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
> +	}
> +
> +done:
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> +			       const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	uint64_t ms_start_addr, ms_end_addr, ms_size, hugepage_size;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct rte_fbarray *arr;
> +	char addr[ADDR_STR];
> +	uint32_t ms_list_idx = 0;
> +	uint32_t ms_idx = 0;
> +	int32_t ms_socket_id;
> +	uint32_t ms_flags;
> +	/* size of an array == num params to be parsed. */
> +	uint32_t vals[2] = {0};
> +
> +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> +		return -1;
> +
> +	ms_list_idx = vals[0];
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> +		return -1;
> +
> +	ms_idx = vals[1];
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	if (msl->memseg_arr.count == 0) {
> +		rte_mcfg_mem_read_unlock();
> +		return -1;
> +	}
> +
> +	arr = &msl->memseg_arr;
> +	ms = rte_fbarray_get(arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +	ms_size = ms->len;
> +	hugepage_size = ms->hugepage_sz;
> +	ms_socket_id = ms->socket_id;
> +	ms_flags = ms->flags;
> +
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> +	rte_tel_data_add_dict_u64(d, "Size", ms_size);
> +	rte_tel_data_add_dict_u64(d, "Hugepage_size", hugepage_size);
> +	rte_tel_data_add_dict_int(d, "Socket_id", ms_socket_id);
> +	rte_tel_data_add_dict_int(d, "flags", ms_flags);
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_element_list_request(const char *cmd __rte_unused,
> +				const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct malloc_elem *elem;
> +	struct malloc_heap *heap;
> +	uint64_t ms_start_addr, ms_end_addr;
> +	uint64_t elem_start_addr, elem_end_addr;
> +	uint32_t ms_list_idx = 0;
> +	uint32_t heap_id = 0;
> +	uint32_t ms_idx = 0;
> +	int elem_count = 0;
> +	/* size of an array == num params to be parsed. */
> +	uint32_t vals[3] = {0};
> +
> +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> +		return -1;
> +
> +	heap_id = vals[0];
> +	if (heap_id >= RTE_MAX_HEAPS)
> +		return -1;
> +
> +	ms_list_idx = vals[1];
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> +		return -1;
> +
> +	ms_idx = vals[2];
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +
> +	heap = &mcfg->malloc_heaps[heap_id];
> +	rte_spinlock_lock(&heap->lock);
> +
> +	elem = heap->first;
> +	while (elem) {
> +		elem_start_addr = (uint64_t)elem;
> +		elem_end_addr =
> +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> >size);
> +
> +		if ((uint64_t)elem_start_addr >= ms_start_addr &&
> +		    (uint64_t)elem_end_addr <= ms_end_addr)
> +			elem_count++;
> +		elem = elem->next;
> +	}
> +
> +	rte_spinlock_unlock(&heap->lock);
> +
> +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> +
> +	return 0;
> +}
> +
> +static int
> +handle_eal_element_info_request(const char *cmd __rte_unused,
> +				const char *params, struct rte_tel_data *d) {
> +	struct rte_mem_config *mcfg;
> +	struct rte_memseg_list *msl;
> +	const struct rte_memseg *ms;
> +	struct malloc_elem *elem;
> +	struct malloc_heap *heap;
> +	struct rte_tel_data *c;
> +	uint64_t ms_start_addr, ms_end_addr;
> +	uint64_t elem_start_addr, elem_end_addr;
> +	uint32_t ms_list_idx = 0;
> +	uint32_t heap_id = 0;
> +	uint32_t ms_idx = 0;
> +	uint32_t start_elem = 0, end_elem = 0;
> +	uint32_t count = 0, elem_count = 0;
> +	char str[ADDR_STR];
> +	/* size of an array == num params to be parsed. */
> +	uint32_t vals[5] = {0};
> +
> +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> +		return -1;
> +
> +	heap_id = vals[0];
> +	if (heap_id >= RTE_MAX_HEAPS)
> +		return -1;
> +
> +	ms_list_idx = vals[1];
> +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> +		return -1;
> +
> +	ms_idx = vals[2];
> +	start_elem = vals[3];
> +	end_elem = vals[4];
> +
> +	if (end_elem < start_elem)
> +		return -1;
> +
> +	rte_mcfg_mem_read_lock();
> +
> +	mcfg = rte_eal_get_configuration()->mem_config;
> +	msl = &mcfg->memsegs[ms_list_idx];
> +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> +	if (ms == NULL) {
> +		rte_mcfg_mem_read_unlock();
> +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> memseg.\n");
> +		return -1;
> +	}
> +
> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +
> +	heap = &mcfg->malloc_heaps[heap_id];
> +	rte_spinlock_lock(&heap->lock);
> +
> +	elem = heap->first;
> +	while (elem) {
> +		elem_start_addr = (uint64_t)elem;
> +		elem_end_addr =
> +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> >size);
> +
> +		if (elem_start_addr < ms_start_addr ||
> +				elem_end_addr > ms_end_addr) {
> +			elem = elem->next;
> +			continue;
> +		}
> +
> +		if (count < start_elem) {
> +			elem = elem->next;
> +			count++;
> +			continue;
> +		}
> +
> +		c = rte_tel_data_alloc();
> +		if (c == NULL)
> +			break;
> +
> +		rte_tel_data_start_dict(c);
> +		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
> +		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> +		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> +		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
> +		rte_tel_data_add_dict_string(c, "element_start_addr", str);
> +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
> +		rte_tel_data_add_dict_string(c, "element_end_addr", str);
> +		rte_tel_data_add_dict_int(c, "element_size", elem->size);
> +		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
> +			 elem->state == 1 ? "Busy" : elem->state == 2 ?
> +			 "Pad" : "Error");
> +		rte_tel_data_add_dict_string(c, "element_state", str);
> +
> +		snprintf(str, ADDR_STR, "%s_%u", "element", count);
> +		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
> +			rte_tel_data_free(c);
> +			break;
> +		}
> +
> +		elem_count++;
> +		count++;
> +		if (count > end_elem)
> +			break;
> +
> +		elem = elem->next;
> +	}
> +
> +	rte_spinlock_unlock(&heap->lock);
> +
> +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> +
> +	return 0;
> +}
> +
>  RTE_INIT(memory_telemetry)
>  {
>  	rte_telemetry_register_cmd(
> @@ -1279,5 +1643,22 @@ RTE_INIT(memory_telemetry)
>  	rte_telemetry_register_cmd(
>  			EAL_HEAP_INFO_REQ,
> handle_eal_heap_info_request,
>  			"Returns malloc heap stats. Parameters: int
> heap_id");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LISTS_REQ,
> +			handle_eal_memseg_lists_request,
> +			"Returns array of memseg list IDs. Takes no
> parameters");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_LIST_INFO_REQ,
> +			handle_eal_memseg_list_info_request,
> +			"Returns memseg list info. Parameters: int
> memseg_list_id");
> +	rte_telemetry_register_cmd(
> +			EAL_MEMSEG_INFO_REQ,
> handle_eal_memseg_info_request,
> +			"Returns memseg info. Parameter: int
> memseg_list_id,int memseg_id");
> +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> +			handle_eal_element_list_request,
> +			"Returns array of heap element IDs. Parameters: int
> heap_id, int memseg_list_id, int memseg_id");
> +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> +			handle_eal_element_info_request,
> +			"Returns element info. Parameters: int heap_id, int
> memseg_list_id,
> +int memseg_id, int start_elem_id, int end_elem_id");
>  }
>  #endif
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [PATCH v7] mem: telemetry support for memseg and element information
  2022-12-06 11:46         ` Amit Prakash Shukla
@ 2023-01-30 10:18           ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2023-01-30 10:18 UTC (permalink / raw)
  To: david.marchand
  Cc: dev, Jerin Jacob Kollanukkaran, bruce.richardson, ciara.power,
	dmitry.kozliuk, Anatoly Burakov

Ping.

> -----Original Message-----
> From: Amit Prakash Shukla
> Sent: Tuesday, December 6, 2022 5:17 PM
> To: david.marchand@redhat.com
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> bruce.richardson@intel.com; ciara.power@intel.com;
> dmitry.kozliuk@gmail.com; Anatoly Burakov <anatoly.burakov@intel.com>;
> Amit Prakash Shukla <amitprakashs@marvell.com>
> Subject: RE: [PATCH v7] mem: telemetry support for memseg and element
> information
> 
> Ping.
> 
> > -----Original Message-----
> > From: Amit Prakash Shukla <amitprakashs@marvell.com>
> > Sent: Tuesday, October 25, 2022 6:32 PM
> > To: Anatoly Burakov <anatoly.burakov@intel.com>
> > Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> > david.marchand@redhat.com; bruce.richardson@intel.com;
> > ciara.power@intel.com; dmitry.kozliuk@gmail.com; Amit Prakash Shukla
> > <amitprakashs@marvell.com>
> > Subject: [PATCH v7] mem: telemetry support for memseg and element
> > information
> >
> > Changes adds telemetry support to display memory occupancy in memseg
> > and the information of the elements allocated from a memseg based on
> > arguments provided by user. This patch adds following endpoints:
> >
> > 1. /eal/memseg_lists
> > The command displays the memseg list from which the memory has been
> > allocated.
> > Example:
> > --> /eal/memseg_lists
> > {"/eal/memseg_lists": [0, 1]}
> >
> > 2. /eal/memseg_list_info,<memseg-list-id>
> > The command outputs the memsegs, from which the memory is allocated,
> > for the memseg_list given as input.
> > Example:
> > --> /eal/memseg_list_info,0
> > {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
> > 12, 13, 14, 15]}
> >
> > 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> > The command outputs the memseg information based on the memseg-list
> > and the memseg-id given as input.
> > Example:
> > --> /eal/memseg_info,0,10
> > {"/eal/memseg_info": {"Memseg_list_index": 0, \
> > "Memseg_index": 10, "Start_addr": "0x101600000", \
> > "End_addr": "0x101800000", "Size": 2097152, "Hugepage_size": 2097152,
> > \
> > "Socket_id": 0, "flags": 0}}
> >
> > --> /eal/memseg_info,0,15
> > {"/eal/memseg_info": {"Memseg_list_index": 0, "Memseg_index": 15, \
> > "Start_addr": "0x102000000", "End_addr": "0x102200000", \
> > "Size": 2097152, "Hugepage_size": 2097152, "Socket_id": 0, "flags":
> > 0}}
> >
> > 4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> > The command outputs number of elements in a memseg based on the
> heap-
> > id, memseg-list-id and memseg-id given as input.
> > Example:
> > --> /eal/mem_element_list,0,0,10
> > {"/eal/mem_element_list": {"Element_count": 52}}
> >
> > --> /eal/mem_element_list,0,1,15
> > {"/eal/mem_element_list": {"Element_count": 52}}
> >
> > 5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> >    <elem-start-id>,<elem-end-id>
> > The command outputs element information like element start address,
> > end address, to which memseg it belongs, element state, element size.
> > User can give a range of elements to be printed.
> > Example:
> > --> /eal/mem_element_info,0,0,15,1,2
> > {"/eal/mem_element_info": {"element_1": {"msl_id": 0, "ms_id": 15, \
> > "memseg_start_addr": "0x102000000", "memseg_end_addr":
> > "0x102200000", \
> > "element_start_addr": "0x102000b00", "element_end_addr":
> > "0x102003380", \
> > "element_size": 10368, "element_state": "Busy"}, "element_2": \
> > {"msl_id": 0, "ms_id": 15, "memseg_start_addr": "0x102000000", \
> > "memseg_end_addr": "0x102200000", "element_start_addr":
> > "0x102003380", \
> > "element_end_addr": "0x102005c00", "element_size": 10368, \
> > "element_state": "Busy"}, "Element_count": 2}}
> >
> > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> > ---
> > v2:
> > - Fixed compilation error related int-to-pointer-cast
> > - Changes for code review suggestions
> >
> > v3:
> > - Commit message changes
> > - Renaming end-points
> > - Changing input parameters to comma-seperated
> > - Reverting telemetry output buffer size
> >
> > v4:
> > - Patch-2 adds telemetry support to display system memory
> >
> > v5:
> > - Removed command help related changes
> >
> > v6:
> > - Changes for code review suggestions
> > - Dropped Patch-2 from the series
> >
> > v7:
> > - Fixed compilation error
> >
> >  lib/eal/common/eal_common_memory.c | 391
> > ++++++++++++++++++++++++++++-
> >  1 file changed, 386 insertions(+), 5 deletions(-)
> >
> > diff --git a/lib/eal/common/eal_common_memory.c
> > b/lib/eal/common/eal_common_memory.c
> > index 688dc615d7..bce18046ce 100644
> > --- a/lib/eal/common/eal_common_memory.c
> > +++ b/lib/eal/common/eal_common_memory.c
> > @@ -3,6 +3,7 @@
> >   */
> >
> >  #include <errno.h>
> > +#include <ctype.h>
> >  #include <stdio.h>
> >  #include <stdint.h>
> >  #include <stdlib.h>
> > @@ -26,6 +27,7 @@
> >  #include "eal_memcfg.h"
> >  #include "eal_options.h"
> >  #include "malloc_heap.h"
> > +#include "malloc_elem.h"
> >
> >  /*
> >   * Try to mmap *size bytes in /dev/zero. If it is successful, return
> > the @@ -
> > 1113,11 +1115,17 @@ rte_eal_memory_init(void)  }
> >
> >  #ifndef RTE_EXEC_ENV_WINDOWS
> > -#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
> > -#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
> > -#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
> > -#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
> > -#define ADDR_STR		15
> > +#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
> > +#define EAL_MEMZONE_INFO_REQ
> 	"/eal/memzone_info"
> > +#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
> > +#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
> > +#define EAL_MEMSEG_LISTS_REQ		"/eal/memseg_lists"
> > +#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
> > +#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
> > +#define EAL_ELEMENT_LIST_REQ		"/eal/mem_element_list"
> > +#define EAL_ELEMENT_INFO_REQ		"/eal/mem_element_info"
> > +#define ADDR_STR			15
> > +
> >
> >  /* Telemetry callback handler to return heap stats for requested heap
> > id. */ static int @@ -1265,6 +1273,362 @@
> > handle_eal_memzone_list_request(const char *cmd __rte_unused,
> >  	return 0;
> >  }
> >
> > +/* n_vals is the number of params to be parsed. */ static int
> > +parse_params(const char *params, uint32_t *vals, size_t n_vals) {
> > +	char dlim[2] = ",";
> > +	char *params_args;
> > +	size_t count = 0;
> > +	char *token;
> > +
> > +	if (vals == NULL || params == NULL || strlen(params) == 0)
> > +		return -1;
> > +
> > +	/* strtok expects char * and param is const char *. Hence on using
> > +	 * params as "const char *" compiler throws warning.
> > +	 */
> > +	params_args = strdup(params);
> > +	if (params_args == NULL)
> > +		return -1;
> > +
> > +	token = strtok(params_args, dlim);
> > +	while (token && isdigit(*token) && count < n_vals) {
> > +		vals[count++] = strtoul(token, NULL, 10);
> > +		token = strtok(NULL, dlim);
> > +	}
> > +
> > +	free(params_args);
> > +
> > +	if (count < n_vals)
> > +		return -1;
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_memseg_lists_request(const char *cmd __rte_unused,
> > +				const char *params __rte_unused,
> > +				struct rte_tel_data *d)
> > +{
> > +	struct rte_mem_config *mcfg;
> > +	int i;
> > +
> > +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> > +
> > +	rte_mcfg_mem_read_lock();
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +
> > +	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
> > +		struct rte_memseg_list *msl = &mcfg->memsegs[i];
> > +		if (msl->memseg_arr.count == 0)
> > +			continue;
> > +
> > +		rte_tel_data_add_array_int(d, i);
> > +	}
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
> > +				    const char *params, struct rte_tel_data *d)
> > {
> > +	struct rte_mem_config *mcfg;
> > +	struct rte_memseg_list *msl;
> > +	struct rte_fbarray *arr;
> > +	uint32_t ms_list_idx;
> > +	int ms_idx;
> > +	/* size of an array == num params to be parsed. */
> > +	uint32_t vals[1] = {0};
> > +
> > +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> > +		return -1;
> > +
> > +	ms_list_idx = vals[0];
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> > +		return -1;
> > +
> > +	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
> > +
> > +	rte_mcfg_mem_read_lock();
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	if (msl->memseg_arr.count == 0)
> > +		goto done;
> > +
> > +	arr = &msl->memseg_arr;
> > +
> > +	ms_idx = rte_fbarray_find_next_used(arr, 0);
> > +	while (ms_idx >= 0) {
> > +		rte_tel_data_add_array_int(d, ms_idx);
> > +		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
> > +	}
> > +
> > +done:
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_memseg_info_request(const char *cmd __rte_unused,
> > +			       const char *params, struct rte_tel_data *d) {
> > +	struct rte_mem_config *mcfg;
> > +	uint64_t ms_start_addr, ms_end_addr, ms_size, hugepage_size;
> > +	struct rte_memseg_list *msl;
> > +	const struct rte_memseg *ms;
> > +	struct rte_fbarray *arr;
> > +	char addr[ADDR_STR];
> > +	uint32_t ms_list_idx = 0;
> > +	uint32_t ms_idx = 0;
> > +	int32_t ms_socket_id;
> > +	uint32_t ms_flags;
> > +	/* size of an array == num params to be parsed. */
> > +	uint32_t vals[2] = {0};
> > +
> > +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> > +		return -1;
> > +
> > +	ms_list_idx = vals[0];
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> > +		return -1;
> > +
> > +	ms_idx = vals[1];
> > +
> > +	rte_mcfg_mem_read_lock();
> > +
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	if (msl->memseg_arr.count == 0) {
> > +		rte_mcfg_mem_read_unlock();
> > +		return -1;
> > +	}
> > +
> > +	arr = &msl->memseg_arr;
> > +	ms = rte_fbarray_get(arr, ms_idx);
> > +	if (ms == NULL) {
> > +		rte_mcfg_mem_read_unlock();
> > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > memseg.\n");
> > +		return -1;
> > +	}
> > +
> > +	ms_start_addr = ms->addr_64;
> > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > +	ms_size = ms->len;
> > +	hugepage_size = ms->hugepage_sz;
> > +	ms_socket_id = ms->socket_id;
> > +	ms_flags = ms->flags;
> > +
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	rte_tel_data_start_dict(d);
> > +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> > +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> > +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> > +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> > +	rte_tel_data_add_dict_u64(d, "Size", ms_size);
> > +	rte_tel_data_add_dict_u64(d, "Hugepage_size", hugepage_size);
> > +	rte_tel_data_add_dict_int(d, "Socket_id", ms_socket_id);
> > +	rte_tel_data_add_dict_int(d, "flags", ms_flags);
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_element_list_request(const char *cmd __rte_unused,
> > +				const char *params, struct rte_tel_data *d) {
> > +	struct rte_mem_config *mcfg;
> > +	struct rte_memseg_list *msl;
> > +	const struct rte_memseg *ms;
> > +	struct malloc_elem *elem;
> > +	struct malloc_heap *heap;
> > +	uint64_t ms_start_addr, ms_end_addr;
> > +	uint64_t elem_start_addr, elem_end_addr;
> > +	uint32_t ms_list_idx = 0;
> > +	uint32_t heap_id = 0;
> > +	uint32_t ms_idx = 0;
> > +	int elem_count = 0;
> > +	/* size of an array == num params to be parsed. */
> > +	uint32_t vals[3] = {0};
> > +
> > +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> > +		return -1;
> > +
> > +	heap_id = vals[0];
> > +	if (heap_id >= RTE_MAX_HEAPS)
> > +		return -1;
> > +
> > +	ms_list_idx = vals[1];
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> > +		return -1;
> > +
> > +	ms_idx = vals[2];
> > +
> > +	rte_mcfg_mem_read_lock();
> > +
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> > +	if (ms == NULL) {
> > +		rte_mcfg_mem_read_unlock();
> > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > memseg.\n");
> > +		return -1;
> > +	}
> > +
> > +	ms_start_addr = ms->addr_64;
> > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	rte_tel_data_start_dict(d);
> > +
> > +	heap = &mcfg->malloc_heaps[heap_id];
> > +	rte_spinlock_lock(&heap->lock);
> > +
> > +	elem = heap->first;
> > +	while (elem) {
> > +		elem_start_addr = (uint64_t)elem;
> > +		elem_end_addr =
> > +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> > >size);
> > +
> > +		if ((uint64_t)elem_start_addr >= ms_start_addr &&
> > +		    (uint64_t)elem_end_addr <= ms_end_addr)
> > +			elem_count++;
> > +		elem = elem->next;
> > +	}
> > +
> > +	rte_spinlock_unlock(&heap->lock);
> > +
> > +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_eal_element_info_request(const char *cmd __rte_unused,
> > +				const char *params, struct rte_tel_data *d) {
> > +	struct rte_mem_config *mcfg;
> > +	struct rte_memseg_list *msl;
> > +	const struct rte_memseg *ms;
> > +	struct malloc_elem *elem;
> > +	struct malloc_heap *heap;
> > +	struct rte_tel_data *c;
> > +	uint64_t ms_start_addr, ms_end_addr;
> > +	uint64_t elem_start_addr, elem_end_addr;
> > +	uint32_t ms_list_idx = 0;
> > +	uint32_t heap_id = 0;
> > +	uint32_t ms_idx = 0;
> > +	uint32_t start_elem = 0, end_elem = 0;
> > +	uint32_t count = 0, elem_count = 0;
> > +	char str[ADDR_STR];
> > +	/* size of an array == num params to be parsed. */
> > +	uint32_t vals[5] = {0};
> > +
> > +	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
> > +		return -1;
> > +
> > +	heap_id = vals[0];
> > +	if (heap_id >= RTE_MAX_HEAPS)
> > +		return -1;
> > +
> > +	ms_list_idx = vals[1];
> > +	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
> > +		return -1;
> > +
> > +	ms_idx = vals[2];
> > +	start_elem = vals[3];
> > +	end_elem = vals[4];
> > +
> > +	if (end_elem < start_elem)
> > +		return -1;
> > +
> > +	rte_mcfg_mem_read_lock();
> > +
> > +	mcfg = rte_eal_get_configuration()->mem_config;
> > +	msl = &mcfg->memsegs[ms_list_idx];
> > +	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
> > +	if (ms == NULL) {
> > +		rte_mcfg_mem_read_unlock();
> > +		RTE_LOG(DEBUG, EAL, "Error fetching requested
> > memseg.\n");
> > +		return -1;
> > +	}
> > +
> > +	ms_start_addr = ms->addr_64;
> > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > +
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	rte_tel_data_start_dict(d);
> > +
> > +	heap = &mcfg->malloc_heaps[heap_id];
> > +	rte_spinlock_lock(&heap->lock);
> > +
> > +	elem = heap->first;
> > +	while (elem) {
> > +		elem_start_addr = (uint64_t)elem;
> > +		elem_end_addr =
> > +			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem-
> > >size);
> > +
> > +		if (elem_start_addr < ms_start_addr ||
> > +				elem_end_addr > ms_end_addr) {
> > +			elem = elem->next;
> > +			continue;
> > +		}
> > +
> > +		if (count < start_elem) {
> > +			elem = elem->next;
> > +			count++;
> > +			continue;
> > +		}
> > +
> > +		c = rte_tel_data_alloc();
> > +		if (c == NULL)
> > +			break;
> > +
> > +		rte_tel_data_start_dict(c);
> > +		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
> > +		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> > +		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> > +		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
> > +		rte_tel_data_add_dict_string(c, "element_start_addr", str);
> > +		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
> > +		rte_tel_data_add_dict_string(c, "element_end_addr", str);
> > +		rte_tel_data_add_dict_int(c, "element_size", elem->size);
> > +		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
> > +			 elem->state == 1 ? "Busy" : elem->state == 2 ?
> > +			 "Pad" : "Error");
> > +		rte_tel_data_add_dict_string(c, "element_state", str);
> > +
> > +		snprintf(str, ADDR_STR, "%s_%u", "element", count);
> > +		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
> > +			rte_tel_data_free(c);
> > +			break;
> > +		}
> > +
> > +		elem_count++;
> > +		count++;
> > +		if (count > end_elem)
> > +			break;
> > +
> > +		elem = elem->next;
> > +	}
> > +
> > +	rte_spinlock_unlock(&heap->lock);
> > +
> > +	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
> > +
> > +	return 0;
> > +}
> > +
> >  RTE_INIT(memory_telemetry)
> >  {
> >  	rte_telemetry_register_cmd(
> > @@ -1279,5 +1643,22 @@ RTE_INIT(memory_telemetry)
> >  	rte_telemetry_register_cmd(
> >  			EAL_HEAP_INFO_REQ,
> > handle_eal_heap_info_request,
> >  			"Returns malloc heap stats. Parameters: int
> heap_id");
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_LISTS_REQ,
> > +			handle_eal_memseg_lists_request,
> > +			"Returns array of memseg list IDs. Takes no
> > parameters");
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_LIST_INFO_REQ,
> > +			handle_eal_memseg_list_info_request,
> > +			"Returns memseg list info. Parameters: int
> > memseg_list_id");
> > +	rte_telemetry_register_cmd(
> > +			EAL_MEMSEG_INFO_REQ,
> > handle_eal_memseg_info_request,
> > +			"Returns memseg info. Parameter: int
> > memseg_list_id,int memseg_id");
> > +	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
> > +			handle_eal_element_list_request,
> > +			"Returns array of heap element IDs. Parameters: int
> > heap_id, int memseg_list_id, int memseg_id");
> > +	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
> > +			handle_eal_element_info_request,
> > +			"Returns element info. Parameters: int heap_id, int
> > memseg_list_id,
> > +int memseg_id, int start_elem_id, int end_elem_id");
> >  }
> >  #endif
> > --
> > 2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v7] mem: telemetry support for memseg and element information
  2022-10-25 13:02       ` [PATCH v7] " Amit Prakash Shukla
  2022-12-06 11:46         ` Amit Prakash Shukla
@ 2023-02-20 11:10         ` Thomas Monjalon
  2023-02-28  7:30           ` [EXT] " Amit Prakash Shukla
  2023-05-16 10:47         ` Burakov, Anatoly
  2023-05-17  9:21         ` [PATCH v8] " Amit Prakash Shukla
  3 siblings, 1 reply; 42+ messages in thread
From: Thomas Monjalon @ 2023-02-20 11:10 UTC (permalink / raw)
  To: dev
  Cc: Anatoly Burakov, jerinj, david.marchand, bruce.richardson,
	ciara.power, dmitry.kozliuk, Amit Prakash Shukla

25/10/2022 15:02, Amit Prakash Shukla:
> Changes adds telemetry support to display memory occupancy
> in memseg and the information of the elements allocated from
> a memseg based on arguments provided by user.

There was no comment since October.
Can we merge?




^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v7] mem: telemetry support for memseg and element information
  2023-02-20 11:10         ` Thomas Monjalon
@ 2023-02-28  7:30           ` Amit Prakash Shukla
  2023-05-15 11:51             ` Amit Prakash Shukla
  0 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2023-02-28  7:30 UTC (permalink / raw)
  To: Thomas Monjalon, dev
  Cc: Anatoly Burakov, Jerin Jacob Kollanukkaran, david.marchand,
	bruce.richardson, ciara.power, dmitry.kozliuk

Hi Thomas,

No changes pending from my side.

Thanks,
Amit Shukla

> -----Original Message-----
> From: Thomas Monjalon <thomas@monjalon.net>
> Sent: Monday, February 20, 2023 4:41 PM
> To: dev@dpdk.org
> Cc: Anatoly Burakov <anatoly.burakov@intel.com>; Jerin Jacob
> Kollanukkaran <jerinj@marvell.com>; david.marchand@redhat.com;
> bruce.richardson@intel.com; ciara.power@intel.com;
> dmitry.kozliuk@gmail.com; Amit Prakash Shukla
> <amitprakashs@marvell.com>
> Subject: [EXT] Re: [PATCH v7] mem: telemetry support for memseg and
> element information
> 
> External Email
> 
> ----------------------------------------------------------------------
> 25/10/2022 15:02, Amit Prakash Shukla:
> > Changes adds telemetry support to display memory occupancy in memseg
> > and the information of the elements allocated from a memseg based on
> > arguments provided by user.
> 
> There was no comment since October.
> Can we merge?
> 
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v7] mem: telemetry support for memseg and element information
  2023-02-28  7:30           ` [EXT] " Amit Prakash Shukla
@ 2023-05-15 11:51             ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2023-05-15 11:51 UTC (permalink / raw)
  To: Amit Prakash Shukla, Thomas Monjalon, dev
  Cc: Anatoly Burakov, Jerin Jacob Kollanukkaran, david.marchand,
	bruce.richardson, ciara.power, dmitry.kozliuk

Hi Anatoly and David,

Could you review this patch, this is pending since October-22. If there are no comments, please accept the patch to make forward progress.

Thanks,
Amit Shukla

> -----Original Message-----
> From: Amit Prakash Shukla <amitprakashs@marvell.com>
> Sent: Tuesday, February 28, 2023 1:00 PM
> To: Thomas Monjalon <thomas@monjalon.net>; dev@dpdk.org
> Cc: Anatoly Burakov <anatoly.burakov@intel.com>; Jerin Jacob
> Kollanukkaran <jerinj@marvell.com>; david.marchand@redhat.com;
> bruce.richardson@intel.com; ciara.power@intel.com;
> dmitry.kozliuk@gmail.com
> Subject: RE: [EXT] Re: [PATCH v7] mem: telemetry support for memseg and
> element information
> 
> Hi Thomas,
> 
> No changes pending from my side.
> 
> Thanks,
> Amit Shukla
> 
> > -----Original Message-----
> > From: Thomas Monjalon <thomas@monjalon.net>
> > Sent: Monday, February 20, 2023 4:41 PM
> > To: dev@dpdk.org
> > Cc: Anatoly Burakov <anatoly.burakov@intel.com>; Jerin Jacob
> > Kollanukkaran <jerinj@marvell.com>; david.marchand@redhat.com;
> > bruce.richardson@intel.com; ciara.power@intel.com;
> > dmitry.kozliuk@gmail.com; Amit Prakash Shukla
> > <amitprakashs@marvell.com>
> > Subject: [EXT] Re: [PATCH v7] mem: telemetry support for memseg and
> > element information
> >
> > External Email
> >
> > ----------------------------------------------------------------------
> > 25/10/2022 15:02, Amit Prakash Shukla:
> > > Changes adds telemetry support to display memory occupancy in
> memseg
> > > and the information of the elements allocated from a memseg based on
> > > arguments provided by user.
> >
> > There was no comment since October.
> > Can we merge?
> >
> >


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v7] mem: telemetry support for memseg and element information
  2022-10-25 13:02       ` [PATCH v7] " Amit Prakash Shukla
  2022-12-06 11:46         ` Amit Prakash Shukla
  2023-02-20 11:10         ` Thomas Monjalon
@ 2023-05-16 10:47         ` Burakov, Anatoly
  2023-05-17  9:08           ` [EXT] " Amit Prakash Shukla
  2023-05-17  9:21         ` [PATCH v8] " Amit Prakash Shukla
  3 siblings, 1 reply; 42+ messages in thread
From: Burakov, Anatoly @ 2023-05-16 10:47 UTC (permalink / raw)
  To: Amit Prakash Shukla
  Cc: dev, jerinj, david.marchand, bruce.richardson, ciara.power,
	dmitry.kozliuk

On 10/25/2022 2:02 PM, Amit Prakash Shukla wrote:
> Changes adds telemetry support to display memory occupancy
> in memseg and the information of the elements allocated from
> a memseg based on arguments provided by user. This patch
> adds following endpoints:
> 
> 1. /eal/memseg_lists
> The command displays the memseg list from which the memory
> has been allocated.
> Example:
> --> /eal/memseg_lists
> {"/eal/memseg_lists": [0, 1]}
> 
> 2. /eal/memseg_list_info,<memseg-list-id>
> The command outputs the memsegs, from which the memory is
> allocated, for the memseg_list given as input.
> Example:
> --> /eal/memseg_list_info,0
> {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
>   12, 13, 14, 15]}
> 
> 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> The command outputs the memseg information based on the
> memseg-list and the memseg-id given as input.
> Example:
> --> /eal/memseg_info,0,10
> {"/eal/memseg_info": {"Memseg_list_index": 0, \
> "Memseg_index": 10, "Start_addr": "0x101600000", \
> "End_addr": "0x101800000", "Size": 2097152, "Hugepage_size": 2097152, \
> "Socket_id": 0, "flags": 0}}
> 
> --> /eal/memseg_info,0,15
> {"/eal/memseg_info": {"Memseg_list_index": 0, "Memseg_index": 15, \
> "Start_addr": "0x102000000", "End_addr": "0x102200000", \
> "Size": 2097152, "Hugepage_size": 2097152, "Socket_id": 0, "flags": 0}}
> 
> 4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based
> on the heap-id, memseg-list-id and memseg-id given as input.
> Example:
> --> /eal/mem_element_list,0,0,10
> {"/eal/mem_element_list": {"Element_count": 52}}
> 
> --> /eal/mem_element_list,0,1,15
> {"/eal/mem_element_list": {"Element_count": 52}}
> 
> 5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>     <elem-start-id>,<elem-end-id>
> The command outputs element information like element start
> address, end address, to which memseg it belongs, element
> state, element size. User can give a range of elements to be
> printed.
> Example:
> --> /eal/mem_element_info,0,0,15,1,2
> {"/eal/mem_element_info": {"element_1": {"msl_id": 0, "ms_id": 15, \
> "memseg_start_addr": "0x102000000", "memseg_end_addr": "0x102200000", \
> "element_start_addr": "0x102000b00", "element_end_addr": "0x102003380", \
> "element_size": 10368, "element_state": "Busy"}, "element_2": \
> {"msl_id": 0, "ms_id": 15, "memseg_start_addr": "0x102000000", \
> "memseg_end_addr": "0x102200000", "element_start_addr": "0x102003380", \
> "element_end_addr": "0x102005c00", "element_size": 10368, \
> "element_state": "Busy"}, "Element_count": 2}}
> 
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---



> +	ms_start_addr = ms->addr_64;
> +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> +	ms_size = ms->len;
> +	hugepage_size = ms->hugepage_sz;
> +	ms_socket_id = ms->socket_id;
> +	ms_flags = ms->flags;
> +
> +	rte_mcfg_mem_read_unlock();
> +
> +	rte_tel_data_start_dict(d);
> +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> +	rte_tel_data_add_dict_u64(d, "Size", ms_size);
> +	rte_tel_data_add_dict_u64(d, "Hugepage_size", hugepage_size);

Seems like rte_tel_data_add_dict_u64 is deprecated now.

I would also suggest outputting IOVA address for memsegs as well (unless 
it's set to RTE_BAD_IOVA, in which case it should say something 
meaningful too).

Otherwise (and with above changes), LGTM

Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
-- 
Thanks,
Anatoly


^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: [EXT] Re: [PATCH v7] mem: telemetry support for memseg and element information
  2023-05-16 10:47         ` Burakov, Anatoly
@ 2023-05-17  9:08           ` Amit Prakash Shukla
  0 siblings, 0 replies; 42+ messages in thread
From: Amit Prakash Shukla @ 2023-05-17  9:08 UTC (permalink / raw)
  To: Burakov, Anatoly
  Cc: dev, Jerin Jacob Kollanukkaran, david.marchand, bruce.richardson,
	ciara.power, dmitry.kozliuk

Thanks Anatoly for review and feedback. I will make the suggested changes in next version of the patch.

Thanks,
Amit Shukla

> -----Original Message-----
> From: Burakov, Anatoly <anatoly.burakov@intel.com>
> Sent: Tuesday, May 16, 2023 4:17 PM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>
> Cc: dev@dpdk.org; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> david.marchand@redhat.com; bruce.richardson@intel.com;
> ciara.power@intel.com; dmitry.kozliuk@gmail.com
> Subject: [EXT] Re: [PATCH v7] mem: telemetry support for memseg and
> element information
> 
> External Email
> 
> ----------------------------------------------------------------------
> On 10/25/2022 2:02 PM, Amit Prakash Shukla wrote:
> > Changes adds telemetry support to display memory occupancy in memseg
> > and the information of the elements allocated from a memseg based on
> > arguments provided by user. This patch adds following endpoints:
> >
> > 1. /eal/memseg_lists
> > The command displays the memseg list from which the memory has been
> > allocated.
> > Example:
> > --> /eal/memseg_lists
> > {"/eal/memseg_lists": [0, 1]}
> >
> > 2. /eal/memseg_list_info,<memseg-list-id>
> > The command outputs the memsegs, from which the memory is allocated,
> > for the memseg_list given as input.
> > Example:
> > --> /eal/memseg_list_info,0
> > {"/eal/memseg_list_info": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, \
> >   12, 13, 14, 15]}
> >
> > 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> > The command outputs the memseg information based on the memseg-list
> > and the memseg-id given as input.
> > Example:
> > --> /eal/memseg_info,0,10
> > {"/eal/memseg_info": {"Memseg_list_index": 0, \
> > "Memseg_index": 10, "Start_addr": "0x101600000", \
> > "End_addr": "0x101800000", "Size": 2097152, "Hugepage_size": 2097152,
> > \
> > "Socket_id": 0, "flags": 0}}
> >
> > --> /eal/memseg_info,0,15
> > {"/eal/memseg_info": {"Memseg_list_index": 0, "Memseg_index": 15, \
> > "Start_addr": "0x102000000", "End_addr": "0x102200000", \
> > "Size": 2097152, "Hugepage_size": 2097152, "Socket_id": 0, "flags":
> > 0}}
> >
> > 4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> > The command outputs number of elements in a memseg based on the
> > heap-id, memseg-list-id and memseg-id given as input.
> > Example:
> > --> /eal/mem_element_list,0,0,10
> > {"/eal/mem_element_list": {"Element_count": 52}}
> >
> > --> /eal/mem_element_list,0,1,15
> > {"/eal/mem_element_list": {"Element_count": 52}}
> >
> > 5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
> >     <elem-start-id>,<elem-end-id>
> > The command outputs element information like element start address,
> > end address, to which memseg it belongs, element state, element size.
> > User can give a range of elements to be printed.
> > Example:
> > --> /eal/mem_element_info,0,0,15,1,2
> > {"/eal/mem_element_info": {"element_1": {"msl_id": 0, "ms_id": 15, \
> > "memseg_start_addr": "0x102000000", "memseg_end_addr":
> "0x102200000",
> > \
> > "element_start_addr": "0x102000b00", "element_end_addr":
> > "0x102003380", \
> > "element_size": 10368, "element_state": "Busy"}, "element_2": \
> > {"msl_id": 0, "ms_id": 15, "memseg_start_addr": "0x102000000", \
> > "memseg_end_addr": "0x102200000", "element_start_addr":
> "0x102003380",
> > \
> > "element_end_addr": "0x102005c00", "element_size": 10368, \
> > "element_state": "Busy"}, "Element_count": 2}}
> >
> > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> > ---
> 
> 
> 
> > +	ms_start_addr = ms->addr_64;
> > +	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
> > +	ms_size = ms->len;
> > +	hugepage_size = ms->hugepage_sz;
> > +	ms_socket_id = ms->socket_id;
> > +	ms_flags = ms->flags;
> > +
> > +	rte_mcfg_mem_read_unlock();
> > +
> > +	rte_tel_data_start_dict(d);
> > +	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
> > +	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
> > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
> > +	rte_tel_data_add_dict_string(d, "Start_addr", addr);
> > +	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
> > +	rte_tel_data_add_dict_string(d, "End_addr", addr);
> > +	rte_tel_data_add_dict_u64(d, "Size", ms_size);
> > +	rte_tel_data_add_dict_u64(d, "Hugepage_size", hugepage_size);
> 
> Seems like rte_tel_data_add_dict_u64 is deprecated now.
> 
> I would also suggest outputting IOVA address for memsegs as well (unless it's
> set to RTE_BAD_IOVA, in which case it should say something meaningful
> too).
> 
> Otherwise (and with above changes), LGTM
> 
> Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
> --
> Thanks,
> Anatoly


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v8] mem: telemetry support for memseg and element information
  2022-10-25 13:02       ` [PATCH v7] " Amit Prakash Shukla
                           ` (2 preceding siblings ...)
  2023-05-16 10:47         ` Burakov, Anatoly
@ 2023-05-17  9:21         ` Amit Prakash Shukla
  2023-06-07 20:40           ` David Marchand
  3 siblings, 1 reply; 42+ messages in thread
From: Amit Prakash Shukla @ 2023-05-17  9:21 UTC (permalink / raw)
  To: anatoly.burakov, david.marchand; +Cc: dev, jerinj, Amit Prakash Shukla

Changes adds telemetry support to display memory occupancy
in memseg and the information of the elements allocated from
a memseg based on arguments provided by user. This patch
adds following endpoints:

1. /eal/memseg_lists
The command displays the memseg list from which the memory
has been allocated.
Example:
--> /eal/memseg_lists
{
  "/eal/memseg_lists": [
    0
  ]
}

2. /eal/memseg_list_info,<memseg-list-id>
The command outputs the memsegs, from which the memory is
allocated, for the memseg_list given as input.
Example:
--> /eal/memseg_list_info,0
{
  "/eal/memseg_list_info": [
    0,
    1,
    2,
    3,
    4,
    5
  ]
}

3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
The command outputs the memseg information based on the
memseg-list and the memseg-id given as input.
Example:
--> /eal/memseg_info,0,5
{
  "/eal/memseg_info": {
    "Memseg_list_index": 0,
    "Memseg_index": 5,
    "IOVA_addr": "0x1c0000000",
    "Start_addr": "0x1c0000000",
    "End_addr": "0x1e0000000",
    "Size": 536870912,
    "Hugepage_size": 536870912,
    "Socket_id": 0,
    "flags": 0
  }
}

--> /eal/memseg_info,0,1
{
  "/eal/memseg_info": {
    "Memseg_list_index": 0,
    "Memseg_index": 1,
    "IOVA_addr": "0x140000000",
    "Start_addr": "0x140000000",
    "End_addr": "0x160000000",
    "Size": 536870912,
    "Hugepage_size": 536870912,
    "Socket_id": 0,
    "flags": 0
  }
}

4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
The command outputs number of elements in a memseg based
on the heap-id, memseg-list-id and memseg-id given as input.
Example:
--> /eal/mem_element_list,0,0,5
{
  "/eal/mem_element_list": {
    "Element_count": 2
  }
}

--> /eal/mem_element_list,0,0,1
{
  "/eal/mem_element_list": {
    "Element_count": 52
  }
}

5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
   <elem-start-id>,<elem-end-id>
The command outputs element information like element start
address, end address, to which memseg it belongs, element
state, element size. User can give a range of elements to be
printed.
Example:
--> /eal/mem_element_info,0,0,4,1,2
{
  "/eal/mem_element_info": {
    "element_1": {
      "msl_id": 0,
      "ms_id": 4,
      "memseg_start_addr": "0x1a0000000",
      "memseg_end_addr": "0x1c0000000",
      "element_start_addr": "0x1a01fe680",
      "element_end_addr": "0x1a0bfe700",
      "element_size": 10485888,
      "element_state": "Busy"
    },
    "element_2": {
      "msl_id": 0,
      "ms_id": 4,
      "memseg_start_addr": "0x1a0000000",
      "memseg_end_addr": "0x1c0000000",
      "element_start_addr": "0x1a0bfe700",
      "element_end_addr": "0x1a15fe780",
      "element_size": 10485888,
      "element_state": "Busy"
    },
    "Element_count": 2
  }
}

Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
---
v2:
- Fixed compilation error related int-to-pointer-cast
- Changes for code review suggestions

v3:
- Commit message changes
- Renaming end-points
- Changing input parameters to comma-seperated
- Reverting telemetry output buffer size

v4:
- Patch-2 adds telemetry support to display system memory

v5:
- Removed command help related changes

v6:
- Changes for code review suggestions
- Dropped Patch-2 from the series

v7:
- Fixed compilation error

v8:
- Replaced rte_tel_data_add_dict_u64 with rte_tel_data_add_dict_uint
- Printing IOVA address for memsegs

 lib/eal/common/eal_common_memory.c | 398 ++++++++++++++++++++++++++++-
 1 file changed, 393 insertions(+), 5 deletions(-)

diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index e21fc7cfae..e75a895fbd 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -3,6 +3,7 @@
  */
 
 #include <errno.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -26,6 +27,7 @@
 #include "eal_memcfg.h"
 #include "eal_options.h"
 #include "malloc_heap.h"
+#include "malloc_elem.h"
 
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
@@ -1105,11 +1107,17 @@ rte_eal_memory_init(void)
 }
 
 #ifndef RTE_EXEC_ENV_WINDOWS
-#define EAL_MEMZONE_LIST_REQ	"/eal/memzone_list"
-#define EAL_MEMZONE_INFO_REQ	"/eal/memzone_info"
-#define EAL_HEAP_LIST_REQ	"/eal/heap_list"
-#define EAL_HEAP_INFO_REQ	"/eal/heap_info"
-#define ADDR_STR		15
+#define EAL_MEMZONE_LIST_REQ		"/eal/memzone_list"
+#define EAL_MEMZONE_INFO_REQ		"/eal/memzone_info"
+#define EAL_HEAP_LIST_REQ		"/eal/heap_list"
+#define EAL_HEAP_INFO_REQ		"/eal/heap_info"
+#define EAL_MEMSEG_LISTS_REQ		"/eal/memseg_lists"
+#define EAL_MEMSEG_LIST_INFO_REQ	"/eal/memseg_list_info"
+#define EAL_MEMSEG_INFO_REQ		"/eal/memseg_info"
+#define EAL_ELEMENT_LIST_REQ		"/eal/mem_element_list"
+#define EAL_ELEMENT_INFO_REQ		"/eal/mem_element_info"
+#define ADDR_STR			15
+
 
 /* Telemetry callback handler to return heap stats for requested heap id. */
 static int
@@ -1258,6 +1266,369 @@ handle_eal_memzone_list_request(const char *cmd __rte_unused,
 	return 0;
 }
 
+/* n_vals is the number of params to be parsed. */
+static int
+parse_params(const char *params, uint32_t *vals, size_t n_vals)
+{
+	char dlim[2] = ",";
+	char *params_args;
+	size_t count = 0;
+	char *token;
+
+	if (vals == NULL || params == NULL || strlen(params) == 0)
+		return -1;
+
+	/* strtok expects char * and param is const char *. Hence on using
+	 * params as "const char *" compiler throws warning.
+	 */
+	params_args = strdup(params);
+	if (params_args == NULL)
+		return -1;
+
+	token = strtok(params_args, dlim);
+	while (token && isdigit(*token) && count < n_vals) {
+		vals[count++] = strtoul(token, NULL, 10);
+		token = strtok(NULL, dlim);
+	}
+
+	free(params_args);
+
+	if (count < n_vals)
+		return -1;
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_lists_request(const char *cmd __rte_unused,
+				const char *params __rte_unused,
+				struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	int i;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+
+	for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
+		struct rte_memseg_list *msl = &mcfg->memsegs[i];
+		if (msl->memseg_arr.count == 0)
+			continue;
+
+		rte_tel_data_add_array_int(d, i);
+	}
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_list_info_request(const char *cmd __rte_unused,
+				    const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	uint32_t ms_list_idx;
+	int ms_idx;
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[1] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	ms_list_idx = vals[0];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
+
+	rte_mcfg_mem_read_lock();
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0)
+		goto done;
+
+	arr = &msl->memseg_arr;
+
+	ms_idx = rte_fbarray_find_next_used(arr, 0);
+	while (ms_idx >= 0) {
+		rte_tel_data_add_array_int(d, ms_idx);
+		ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
+	}
+
+done:
+	rte_mcfg_mem_read_unlock();
+
+	return 0;
+}
+
+static int
+handle_eal_memseg_info_request(const char *cmd __rte_unused,
+			       const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	uint64_t ms_start_addr, ms_end_addr, ms_size, hugepage_size, ms_iova;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct rte_fbarray *arr;
+	char addr[ADDR_STR];
+	uint32_t ms_list_idx = 0;
+	uint32_t ms_idx = 0;
+	int32_t ms_socket_id;
+	uint32_t ms_flags;
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[2] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	ms_list_idx = vals[0];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[1];
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	if (msl->memseg_arr.count == 0) {
+		rte_mcfg_mem_read_unlock();
+		return -1;
+	}
+
+	arr = &msl->memseg_arr;
+	ms = rte_fbarray_get(arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_iova = ms->iova;
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	ms_size = ms->len;
+	hugepage_size = ms->hugepage_sz;
+	ms_socket_id = ms->socket_id;
+	ms_flags = ms->flags;
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "Memseg_list_index", ms_list_idx);
+	rte_tel_data_add_dict_int(d, "Memseg_index", ms_idx);
+	if (ms_iova == RTE_BAD_IOVA)
+		snprintf(addr, ADDR_STR, "Bad IOVA");
+	else
+		snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_iova);
+
+	rte_tel_data_add_dict_string(d, "IOVA_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+	rte_tel_data_add_dict_string(d, "Start_addr", addr);
+	snprintf(addr, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+	rte_tel_data_add_dict_string(d, "End_addr", addr);
+	rte_tel_data_add_dict_uint(d, "Size", ms_size);
+	rte_tel_data_add_dict_uint(d, "Hugepage_size", hugepage_size);
+	rte_tel_data_add_dict_int(d, "Socket_id", ms_socket_id);
+	rte_tel_data_add_dict_int(d, "flags", ms_flags);
+
+	return 0;
+}
+
+static int
+handle_eal_element_list_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	int elem_count = 0;
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[3] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	heap_id = vals[0];
+	if (heap_id >= RTE_MAX_HEAPS)
+		return -1;
+
+	ms_list_idx = vals[1];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[2];
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if ((uint64_t)elem_start_addr >= ms_start_addr &&
+		    (uint64_t)elem_end_addr <= ms_end_addr)
+			elem_count++;
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
+static int
+handle_eal_element_info_request(const char *cmd __rte_unused,
+				const char *params, struct rte_tel_data *d)
+{
+	struct rte_mem_config *mcfg;
+	struct rte_memseg_list *msl;
+	const struct rte_memseg *ms;
+	struct malloc_elem *elem;
+	struct malloc_heap *heap;
+	struct rte_tel_data *c;
+	uint64_t ms_start_addr, ms_end_addr;
+	uint64_t elem_start_addr, elem_end_addr;
+	uint32_t ms_list_idx = 0;
+	uint32_t heap_id = 0;
+	uint32_t ms_idx = 0;
+	uint32_t start_elem = 0, end_elem = 0;
+	uint32_t count = 0, elem_count = 0;
+	char str[ADDR_STR];
+	/* size of an array == num params to be parsed. */
+	uint32_t vals[5] = {0};
+
+	if (parse_params(params, vals, RTE_DIM(vals)) < 0)
+		return -1;
+
+	heap_id = vals[0];
+	if (heap_id >= RTE_MAX_HEAPS)
+		return -1;
+
+	ms_list_idx = vals[1];
+	if (ms_list_idx >= RTE_MAX_MEMSEG_LISTS)
+		return -1;
+
+	ms_idx = vals[2];
+	start_elem = vals[3];
+	end_elem = vals[4];
+
+	if (end_elem < start_elem)
+		return -1;
+
+	rte_mcfg_mem_read_lock();
+
+	mcfg = rte_eal_get_configuration()->mem_config;
+	msl = &mcfg->memsegs[ms_list_idx];
+	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+	if (ms == NULL) {
+		rte_mcfg_mem_read_unlock();
+		RTE_LOG(DEBUG, EAL, "Error fetching requested memseg.\n");
+		return -1;
+	}
+
+	ms_start_addr = ms->addr_64;
+	ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+
+	rte_mcfg_mem_read_unlock();
+
+	rte_tel_data_start_dict(d);
+
+	heap = &mcfg->malloc_heaps[heap_id];
+	rte_spinlock_lock(&heap->lock);
+
+	elem = heap->first;
+	while (elem) {
+		elem_start_addr = (uint64_t)elem;
+		elem_end_addr =
+			(uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+
+		if (elem_start_addr < ms_start_addr ||
+				elem_end_addr > ms_end_addr) {
+			elem = elem->next;
+			continue;
+		}
+
+		if (count < start_elem) {
+			elem = elem->next;
+			count++;
+			continue;
+		}
+
+		c = rte_tel_data_alloc();
+		if (c == NULL)
+			break;
+
+		rte_tel_data_start_dict(c);
+		rte_tel_data_add_dict_int(c, "msl_id", ms_list_idx);
+		rte_tel_data_add_dict_int(c, "ms_id", ms_idx);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_start_addr);
+		rte_tel_data_add_dict_string(c, "memseg_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, ms_end_addr);
+		rte_tel_data_add_dict_string(c, "memseg_end_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_start_addr);
+		rte_tel_data_add_dict_string(c, "element_start_addr", str);
+		snprintf(str, ADDR_STR, "0x%"PRIx64, elem_end_addr);
+		rte_tel_data_add_dict_string(c, "element_end_addr", str);
+		rte_tel_data_add_dict_int(c, "element_size", elem->size);
+		snprintf(str, ADDR_STR, "%s", elem->state == 0 ? "Free" :
+			 elem->state == 1 ? "Busy" : elem->state == 2 ?
+			 "Pad" : "Error");
+		rte_tel_data_add_dict_string(c, "element_state", str);
+
+		snprintf(str, ADDR_STR, "%s_%u", "element", count);
+		if (rte_tel_data_add_dict_container(d, str, c, 0) != 0) {
+			rte_tel_data_free(c);
+			break;
+		}
+
+		elem_count++;
+		count++;
+		if (count > end_elem)
+			break;
+
+		elem = elem->next;
+	}
+
+	rte_spinlock_unlock(&heap->lock);
+
+	rte_tel_data_add_dict_int(d, "Element_count", elem_count);
+
+	return 0;
+}
+
 RTE_INIT(memory_telemetry)
 {
 	rte_telemetry_register_cmd(
@@ -1272,5 +1643,22 @@ RTE_INIT(memory_telemetry)
 	rte_telemetry_register_cmd(
 			EAL_HEAP_INFO_REQ, handle_eal_heap_info_request,
 			"Returns malloc heap stats. Parameters: int heap_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LISTS_REQ,
+			handle_eal_memseg_lists_request,
+			"Returns array of memseg list IDs. Takes no parameters");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_LIST_INFO_REQ,
+			handle_eal_memseg_list_info_request,
+			"Returns memseg list info. Parameters: int memseg_list_id");
+	rte_telemetry_register_cmd(
+			EAL_MEMSEG_INFO_REQ, handle_eal_memseg_info_request,
+			"Returns memseg info. Parameter: int memseg_list_id,int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_LIST_REQ,
+			handle_eal_element_list_request,
+			"Returns array of heap element IDs. Parameters: int heap_id, int memseg_list_id, int memseg_id");
+	rte_telemetry_register_cmd(EAL_ELEMENT_INFO_REQ,
+			handle_eal_element_info_request,
+			"Returns element info. Parameters: int heap_id, int memseg_list_id, int memseg_id, int start_elem_id, int end_elem_id");
 }
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8] mem: telemetry support for memseg and element information
  2023-05-17  9:21         ` [PATCH v8] " Amit Prakash Shukla
@ 2023-06-07 20:40           ` David Marchand
  0 siblings, 0 replies; 42+ messages in thread
From: David Marchand @ 2023-06-07 20:40 UTC (permalink / raw)
  To: Amit Prakash Shukla; +Cc: anatoly.burakov, dev, jerinj

On Wed, May 17, 2023 at 11:22 AM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> Changes adds telemetry support to display memory occupancy
> in memseg and the information of the elements allocated from
> a memseg based on arguments provided by user. This patch
> adds following endpoints:
>
> 1. /eal/memseg_lists
> The command displays the memseg list from which the memory
> has been allocated.
> Example:
> --> /eal/memseg_lists
> {
>   "/eal/memseg_lists": [
>     0
>   ]
> }
>
> 2. /eal/memseg_list_info,<memseg-list-id>
> The command outputs the memsegs, from which the memory is
> allocated, for the memseg_list given as input.
> Example:
> --> /eal/memseg_list_info,0
> {
>   "/eal/memseg_list_info": [
>     0,
>     1,
>     2,
>     3,
>     4,
>     5
>   ]
> }
>
> 3. /eal/memseg_info,<memseg-list-id>,<memseg-id>
> The command outputs the memseg information based on the
> memseg-list and the memseg-id given as input.
> Example:
> --> /eal/memseg_info,0,5
> {
>   "/eal/memseg_info": {
>     "Memseg_list_index": 0,
>     "Memseg_index": 5,
>     "IOVA_addr": "0x1c0000000",
>     "Start_addr": "0x1c0000000",
>     "End_addr": "0x1e0000000",
>     "Size": 536870912,
>     "Hugepage_size": 536870912,
>     "Socket_id": 0,
>     "flags": 0
>   }
> }
>
> --> /eal/memseg_info,0,1
> {
>   "/eal/memseg_info": {
>     "Memseg_list_index": 0,
>     "Memseg_index": 1,
>     "IOVA_addr": "0x140000000",
>     "Start_addr": "0x140000000",
>     "End_addr": "0x160000000",
>     "Size": 536870912,
>     "Hugepage_size": 536870912,
>     "Socket_id": 0,
>     "flags": 0
>   }
> }
>
> 4. /eal/mem_element_list,<heap-id>,<memseg-list-id>,<memseg-id>
> The command outputs number of elements in a memseg based
> on the heap-id, memseg-list-id and memseg-id given as input.
> Example:
> --> /eal/mem_element_list,0,0,5
> {
>   "/eal/mem_element_list": {
>     "Element_count": 2
>   }
> }
>
> --> /eal/mem_element_list,0,0,1
> {
>   "/eal/mem_element_list": {
>     "Element_count": 52
>   }
> }
>
> 5. /eal/mem_element_info,<heap-id>,<memseg-list-id>,<memseg-id>,  \
>    <elem-start-id>,<elem-end-id>
> The command outputs element information like element start
> address, end address, to which memseg it belongs, element
> state, element size. User can give a range of elements to be
> printed.
> Example:
> --> /eal/mem_element_info,0,0,4,1,2
> {
>   "/eal/mem_element_info": {
>     "element_1": {
>       "msl_id": 0,
>       "ms_id": 4,
>       "memseg_start_addr": "0x1a0000000",
>       "memseg_end_addr": "0x1c0000000",
>       "element_start_addr": "0x1a01fe680",
>       "element_end_addr": "0x1a0bfe700",
>       "element_size": 10485888,
>       "element_state": "Busy"
>     },
>     "element_2": {
>       "msl_id": 0,
>       "ms_id": 4,
>       "memseg_start_addr": "0x1a0000000",
>       "memseg_end_addr": "0x1c0000000",
>       "element_start_addr": "0x1a0bfe700",
>       "element_end_addr": "0x1a15fe780",
>       "element_size": 10485888,
>       "element_state": "Busy"
>     },
>     "Element_count": 2
>   }
> }
>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>

Applied, thanks.


-- 
David Marchand


^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2023-06-07 20:40 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-19  6:30 [PATCH] mem: telemetry support for memseg and element information Amit Prakash Shukla
2022-05-19 12:42 ` David Marchand
2022-05-19 18:57 ` [PATCH v2] " Amit Prakash Shukla
2022-05-23 11:14   ` Bruce Richardson
2022-05-23 13:35     ` [EXT] " Amit Prakash Shukla
2022-05-23 13:43       ` Bruce Richardson
2022-05-24 10:30         ` Amit Prakash Shukla
2022-05-24 10:33 ` [PATCH v3] " Amit Prakash Shukla
2022-05-25 10:33 ` [PATCH v4 1/2] " Amit Prakash Shukla
2022-05-25 10:33   ` [PATCH v4 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
2022-06-30  5:54     ` Amit Prakash Shukla
2022-07-21 11:21       ` Amit Prakash Shukla
2022-06-14 12:50   ` [PATCH v4 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
2022-06-30  5:52     ` Amit Prakash Shukla
2022-07-21 11:20       ` Amit Prakash Shukla
2022-09-29  8:29   ` David Marchand
2022-09-29 11:30     ` [EXT] " Amit Prakash Shukla
2022-09-29 11:43   ` [PATCH v5 " Amit Prakash Shukla
2022-09-29 11:43     ` [PATCH v5 2/2] mem: telemetry support for system memory information Amit Prakash Shukla
2022-10-07 19:46       ` David Marchand
2022-10-11  7:10         ` [EXT] " Amit Prakash Shukla
2022-10-20 19:18           ` Dmitry Kozlyuk
2022-10-20 19:50             ` Stephen Hemminger
2022-10-06  7:07     ` [PATCH v5 1/2] mem: telemetry support for memseg and element information Amit Prakash Shukla
2022-10-07 19:52       ` David Marchand
2022-10-07 19:48     ` David Marchand
2022-10-11  7:22       ` [EXT] " Amit Prakash Shukla
2022-10-20 11:40     ` Dmitry Kozlyuk
2022-10-21 19:26       ` [EXT] " Amit Prakash Shukla
2022-10-21 20:07         ` Dmitry Kozlyuk
2022-10-25  7:25           ` Amit Prakash Shukla
2022-10-25 11:51     ` [PATCH v6] " Amit Prakash Shukla
2022-10-25 13:02       ` [PATCH v7] " Amit Prakash Shukla
2022-12-06 11:46         ` Amit Prakash Shukla
2023-01-30 10:18           ` Amit Prakash Shukla
2023-02-20 11:10         ` Thomas Monjalon
2023-02-28  7:30           ` [EXT] " Amit Prakash Shukla
2023-05-15 11:51             ` Amit Prakash Shukla
2023-05-16 10:47         ` Burakov, Anatoly
2023-05-17  9:08           ` [EXT] " Amit Prakash Shukla
2023-05-17  9:21         ` [PATCH v8] " Amit Prakash Shukla
2023-06-07 20:40           ` David Marchand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).