get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 74210,
    "url": "http://patches.dpdk.org/api/patches/74210/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1594891216-11778-2-git-send-email-suanmingm@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": "<1594891216-11778-2-git-send-email-suanmingm@mellanox.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1594891216-11778-2-git-send-email-suanmingm@mellanox.com",
    "date": "2020-07-16T09:20:10",
    "name": "[v2,1/7] common/mlx5: add mlx5 memory management functions",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "7eca225e71cf4dea23f003028a674ef16820dfbf",
    "submitter": {
        "id": 1358,
        "url": "http://patches.dpdk.org/api/people/1358/?format=api",
        "name": "Suanming Mou",
        "email": "suanmingm@mellanox.com"
    },
    "delegate": {
        "id": 3268,
        "url": "http://patches.dpdk.org/api/users/3268/?format=api",
        "username": "rasland",
        "first_name": "Raslan",
        "last_name": "Darawsheh",
        "email": "rasland@nvidia.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1594891216-11778-2-git-send-email-suanmingm@mellanox.com/mbox/",
    "series": [
        {
            "id": 11083,
            "url": "http://patches.dpdk.org/api/series/11083/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=11083",
            "date": "2020-07-16T09:20:09",
            "name": "net/mlx5: add sys_mem_en devarg",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/11083/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/74210/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/74210/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 456A8A0540;\n\tThu, 16 Jul 2020 11:20:36 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 1657E1BF7D;\n\tThu, 16 Jul 2020 11:20:28 +0200 (CEST)",
            "from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130])\n by dpdk.org (Postfix) with ESMTP id 47D081BED9\n for <dev@dpdk.org>; Thu, 16 Jul 2020 11:20:25 +0200 (CEST)"
        ],
        "From": "Suanming Mou <suanmingm@mellanox.com>",
        "To": "viacheslavo@mellanox.com,\n\tmatan@mellanox.com",
        "Cc": "orika@mellanox.com,\n\trasland@mellanox.com,\n\tdev@dpdk.org",
        "Date": "Thu, 16 Jul 2020 17:20:10 +0800",
        "Message-Id": "<1594891216-11778-2-git-send-email-suanmingm@mellanox.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1594891216-11778-1-git-send-email-suanmingm@mellanox.com>",
        "References": "<1594785603-152773-1-git-send-email-suanmingm@mellanox.com>\n <1594891216-11778-1-git-send-email-suanmingm@mellanox.com>",
        "Subject": "[dpdk-dev] [PATCH v2 1/7] common/mlx5: add mlx5 memory management\n\tfunctions",
        "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": "Add the internal mlx5 memory management functions:\n\nmlx5_malloc_mem_select();\nmlx5_memory_stat_dump();\nmlx5_rellaocate();\nmlx5_malloc();\nmlx5_free();\n\nUser will be allowed to manage memory from system or from rte memory\nwith the unified functions.\n\nIn this case, for the system with limited memory which can not reserve\nlots of rte hugepage memory in advanced, will allocate the memory from\nsystem for some of not so important control path objects based on the\nsys_mem_en configuration.\n\nSigned-off-by: Suanming Mou <suanmingm@mellanox.com>\nAcked-by: Matan Azrad <matan@mellanox.com>\n---\n drivers/common/mlx5/Makefile                    |   1 +\n drivers/common/mlx5/meson.build                 |   1 +\n drivers/common/mlx5/mlx5_malloc.c               | 306 ++++++++++++++++++++++++\n drivers/common/mlx5/mlx5_malloc.h               |  99 ++++++++\n drivers/common/mlx5/rte_common_mlx5_version.map |   6 +\n 5 files changed, 413 insertions(+)\n create mode 100644 drivers/common/mlx5/mlx5_malloc.c\n create mode 100644 drivers/common/mlx5/mlx5_malloc.h",
    "diff": "diff --git a/drivers/common/mlx5/Makefile b/drivers/common/mlx5/Makefile\nindex f6c762b..239d681 100644\n--- a/drivers/common/mlx5/Makefile\n+++ b/drivers/common/mlx5/Makefile\n@@ -21,6 +21,7 @@ SRCS-y += linux/mlx5_nl.c\n SRCS-y += linux/mlx5_common_verbs.c\n SRCS-y += mlx5_common_mp.c\n SRCS-y += mlx5_common_mr.c\n+SRCS-y += mlx5_malloc.c\n ifeq ($(CONFIG_RTE_IBVERBS_LINK_DLOPEN),y)\n INSTALL-y-lib += $(LIB_GLUE)\n endif\ndiff --git a/drivers/common/mlx5/meson.build b/drivers/common/mlx5/meson.build\nindex ba43714..70e2c1c 100644\n--- a/drivers/common/mlx5/meson.build\n+++ b/drivers/common/mlx5/meson.build\n@@ -13,6 +13,7 @@ sources += files(\n \t'mlx5_common.c',\n \t'mlx5_common_mp.c',\n \t'mlx5_common_mr.c',\n+\t'mlx5_malloc.c',\n )\n \n cflags_options = [\ndiff --git a/drivers/common/mlx5/mlx5_malloc.c b/drivers/common/mlx5/mlx5_malloc.c\nnew file mode 100644\nindex 0000000..316305d\n--- /dev/null\n+++ b/drivers/common/mlx5/mlx5_malloc.c\n@@ -0,0 +1,306 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2020 Mellanox Technologies, Ltd\n+ */\n+\n+#include <errno.h>\n+#include <rte_malloc.h>\n+#include <malloc.h>\n+#include <stdbool.h>\n+#include <string.h>\n+\n+#include <rte_atomic.h>\n+\n+#include \"mlx5_common_utils.h\"\n+#include \"mlx5_malloc.h\"\n+\n+struct mlx5_sys_mem {\n+\tuint32_t init:1; /* Memory allocator initialized. */\n+\tuint32_t enable:1; /* System memory select. */\n+\tuint32_t reserve:30; /* Reserve. */\n+\tunion {\n+\t\tstruct rte_memseg_list *last_msl;\n+\t\trte_atomic64_t a64_last_msl;\n+\t};\n+\t/* last allocated rte memory memseg list. */\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\trte_atomic64_t malloc_sys;\n+\t/* Memory allocated from system count. */\n+\trte_atomic64_t malloc_rte;\n+\t/* Memory allocated from hugepage count. */\n+\trte_atomic64_t realloc_sys;\n+\t/* Memory reallocate from system count. */\n+\trte_atomic64_t realloc_rte;\n+\t/* Memory reallocate from hugepage count. */\n+\trte_atomic64_t free_sys;\n+\t/* Memory free to system count. */\n+\trte_atomic64_t free_rte;\n+\t/* Memory free to hugepage count. */\n+\trte_atomic64_t msl_miss;\n+\t/* MSL miss count. */\n+\trte_atomic64_t msl_update;\n+\t/* MSL update count. */\n+#endif\n+};\n+\n+/* Initialize default as not */\n+static struct mlx5_sys_mem mlx5_sys_mem = {\n+\t.init = 0,\n+\t.enable = 0,\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\t.malloc_sys = RTE_ATOMIC64_INIT(0),\n+\t.malloc_rte = RTE_ATOMIC64_INIT(0),\n+\t.realloc_sys = RTE_ATOMIC64_INIT(0),\n+\t.realloc_rte = RTE_ATOMIC64_INIT(0),\n+\t.free_sys = RTE_ATOMIC64_INIT(0),\n+\t.free_rte = RTE_ATOMIC64_INIT(0),\n+\t.msl_miss = RTE_ATOMIC64_INIT(0),\n+\t.msl_update = RTE_ATOMIC64_INIT(0),\n+#endif\n+};\n+\n+/**\n+ * Check if the address belongs to memory seg list.\n+ *\n+ * @param addr\n+ *   Memory address to be ckeced.\n+ * @param msl\n+ *   Memory seg list.\n+ *\n+ * @return\n+ *   True if it belongs, false otherwise.\n+ */\n+static bool\n+mlx5_mem_check_msl(void *addr, struct rte_memseg_list *msl)\n+{\n+\tvoid *start, *end;\n+\n+\tif (!msl)\n+\t\treturn false;\n+\tstart = msl->base_va;\n+\tend = RTE_PTR_ADD(start, msl->len);\n+\tif (addr >= start && addr < end)\n+\t\treturn true;\n+\treturn false;\n+}\n+\n+/**\n+ * Update the msl if memory belongs to new msl.\n+ *\n+ * @param addr\n+ *   Memory address.\n+ */\n+static void\n+mlx5_mem_update_msl(void *addr)\n+{\n+\t/*\n+\t * Update the cache msl if the new addr comes from the new msl\n+\t * different with the cached msl.\n+\t */\n+\tif (addr && !mlx5_mem_check_msl(addr,\n+\t    (struct rte_memseg_list *)(uintptr_t)rte_atomic64_read\n+\t    (&mlx5_sys_mem.a64_last_msl))) {\n+\t\trte_atomic64_set(&mlx5_sys_mem.a64_last_msl,\n+\t\t\t(int64_t)(uintptr_t)rte_mem_virt2memseg_list(addr));\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\t\trte_atomic64_inc(&mlx5_sys_mem.msl_update);\n+#endif\n+\t}\n+}\n+\n+/**\n+ * Check if the address belongs to rte memory.\n+ *\n+ * @param addr\n+ *   Memory address to be ckeced.\n+ *\n+ * @return\n+ *   True if it belongs, false otherwise.\n+ */\n+static bool\n+mlx5_mem_is_rte(void *addr)\n+{\n+\t/*\n+\t * Check if the last cache msl matches. Drop to slow path\n+\t * to check if the memory belongs to rte memory.\n+\t */\n+\tif (!mlx5_mem_check_msl(addr, (struct rte_memseg_list *)(uintptr_t)\n+\t    rte_atomic64_read(&mlx5_sys_mem.a64_last_msl))) {\n+\t\tif (!rte_mem_virt2memseg_list(addr))\n+\t\t\treturn false;\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\t\trte_atomic64_inc(&mlx5_sys_mem.msl_miss);\n+#endif\n+\t}\n+\treturn true;\n+}\n+\n+/**\n+ * Allocate memory with alignment.\n+ *\n+ * @param size\n+ *   Memory size to be allocated.\n+ * @param align\n+ *   Memory alignment.\n+ * @param zero\n+ *   Clear the allocated memory or not.\n+ *\n+ * @return\n+ *   Pointer of the allocated memory, NULL otherwise.\n+ */\n+static void *\n+mlx5_alloc_align(size_t size, unsigned int align, unsigned int zero)\n+{\n+\tvoid *buf;\n+\tbuf = memalign(align, size);\n+\tif (!buf) {\n+\t\tDRV_LOG(ERR, \"Couldn't allocate buf.\\n\");\n+\t\treturn NULL;\n+\t}\n+\tif (zero)\n+\t\tmemset(buf, 0, size);\n+\treturn buf;\n+}\n+\n+void *\n+mlx5_malloc(uint32_t flags, size_t size, unsigned int align, int socket)\n+{\n+\tvoid *addr;\n+\tbool rte_mem;\n+\n+\t/*\n+\t * If neither system memory nor rte memory is required, allocate\n+\t * memory according to mlx5_sys_mem.enable.\n+\t */\n+\tif (flags & MLX5_MEM_RTE)\n+\t\trte_mem = true;\n+\telse if (flags & MLX5_MEM_SYS)\n+\t\trte_mem = false;\n+\telse\n+\t\trte_mem = mlx5_sys_mem.enable ? false : true;\n+\tif (rte_mem) {\n+\t\tif (flags & MLX5_MEM_ZERO)\n+\t\t\taddr = rte_zmalloc_socket(NULL, size, align, socket);\n+\t\telse\n+\t\t\taddr = rte_malloc_socket(NULL, size, align, socket);\n+\t\tmlx5_mem_update_msl(addr);\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\t\tif (addr)\n+\t\t\trte_atomic64_inc(&mlx5_sys_mem.malloc_rte);\n+#endif\n+\t\treturn addr;\n+\t}\n+\t/* The memory will be allocated from system. */\n+\tif (align)\n+\t\taddr = mlx5_alloc_align(size, align, !!(flags & MLX5_MEM_ZERO));\n+\telse if (flags & MLX5_MEM_ZERO)\n+\t\taddr = calloc(1, size);\n+\telse\n+\t\taddr = malloc(size);\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\tif (addr)\n+\t\trte_atomic64_inc(&mlx5_sys_mem.malloc_sys);\n+#endif\n+\treturn addr;\n+}\n+\n+void *\n+mlx5_realloc(void *addr, uint32_t flags, size_t size, unsigned int align,\n+\t     int socket)\n+{\n+\tvoid *new_addr;\n+\tbool rte_mem;\n+\n+\t/* Allocate directly if old memory address is NULL. */\n+\tif (!addr)\n+\t\treturn mlx5_malloc(flags, size, align, socket);\n+\t/* Get the memory type. */\n+\tif (flags & MLX5_MEM_RTE)\n+\t\trte_mem = true;\n+\telse if (flags & MLX5_MEM_SYS)\n+\t\trte_mem = false;\n+\telse\n+\t\trte_mem = mlx5_sys_mem.enable ? false : true;\n+\t/* Check if old memory and to be allocated memory are the same type. */\n+\tif (rte_mem != mlx5_mem_is_rte(addr)) {\n+\t\tDRV_LOG(ERR, \"Couldn't reallocate to different memory type.\");\n+\t\treturn NULL;\n+\t}\n+\t/* Allocate memory from rte memory. */\n+\tif (rte_mem) {\n+\t\tnew_addr = rte_realloc_socket(addr, size, align, socket);\n+\t\tmlx5_mem_update_msl(new_addr);\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\t\tif (new_addr)\n+\t\t\trte_atomic64_inc(&mlx5_sys_mem.realloc_rte);\n+#endif\n+\t\treturn new_addr;\n+\t}\n+\t/* Align is not supported for system memory. */\n+\tif (align) {\n+\t\tDRV_LOG(ERR, \"Couldn't reallocate with alignment\");\n+\t\treturn NULL;\n+\t}\n+\tnew_addr = realloc(addr, size);\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\tif (new_addr)\n+\t\trte_atomic64_inc(&mlx5_sys_mem.realloc_sys);\n+#endif\n+\treturn new_addr;\n+}\n+\n+void\n+mlx5_free(void *addr)\n+{\n+\tif (addr == NULL)\n+\t\treturn;\n+\tif (!mlx5_mem_is_rte(addr)) {\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\t\trte_atomic64_inc(&mlx5_sys_mem.free_sys);\n+#endif\n+\t\tfree(addr);\n+\t} else {\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\t\trte_atomic64_inc(&mlx5_sys_mem.free_rte);\n+#endif\n+\t\trte_free(addr);\n+\t}\n+}\n+\n+void\n+mlx5_memory_stat_dump(void)\n+{\n+#ifdef RTE_LIBRTE_MLX5_DEBUG\n+\tDRV_LOG(INFO, \"System memory malloc:%\"PRIi64\", realloc:%\"PRIi64\",\"\n+\t\t\" free:%\"PRIi64\"\\nRTE memory malloc:%\"PRIi64\",\"\n+\t\t\" realloc:%\"PRIi64\", free:%\"PRIi64\"\\nMSL miss:%\"PRIi64\",\"\n+\t\t\" update:%\"PRIi64\"\",\n+\t\trte_atomic64_read(&mlx5_sys_mem.malloc_sys),\n+\t\trte_atomic64_read(&mlx5_sys_mem.realloc_sys),\n+\t\trte_atomic64_read(&mlx5_sys_mem.free_sys),\n+\t\trte_atomic64_read(&mlx5_sys_mem.malloc_rte),\n+\t\trte_atomic64_read(&mlx5_sys_mem.realloc_rte),\n+\t\trte_atomic64_read(&mlx5_sys_mem.free_rte),\n+\t\trte_atomic64_read(&mlx5_sys_mem.msl_miss),\n+\t\trte_atomic64_read(&mlx5_sys_mem.msl_update));\n+#endif\n+}\n+\n+void\n+mlx5_malloc_mem_select(uint32_t sys_mem_en)\n+{\n+\t/*\n+\t * The initialization should be called only once and all devices\n+\t * should use the same memory type. Otherwise, when new device is\n+\t * being attached with some different memory allocation configuration,\n+\t * the memory will get wrong behavior or a failure will be raised.\n+\t */\n+\tif (!mlx5_sys_mem.init) {\n+\t\tif (sys_mem_en)\n+\t\t\tmlx5_sys_mem.enable = 1;\n+\t\tmlx5_sys_mem.init = 1;\n+\t\tDRV_LOG(INFO, \"%s is selected.\", sys_mem_en ? \"SYS_MEM\" : \"RTE_MEM\");\n+\t} else if (mlx5_sys_mem.enable != sys_mem_en) {\n+\t\tDRV_LOG(WARNING, \"%s is already selected.\",\n+\t\t\tmlx5_sys_mem.enable ? \"SYS_MEM\" : \"RTE_MEM\");\n+\t}\n+}\ndiff --git a/drivers/common/mlx5/mlx5_malloc.h b/drivers/common/mlx5/mlx5_malloc.h\nnew file mode 100644\nindex 0000000..d3e5f5b\n--- /dev/null\n+++ b/drivers/common/mlx5/mlx5_malloc.h\n@@ -0,0 +1,99 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2020 Mellanox Technologies, Ltd\n+ */\n+\n+#ifndef MLX5_MALLOC_H_\n+#define MLX5_MALLOC_H_\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+enum mlx5_mem_flags {\n+\tMLX5_MEM_ANY = 0,\n+\t/* Memory will be allocated dpends on sys_mem_en. */\n+\tMLX5_MEM_SYS = 1 << 0,\n+\t/* Memory should be allocated from system. */\n+\tMLX5_MEM_RTE = 1 << 1,\n+\t/* Memory should be allocated from rte hugepage. */\n+\tMLX5_MEM_ZERO = 1 << 2,\n+\t/* Memory should be cleared to zero. */\n+};\n+\n+/**\n+ * Select the PMD memory allocate preference.\n+ *\n+ * Once sys_mem_en is set, the default memory allocate will from\n+ * system only if an explicitly flag is set to order the memory\n+ * from rte hugepage memory.\n+ *\n+ * @param sys_mem_en\n+ *   Use system memory or not.\n+ */\n+__rte_internal\n+void mlx5_malloc_mem_select(uint32_t sys_mem_en);\n+\n+/**\n+ * Dump the PMD memory usage statistic.\n+ */\n+__rte_internal\n+void mlx5_memory_stat_dump(void);\n+\n+/**\n+ * Memory allocate function.\n+ *\n+ * @param flags\n+ *   The bits as enum mlx5_mem_flags defined.\n+ * @param size\n+ *   Memory size to be allocated.\n+ * @param align\n+ *   Memory alignment.\n+ * @param socket\n+ *   The socket memory should allocated.\n+ *   Valid only when allocate the memory from rte hugepage.\n+ *\n+ * @return\n+ *   Pointer of the allocated memory, NULL otherwise.\n+ */\n+__rte_internal\n+void *mlx5_malloc(uint32_t flags, size_t size, unsigned int align, int socket);\n+\n+/**\n+ * Memory reallocate function.\n+ *\n+ *\n+ *\n+ * @param addr\n+ *   The memory to be reallocated.\n+ * @param flags\n+ *   The bits as enum mlx5_mem_flags defined.\n+ * @param size\n+ *   Memory size to be allocated.\n+ * @param align\n+ *   Memory alignment.\n+ * @param socket\n+ *   The socket memory should allocated.\n+ *   Valid only when allocate the memory from rte hugepage.\n+ *\n+ * @return\n+ *   Pointer of the allocated memory, NULL otherwise.\n+ */\n+\n+__rte_internal\n+void *mlx5_realloc(void *addr, uint32_t flags, size_t size, unsigned int align,\n+\t\t   int socket);\n+\n+/**\n+ * Memory free function.\n+ *\n+ * @param addr\n+ *   The memory address to be freed..\n+ */\n+__rte_internal\n+void mlx5_free(void *addr);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif\ndiff --git a/drivers/common/mlx5/rte_common_mlx5_version.map b/drivers/common/mlx5/rte_common_mlx5_version.map\nindex ae57ebd..381a455 100644\n--- a/drivers/common/mlx5/rte_common_mlx5_version.map\n+++ b/drivers/common/mlx5/rte_common_mlx5_version.map\n@@ -81,5 +81,11 @@ INTERNAL {\n \tmlx5_release_dbr;\n \n \tmlx5_translate_port_name;\n+\n+\tmlx5_malloc_mem_select;\n+\tmlx5_memory_stat_dump;\n+\tmlx5_malloc;\n+\tmlx5_realloc;\n+\tmlx5_free;\n };\n \n",
    "prefixes": [
        "v2",
        "1/7"
    ]
}