get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/68739/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 68739,
    "url": "http://patches.dpdk.org/api/patches/68739/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1587110623-405-2-git-send-email-xuemingl@mellanox.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1587110623-405-2-git-send-email-xuemingl@mellanox.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1587110623-405-2-git-send-email-xuemingl@mellanox.com",
    "date": "2020-04-17T08:03:42",
    "name": "[RFC,v2,1/2] malloc: support malloc and free tracking log",
    "commit_ref": null,
    "pull_url": null,
    "state": "deferred",
    "archived": true,
    "hash": "f32427ef873422620ce92d106e0fa2aff8f94cb0",
    "submitter": {
        "id": 814,
        "url": "http://patches.dpdk.org/api/people/814/?format=api",
        "name": "Xueming Li",
        "email": "xuemingl@mellanox.com"
    },
    "delegate": {
        "id": 24651,
        "url": "http://patches.dpdk.org/api/users/24651/?format=api",
        "username": "dmarchand",
        "first_name": "David",
        "last_name": "Marchand",
        "email": "david.marchand@redhat.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1587110623-405-2-git-send-email-xuemingl@mellanox.com/mbox/",
    "series": [
        {
            "id": 9454,
            "url": "http://patches.dpdk.org/api/series/9454/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=9454",
            "date": "2020-04-17T08:03:41",
            "name": "malloc: support malloc and free tracking log",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/9454/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/68739/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/68739/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 7FC19A058A;\n\tFri, 17 Apr 2020 10:04:03 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 5B3401DE7B;\n\tFri, 17 Apr 2020 10:03:57 +0200 (CEST)",
            "from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130])\n by dpdk.org (Postfix) with ESMTP id 11B391DE40\n for <dev@dpdk.org>; Fri, 17 Apr 2020 10:03:55 +0200 (CEST)"
        ],
        "From": "Xueming Li <xuemingl@mellanox.com>",
        "To": "Anatoly Burakov <anatoly.burakov@intel.com>,\n Ferruh Yigit <ferruh.yigit@intel.com>,\n Stephen Hemminger <stephen@networkplumber.org>",
        "Cc": "dev@dpdk.org,\n\tAsaf Penso <asafp@mellanox.com>",
        "Date": "Fri, 17 Apr 2020 08:03:42 +0000",
        "Message-Id": "<1587110623-405-2-git-send-email-xuemingl@mellanox.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": [
            "<1587110623-405-1-git-send-email-xuemingl@mellanox.com>",
            "<1586318694-31358-1-git-send-email-xuemingl@mellanox.com>"
        ],
        "References": [
            "<1587110623-405-1-git-send-email-xuemingl@mellanox.com>",
            "<1586318694-31358-1-git-send-email-xuemingl@mellanox.com>"
        ],
        "Subject": "[dpdk-dev] [RFC v2 1/2] malloc: support malloc and free tracking log",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch introduces new feature to track rte_malloc leakage by logging\nmalloc and free.\n\nSigned-off-by: Xueming Li <xuemingl@mellanox.com>\n---\n lib/librte_eal/common/eal_memcfg.h  |  26 ++++\n lib/librte_eal/common/malloc_elem.h |   6 +-\n lib/librte_eal/common/rte_malloc.c  | 261 +++++++++++++++++++++++++++++++++++-\n lib/librte_eal/include/rte_malloc.h |  39 +++++-\n lib/librte_eal/rte_eal_version.map  |   3 +\n 5 files changed, 327 insertions(+), 8 deletions(-)",
    "diff": "diff --git a/lib/librte_eal/common/eal_memcfg.h b/lib/librte_eal/common/eal_memcfg.h\nindex 583fcb5..49d59d8 100644\n--- a/lib/librte_eal/common/eal_memcfg.h\n+++ b/lib/librte_eal/common/eal_memcfg.h\n@@ -14,6 +14,28 @@\n \n #include \"malloc_heap.h\"\n \n+\n+enum rte_malloc_log_type {\n+\trte_malloc_log_malloc,\n+\trte_malloc_log_realloc,\n+\trte_malloc_log_free,\n+};\n+\n+/**\n+ * Memory allocation and free tracking log\n+ */\n+struct rte_malloc_log {\n+\tint socket;\n+\tvoid *addr;\n+\tsize_t req_size; /* requested size */\n+\tsize_t size; /* outer element and pad */\n+\tsize_t align;\n+\tuint32_t pad;\n+\tuint32_t type:2; /* log entry type. */\n+\tuint32_t paired:1; /* allocation and free both tracked. */\n+\tchar name[64]; /* name may come from stack, copy. */\n+};\n+\n /**\n  * Memory configuration shared across multiple processes.\n  */\n@@ -73,6 +95,10 @@ struct rte_mem_config {\n \t/**< TSC rate */\n \n \tuint8_t dma_maskbits; /**< Keeps the more restricted dma mask. */\n+\n+\tstruct rte_malloc_log *malloc_logs; /**< Log entries. */\n+\tint malloc_log_max; /**< Max number of logs to write. */\n+\tint malloc_log_count; /**< count of logs written. */\n };\n \n /* update internal config from shared mem config */\ndiff --git a/lib/librte_eal/common/malloc_elem.h b/lib/librte_eal/common/malloc_elem.h\nindex a1e5f7f..006480c 100644\n--- a/lib/librte_eal/common/malloc_elem.h\n+++ b/lib/librte_eal/common/malloc_elem.h\n@@ -9,6 +9,8 @@\n \n #define MIN_DATA_SIZE (RTE_CACHE_LINE_SIZE)\n \n+#define MALLOC_TRACKING_MAX (1 << 29)\n+\n /* dummy definition of struct so we can use pointers to it in malloc_elem struct */\n struct malloc_heap;\n \n@@ -27,7 +29,9 @@ struct malloc_elem {\n \tLIST_ENTRY(malloc_elem) free_list;\n \t/**< list of free elements in heap */\n \tstruct rte_memseg_list *msl;\n-\tvolatile enum elem_state state;\n+\tvolatile uint32_t state:2;\n+\tvolatile uint32_t log:1;\t\t/* Element logged. */\n+\tvolatile uint32_t log_index:29;\t\t/* Element log index. */\n \tuint32_t pad;\n \tsize_t size;\n \tstruct malloc_elem *orig_elem;\ndiff --git a/lib/librte_eal/common/rte_malloc.c b/lib/librte_eal/common/rte_malloc.c\nindex d6026a2..2e30693 100644\n--- a/lib/librte_eal/common/rte_malloc.c\n+++ b/lib/librte_eal/common/rte_malloc.c\n@@ -6,6 +6,7 @@\n #include <stddef.h>\n #include <stdio.h>\n #include <string.h>\n+#include <assert.h>\n #include <sys/queue.h>\n \n #include <rte_errno.h>\n@@ -29,12 +30,245 @@\n #include \"eal_private.h\"\n \n \n+const char *rte_malloc_log_type_name[] = { \"malloc\", \"realloc\", \"free\" };\n+\n+/*\n+ * Track and log memory allocation information.\n+ */\n+static void\n+rte_malloc_log(const char *type, size_t size, unsigned int align,\n+\t       void *addr)\n+{\n+\tstruct rte_malloc_log *log;\n+\tstruct malloc_elem *elem = malloc_elem_from_data(addr);\n+\tstruct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;\n+\n+\tif (!addr || !elem || !mcfg->malloc_log_max ||\n+\t    mcfg->malloc_log_max == mcfg->malloc_log_count)\n+\t\treturn;\n+\n+\tlog = &mcfg->malloc_logs[mcfg->malloc_log_count];\n+\tif (type)\n+\t\tstrncpy(log->name, type, sizeof(log->name) - 1);\n+\tlog->req_size = size;\n+\tlog->pad = elem->pad;\n+\tlog->size = elem->size + elem->pad;\n+\talign = align ? align : 1;\n+\tlog->align = RTE_CACHE_LINE_ROUNDUP(align);\n+\tlog->addr = addr;\n+\tlog->socket = elem->heap->socket_id;\n+\telem->log = 1;\n+\telem->log_index = mcfg->malloc_log_count++;\n+}\n+\n+/*\n+ * track and log memory realloc\n+ */\n+static void\n+rte_realloc_log(uint32_t pref_malloc, uint32_t prev_index,\n+\t\tvoid *new_addr, size_t size, unsigned int align)\n+{\n+\tstruct rte_malloc_log *prev_log;\n+\tstruct rte_malloc_log *log;\n+\tstruct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;\n+\tstruct malloc_elem *elem = malloc_elem_from_data(new_addr);\n+\n+\tif (!mcfg->malloc_log_max || !elem)\n+\t\treturn;\n+\tif (pref_malloc) {\n+\t\tprev_log = &mcfg->malloc_logs[prev_index];\n+\t\tprev_log->paired = 1;\n+\t}\n+\tif (mcfg->malloc_log_max == mcfg->malloc_log_count)\n+\t\treturn;\n+\tlog = &mcfg->malloc_logs[mcfg->malloc_log_count++];\n+\tlog->addr = new_addr;\n+\tlog->type = rte_malloc_log_realloc;\n+\tlog->req_size = size;\n+\tif (pref_malloc)\n+\t\tstrncpy(log->name, prev_log->name, sizeof(log->name));\n+\tlog->pad = elem->pad;\n+\tlog->size = elem->size + elem->pad;\n+\talign = align ? align : 1;\n+\tlog->align = RTE_CACHE_LINE_ROUNDUP(align);\n+\tlog->socket = elem->heap->socket_id;\n+\telem->log = 1;\n+\telem->log_index = mcfg->malloc_log_count++;\n+}\n+\n+/*\n+ * track and log memory free\n+ */\n+static void\n+rte_free_log(void *addr, uint32_t log_malloc, uint32_t log_index, size_t size)\n+{\n+\tstruct rte_malloc_log *alloc_log;\n+\tstruct rte_malloc_log *log;\n+\tstruct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;\n+\n+\tif (!addr || !mcfg->malloc_log_max)\n+\t\treturn;\n+\tif (log_malloc) {\n+\t\talloc_log = &mcfg->malloc_logs[log_index];\n+\t\talloc_log->paired = 1;\n+\t}\n+\tif (mcfg->malloc_log_max == mcfg->malloc_log_count)\n+\t\treturn;\n+\tlog = &mcfg->malloc_logs[mcfg->malloc_log_count++];\n+\tlog->addr = addr;\n+\tlog->type = rte_malloc_log_free;\n+\tlog->size = size;\n+\tif (log_malloc) {\n+\t\tstrncpy(log->name, alloc_log->name, sizeof(log->name));\n+\t\tlog->req_size = alloc_log->req_size;\n+\t\tlog->align = alloc_log->align;\n+\t\tlog->socket = alloc_log->socket;\n+\t\tlog->pad = alloc_log->pad;\n+\t\tlog->paired = 1;\n+\t}\n+}\n+\n+/*\n+ * Initialize malloc tracking with max count of log entries\n+ */\n+int\n+rte_malloc_log_init(uint32_t count)\n+{\n+\tstruct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;\n+\n+\tif (mcfg->malloc_log_max) {\n+\t\tRTE_LOG(ERR, EAL, \"malloc tracking started\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\tif (!count || count > MALLOC_TRACKING_MAX) {\n+\t\tRTE_LOG(ERR, EAL, \"invalid malloc tracking log number\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* allocate logs. */\n+\tmcfg->malloc_logs = rte_calloc(\"malloc_logs\", count,\n+\t\t\t\t       sizeof(*mcfg->malloc_logs), 0);\n+\tif (!mcfg->malloc_logs)\n+\t\treturn -ENOMEM;\n+\n+\tmcfg->malloc_log_count = 0;\n+\tmcfg->malloc_log_max = count;\n+\treturn 0;\n+}\n+\n+/*\n+ * Initialize malloc tracking with max count of log entries\n+ */\n+int\n+rte_malloc_log_stop(void)\n+{\n+\tstruct malloc_elem *elem;\n+\tint i;\n+\tstruct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;\n+\tstruct rte_malloc_log *log;\n+\n+\tif (!mcfg->malloc_log_max) {\n+\t\tRTE_LOG(ERR, EAL, \"malloc tracking not started\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* release all logs. */\n+\tfor (i = 0; i < mcfg->malloc_log_count; i++) {\n+\t\tlog = &mcfg->malloc_logs[i];\n+\t\t/* clear log info from malloc elem. */\n+\t\tif (log->type)\n+\t\t\tcontinue;\n+\t\telem = malloc_elem_from_data(log->addr);\n+\t\tif (elem) {\n+\t\t\telem->log = 0;\n+\t\t\telem->log_index = 0;\n+\t\t}\n+\t}\n+\n+\trte_free(mcfg->malloc_logs);\n+\tmcfg->malloc_logs = NULL;\n+\tmcfg->malloc_log_max = 0;\n+\tmcfg->malloc_log_count = 0;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Dump malloc tracking\n+ */\n+void\n+rte_malloc_log_dump(FILE *out, uint32_t detail)\n+{\n+\tstruct rte_malloc_log *log;\n+\tint i;\n+\tuint32_t n_alloc_free = 0;\n+\tuint32_t n_alloc = 0;\n+\tuint32_t n_free_alloc = 0;\n+\tuint32_t n_free = 0;\n+\tsize_t alloc_leak = 0;\n+\tsize_t free_leak = 0;\n+\tstruct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;\n+\n+\tif (!mcfg->malloc_log_max || !mcfg->malloc_logs) {\n+\t\tRTE_LOG(ERR, EAL, \"malloc tracking not started\\n\");\n+\t\treturn;\n+\t}\n+\tif (detail)\n+\t\tfprintf(out, \"Socket  Action Paired            Address    Size Align Mgmt Pad   Total Type\\n\");\n+\tfor (i = 0; i < mcfg->malloc_log_count; i++) {\n+\t\tlog = &mcfg->malloc_logs[i];\n+\t\tif (detail > 1 ||\n+\t\t    (detail == 1 && !log->paired &&\n+\t\t     log->type != rte_malloc_log_free))\n+\t\t\tfprintf(out, \"%6d %7s %6s %18p %7lu %5lu %4d %3u %7lu %s\\n\",\n+\t\t\t\tlog->socket,\n+\t\t\t\trte_malloc_log_type_name[log->type],\n+\t\t\t\tlog->paired ? \"y\" : \"n\",\n+\t\t\t\tlog->addr, log->req_size, log->align,\n+\t\t\t\tMALLOC_ELEM_OVERHEAD,\n+\t\t\t\tlog->pad,\n+\t\t\t\tlog->size,\n+\t\t\t\tlog->name);\n+\t\tif (log->type == rte_malloc_log_free) {\n+\t\t\tn_free++;\n+\t\t\tif (log->paired)\n+\t\t\t\tn_free_alloc++;\n+\t\t\telse\n+\t\t\t\tfree_leak += log->size;\n+\t\t} else {\n+\t\t\tn_alloc++;\n+\t\t\tif (log->paired)\n+\t\t\t\tn_alloc_free++;\n+\t\t\telse\n+\t\t\t\talloc_leak += log->size;\n+\t\t}\n+\t}\n+\tfprintf(out, \"Total rte_malloc and rte_realloc: %u/%u leak %zu(B), rte_free: %u/%u leak: %zu(B)\\n\",\n+\t\tn_alloc_free, n_alloc, alloc_leak,\n+\t\tn_free_alloc, n_free, free_leak);\n+\tif (mcfg->malloc_log_count == mcfg->malloc_log_max)\n+\t\tfprintf(out, \"Warning: log full, please consider larger log buffer\\n\");\n+}\n+\n /* Free the memory space back to heap */\n void rte_free(void *addr)\n {\n+\tstruct malloc_elem *elem = malloc_elem_from_data(addr);\n+\tuint32_t log_malloc, log_index;\n+\tsize_t size;\n+\n \tif (addr == NULL) return;\n-\tif (malloc_heap_free(malloc_elem_from_data(addr)) < 0)\n+\tif (elem) {\n+\t\tlog_malloc = elem->log;\n+\t\tlog_index = elem->log_index;\n+\t\tsize = elem->size + elem->pad;\n+\t\tif (malloc_heap_free(elem) < 0)\n+\t\t\tRTE_LOG(ERR, EAL, \"Error: Invalid memory\\n\");\n+\t\telse\n+\t\t\trte_free_log(addr, log_malloc, log_index, size);\n+\t} else {\n \t\tRTE_LOG(ERR, EAL, \"Error: Invalid memory\\n\");\n+\t}\n }\n \n /*\n@@ -44,6 +278,8 @@ void rte_free(void *addr)\n rte_malloc_socket(const char *type, size_t size, unsigned int align,\n \t\tint socket_arg)\n {\n+\tvoid *ret;\n+\n \t/* return NULL if size is 0 or alignment is not power-of-2 */\n \tif (size == 0 || (align && !rte_is_power_of_2(align)))\n \t\treturn NULL;\n@@ -57,8 +293,13 @@ void rte_free(void *addr)\n \t\t\t\t!rte_eal_has_hugepages())\n \t\tsocket_arg = SOCKET_ID_ANY;\n \n-\treturn malloc_heap_alloc(type, size, socket_arg, 0,\n+\tret = malloc_heap_alloc(type, size, socket_arg, 0,\n \t\t\talign == 0 ? 1 : align, 0, false);\n+\n+\tif (ret)\n+\t\trte_malloc_log(type, size, align == 0 ? 1 : align, ret);\n+\n+\treturn ret;\n }\n \n /*\n@@ -123,10 +364,12 @@ void rte_free(void *addr)\n void *\n rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket)\n {\n+\tstruct malloc_elem *elem = malloc_elem_from_data(ptr);\n+\tuint32_t log_malloc, log_index;\n+\n \tif (ptr == NULL)\n \t\treturn rte_malloc_socket(NULL, size, align, socket);\n \n-\tstruct malloc_elem *elem = malloc_elem_from_data(ptr);\n \tif (elem == NULL) {\n \t\tRTE_LOG(ERR, EAL, \"Error: memory corruption detected\\n\");\n \t\treturn NULL;\n@@ -139,9 +382,15 @@ void rte_free(void *addr)\n \t */\n \tif ((socket == SOCKET_ID_ANY ||\n \t     (unsigned int)socket == elem->heap->socket_id) &&\n-\t\t\tRTE_PTR_ALIGN(ptr, align) == ptr &&\n-\t\t\tmalloc_heap_resize(elem, size) == 0)\n-\t\treturn ptr;\n+\t    RTE_PTR_ALIGN(ptr, align) == ptr) {\n+\t\tlog_malloc = elem->log;\n+\t\tlog_index = elem->log_index;\n+\t\tif (malloc_heap_resize(elem, size) == 0) {\n+\t\t\trte_realloc_log(log_malloc, log_index, ptr, size,\n+\t\t\t\t\talign);\n+\t\t\treturn ptr;\n+\t\t}\n+\t}\n \n \t/* either requested socket id doesn't match, alignment is off\n \t * or we have no room to expand,\ndiff --git a/lib/librte_eal/include/rte_malloc.h b/lib/librte_eal/include/rte_malloc.h\nindex 42ca051..4947ba9 100644\n--- a/lib/librte_eal/include/rte_malloc.h\n+++ b/lib/librte_eal/include/rte_malloc.h\n@@ -508,7 +508,44 @@ struct rte_malloc_socket_stats {\n  *   to dump all objects.\n  */\n void\n-rte_malloc_dump_stats(FILE *f, const char *type);\n+rte_malloc_dump_stats(FILE *out, const char *type);\n+\n+/**\n+ * Initialize malloc tracking log buffer.\n+ *\n+ * @param count\n+ *   Max count of tracking log entries, range (1 : 1 << 29)\n+ * @return\n+ *   0 on success, negative errno otherwise\n+ */\n+__rte_experimental\n+int\n+rte_malloc_log_init(uint32_t count);\n+\n+/**\n+ * Stop malloc tracking log.\n+ *\n+ * @return\n+ *   0 on success, negative errno otherwise\n+ */\n+__rte_experimental\n+int\n+rte_malloc_log_stop(void);\n+\n+/**\n+ * Dump malloc tracking log to output.\n+ *\n+ * @param out\n+ *   output file handle\n+ * @param detail\n+ *   detail level of output\n+ *   0: summary\n+ *   1: potential leaks - allocated without free\n+ *   2: all entries\n+ */\n+__rte_experimental\n+void\n+rte_malloc_log_dump(FILE *out, uint32_t detail);\n \n /**\n  * Dump contents of all malloc heaps to a file.\ndiff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map\nindex f9ede5b..5151057 100644\n--- a/lib/librte_eal/rte_eal_version.map\n+++ b/lib/librte_eal/rte_eal_version.map\n@@ -338,4 +338,7 @@ EXPERIMENTAL {\n \n \t# added in 20.05\n \trte_log_can_log;\n+\trte_malloc_log_init;\n+\trte_malloc_log_dump;\n+\trte_malloc_log_stop;\n };\n",
    "prefixes": [
        "RFC",
        "v2",
        "1/2"
    ]
}