get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 120246,
    "url": "http://patches.dpdk.org/api/patches/120246/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20221129082109.6809-1-syalavarthi@marvell.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": "<20221129082109.6809-1-syalavarthi@marvell.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20221129082109.6809-1-syalavarthi@marvell.com",
    "date": "2022-11-29T08:20:58",
    "name": "[v2,01/12] app/mldev: implement test framework for mldev",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "9cb9e6b87624dee2b10453e4f77e948cccab110f",
    "submitter": {
        "id": 2480,
        "url": "http://patches.dpdk.org/api/people/2480/?format=api",
        "name": "Srikanth Yalavarthi",
        "email": "syalavarthi@marvell.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20221129082109.6809-1-syalavarthi@marvell.com/mbox/",
    "series": [
        {
            "id": 25915,
            "url": "http://patches.dpdk.org/api/series/25915/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=25915",
            "date": "2022-11-29T08:20:58",
            "name": "[v2,01/12] app/mldev: implement test framework for mldev",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/25915/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/120246/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/120246/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 mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 3776EA0093;\n\tTue, 29 Nov 2022 09:21:18 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 283EC410D1;\n\tTue, 29 Nov 2022 09:21:18 +0100 (CET)",
            "from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com\n [67.231.148.174])\n by mails.dpdk.org (Postfix) with ESMTP id E89F44067E\n for <dev@dpdk.org>; Tue, 29 Nov 2022 09:21:16 +0100 (CET)",
            "from pps.filterd (m0045849.ppops.net [127.0.0.1])\n by mx0a-0016f401.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id\n 2AT3NpLQ005657; Tue, 29 Nov 2022 00:21:16 -0800",
            "from dc5-exch02.marvell.com ([199.233.59.182])\n by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 3m5a508yyp-1\n (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT);\n Tue, 29 Nov 2022 00:21:15 -0800",
            "from DC5-EXCH02.marvell.com (10.69.176.39) by DC5-EXCH02.marvell.com\n (10.69.176.39) with Microsoft SMTP Server (TLS) id 15.0.1497.18;\n Tue, 29 Nov 2022 00:21:14 -0800",
            "from maili.marvell.com (10.69.176.80) by DC5-EXCH02.marvell.com\n (10.69.176.39) with Microsoft SMTP Server id 15.0.1497.18 via Frontend\n Transport; Tue, 29 Nov 2022 00:21:14 -0800",
            "from ml-host-33.caveonetworks.com (unknown [10.110.143.233])\n by maili.marvell.com (Postfix) with ESMTP id CC8773F7051;\n Tue, 29 Nov 2022 00:21:13 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com;\n h=from : to : cc :\n subject : date : message-id : in-reply-to : references : mime-version :\n content-type; s=pfpt0220; bh=rr0PE8zpkss70+98yKdDwypMHlX7oDZixxFBN+uER3A=;\n b=DXq3qHil+M13W927uQhoqPzxMyyhjlxi96FkcYY5SlHxnURIpugKwC3KCthaEso5BDsU\n 0i2LHEBYt7pFisOVW2l7M5l/4RbUhhTP7O2MSXtUgFHvFtJ3+yvkA35+XlCdw9ApEE4P\n yTwF3SRK7J1AreZrU46Kt5qlKOq1ox0T4Can4wwVwIki+JUUCahRsiYH5ZSHgH6Ixv9o\n 2qK4E1VsRtXcVJ1HvaYg/u4ki8CrI8amn1sDGC0TJmf2PlYpW0+mH1y/fSfsoJN+QiBn\n ZWDrmGmiXmjI0jorhA+Pw12K2Ys6PxSEeOZZkq6PopAn48c5jEC1N4Yor2VshYg486N3 iA==",
        "From": "Srikanth Yalavarthi <syalavarthi@marvell.com>",
        "To": "Thomas Monjalon <thomas@monjalon.net>, Srikanth Yalavarthi\n <syalavarthi@marvell.com>",
        "CC": "<dev@dpdk.org>, <sshankarnara@marvell.com>, <jerinj@marvell.com>",
        "Subject": "[PATCH v2 01/12] app/mldev: implement test framework for mldev",
        "Date": "Tue, 29 Nov 2022 00:20:58 -0800",
        "Message-ID": "<20221129082109.6809-1-syalavarthi@marvell.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20221129070746.20396-2-syalavarthi@marvell.com>",
        "References": "<20221129070746.20396-2-syalavarthi@marvell.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Proofpoint-ORIG-GUID": "8rhX1n0D9gGfWxsJRxTQ0CUUNwdbma66",
        "X-Proofpoint-GUID": "8rhX1n0D9gGfWxsJRxTQ0CUUNwdbma66",
        "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.219,Aquarius:18.0.895,Hydra:6.0.545,FMLib:17.11.122.1\n definitions=2022-11-29_06,2022-11-28_02,2022-06-22_01",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "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"
    },
    "content": "Implemented framework for mldev test application. New test cases\ncan be added using the framework. Support is also enabled to add\noptions specific to the test cases. User can launch the tests by\nspecifying the name of test as part of launch arguments.\n\nCode to parse command line arguments is imported from\ntest-eventdev, with support to parse additional data types.\n\nCommon arguments supported include:\n\ntest        : name of the test application to run\ndev_id      : device id of the ML device\nsocket_id   : socket_id of application resources\ndebug       : enable debugging\nhelp        : print help\n\nSample launch command:\n./dpdk-test-mldev -- --test <testname> --dev_id <dev_id> \\\n--socket_id <socket_id>\n\nSigned-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>\n---\nDepends-on: series-25753 (\"mldev: introduce machine learning device library\")\n\n MAINTAINERS                 |   1 +\n app/meson.build             |   1 +\n app/test-mldev/meson.build  |  17 ++\n app/test-mldev/ml_common.h  |  29 +++\n app/test-mldev/ml_main.c    | 118 +++++++++++\n app/test-mldev/ml_options.c | 160 +++++++++++++++\n app/test-mldev/ml_options.h |  31 +++\n app/test-mldev/ml_test.c    |  45 +++++\n app/test-mldev/ml_test.h    |  75 +++++++\n app/test-mldev/parser.c     | 380 ++++++++++++++++++++++++++++++++++++\n app/test-mldev/parser.h     |  55 ++++++\n 11 files changed, 912 insertions(+)\n create mode 100644 app/test-mldev/meson.build\n create mode 100644 app/test-mldev/ml_common.h\n create mode 100644 app/test-mldev/ml_main.c\n create mode 100644 app/test-mldev/ml_options.c\n create mode 100644 app/test-mldev/ml_options.h\n create mode 100644 app/test-mldev/ml_test.c\n create mode 100644 app/test-mldev/ml_test.h\n create mode 100644 app/test-mldev/parser.c\n create mode 100644 app/test-mldev/parser.h",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 0c3e6d28e9..1edea42fad 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -538,6 +538,7 @@ F: doc/guides/prog_guide/rawdev.rst\n ML device API - EXPERIMENTAL\n M: Srikanth Yalavarthi <syalavarthi@marvell.com>\n F: lib/mldev/\n+F: app/test-mldev/\n F: doc/guides/prog_guide/mldev.rst\n \n \ndiff --git a/app/meson.build b/app/meson.build\nindex e32ea4bd5c..74d2420f67 100644\n--- a/app/meson.build\n+++ b/app/meson.build\n@@ -23,6 +23,7 @@ apps = [\n         'test-fib',\n         'test-flow-perf',\n         'test-gpudev',\n+        'test-mldev',\n         'test-pipeline',\n         'test-pmd',\n         'test-regex',\ndiff --git a/app/test-mldev/meson.build b/app/test-mldev/meson.build\nnew file mode 100644\nindex 0000000000..8ca2e1a1c1\n--- /dev/null\n+++ b/app/test-mldev/meson.build\n@@ -0,0 +1,17 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright (c) 2022 Marvell.\n+\n+if is_windows\n+    build = false\n+    reason = 'not supported on Windows'\n+    subdir_done()\n+endif\n+\n+sources = files(\n+        'ml_main.c',\n+        'ml_options.c',\n+        'ml_test.c',\n+        'parser.c',\n+)\n+\n+deps += ['mldev']\ndiff --git a/app/test-mldev/ml_common.h b/app/test-mldev/ml_common.h\nnew file mode 100644\nindex 0000000000..065180b619\n--- /dev/null\n+++ b/app/test-mldev/ml_common.h\n@@ -0,0 +1,29 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#ifndef _ML_COMMON_\n+#define _ML_COMMON_\n+\n+#include <stdio.h>\n+\n+#define CLNRM \"\\x1b[0m\"\n+#define CLRED \"\\x1b[31m\"\n+#define CLGRN \"\\x1b[32m\"\n+#define CLYEL \"\\x1b[33m\"\n+\n+#define ML_STR_FMT 20\n+\n+#define ml_err(fmt, args...) fprintf(stderr, CLRED \"error: %s() \" fmt CLNRM \"\\n\", __func__, ##args)\n+\n+#define ml_info(fmt, args...) fprintf(stdout, CLYEL \"\" fmt CLNRM \"\\n\", ##args)\n+\n+#define ml_dump(str, fmt, val...) printf(\"\\t%-*s : \" fmt \"\\n\", ML_STR_FMT, str, ##val)\n+\n+#define ml_dump_begin(str) printf(\"\\t%-*s :\\n\\t{\\n\", ML_STR_FMT, str)\n+\n+#define ml_dump_list(str, id, val) printf(\"\\t%*s[%2u] : %s\\n\", ML_STR_FMT - 4, str, id, val)\n+\n+#define ml_dump_end printf(\"\\b\\t}\\n\\n\")\n+\n+#endif /* _ML_COMMON_*/\ndiff --git a/app/test-mldev/ml_main.c b/app/test-mldev/ml_main.c\nnew file mode 100644\nindex 0000000000..d6652cd7b7\n--- /dev/null\n+++ b/app/test-mldev/ml_main.c\n@@ -0,0 +1,118 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#include <stdint.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+\n+#include <rte_debug.h>\n+#include <rte_eal.h>\n+#include <rte_mldev.h>\n+\n+#include \"ml_common.h\"\n+#include \"ml_options.h\"\n+#include \"ml_test.h\"\n+\n+struct ml_options opt;\n+struct ml_test *test;\n+\n+int\n+main(int argc, char **argv)\n+{\n+\tuint16_t mldevs;\n+\tint ret;\n+\n+\tret = rte_eal_init(argc, argv);\n+\tif (ret < 0)\n+\t\trte_panic(\"invalid EAL arguments\\n\");\n+\targc -= ret;\n+\targv += ret;\n+\n+\tmldevs = rte_ml_dev_count();\n+\tif (!mldevs)\n+\t\trte_panic(\"no mldev devices found\\n\");\n+\n+\t/* set default values for options */\n+\tml_options_default(&opt);\n+\n+\t/* parse the command line arguments */\n+\tret = ml_options_parse(&opt, argc, argv);\n+\tif (ret) {\n+\t\tml_err(\"parsing one or more user options failed\");\n+\t\tgoto error;\n+\t}\n+\n+\t/* get test struct from name */\n+\ttest = ml_test_get(opt.test_name);\n+\tif (test == NULL) {\n+\t\tml_err(\"failed to find requested test: %s\", opt.test_name);\n+\t\tgoto error;\n+\t}\n+\n+\tif (test->ops.test_result == NULL) {\n+\t\tml_err(\"%s: ops.test_result not found\", opt.test_name);\n+\t\tgoto error;\n+\t}\n+\n+\t/* check test options */\n+\tif (test->ops.opt_check) {\n+\t\tif (test->ops.opt_check(&opt)) {\n+\t\t\tml_err(\"invalid command line argument\");\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n+\n+\t/* check the device capability */\n+\tif (test->ops.cap_check) {\n+\t\tif (test->ops.cap_check(&opt) == false) {\n+\t\t\tml_info(\"unsupported test: %s\", opt.test_name);\n+\t\t\tret = ML_TEST_UNSUPPORTED;\n+\t\t\tgoto no_cap;\n+\t\t}\n+\t}\n+\n+\t/* dump options */\n+\tif (opt.debug) {\n+\t\tif (test->ops.opt_dump)\n+\t\t\ttest->ops.opt_dump(&opt);\n+\t}\n+\n+\t/* test specific setup */\n+\tif (test->ops.test_setup) {\n+\t\tif (test->ops.test_setup(test, &opt)) {\n+\t\t\tml_err(\"failed to setup test: %s\", opt.test_name);\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n+\n+\t/* test driver */\n+\tif (test->ops.test_driver)\n+\t\ttest->ops.test_driver(test, &opt);\n+\n+\t/* get result */\n+\tif (test->ops.test_result)\n+\t\tret = test->ops.test_result(test, &opt);\n+\n+\tif (test->ops.test_destroy)\n+\t\ttest->ops.test_destroy(test, &opt);\n+\n+no_cap:\n+\tif (ret == ML_TEST_SUCCESS) {\n+\t\tprintf(\"Result: \" CLGRN \"%s\" CLNRM \"\\n\", \"Success\");\n+\t} else if (ret == ML_TEST_FAILED) {\n+\t\tprintf(\"Result: \" CLRED \"%s\" CLNRM \"\\n\", \"Failed\");\n+\t\treturn EXIT_FAILURE;\n+\t} else if (ret == ML_TEST_UNSUPPORTED) {\n+\t\tprintf(\"Result: \" CLYEL \"%s\" CLNRM \"\\n\", \"Unsupported\");\n+\t}\n+\n+\trte_eal_cleanup();\n+\n+\treturn 0;\n+\n+error:\n+\trte_eal_cleanup();\n+\n+\treturn EXIT_FAILURE;\n+}\ndiff --git a/app/test-mldev/ml_options.c b/app/test-mldev/ml_options.c\nnew file mode 100644\nindex 0000000000..8fd7760e36\n--- /dev/null\n+++ b/app/test-mldev/ml_options.c\n@@ -0,0 +1,160 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#include <errno.h>\n+#include <getopt.h>\n+#include <stdbool.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <string.h>\n+\n+#include <rte_memory.h>\n+#include <rte_mldev.h>\n+#include <rte_string_fns.h>\n+\n+#include \"ml_common.h\"\n+#include \"ml_options.h\"\n+#include \"ml_test.h\"\n+#include \"parser.h\"\n+\n+typedef int (*option_parser_t)(struct ml_options *opt, const char *arg);\n+\n+void\n+ml_options_default(struct ml_options *opt)\n+{\n+\tmemset(opt, 0, sizeof(*opt));\n+\tstrlcpy(opt->test_name, \"ml_test\", ML_TEST_NAME_MAX_LEN);\n+\topt->dev_id = 0;\n+\topt->socket_id = SOCKET_ID_ANY;\n+\topt->debug = false;\n+}\n+\n+struct long_opt_parser {\n+\tconst char *lgopt_name;\n+\toption_parser_t parser_fn;\n+};\n+\n+static int\n+ml_parse_test_name(struct ml_options *opt, const char *arg)\n+{\n+\tstrlcpy(opt->test_name, arg, ML_TEST_NAME_MAX_LEN);\n+\treturn 0;\n+}\n+\n+static int\n+ml_parse_dev_id(struct ml_options *opt, const char *arg)\n+{\n+\tint ret;\n+\n+\tret = parser_read_int16(&opt->dev_id, arg);\n+\n+\tif (ret < 0)\n+\t\treturn -EINVAL;\n+\n+\treturn ret;\n+}\n+\n+static int\n+ml_parse_socket_id(struct ml_options *opt, const char *arg)\n+{\n+\topt->socket_id = atoi(arg);\n+\n+\treturn 0;\n+}\n+\n+static void\n+ml_dump_test_options(const char *testname)\n+{\n+\tRTE_SET_USED(testname);\n+}\n+\n+static void\n+print_usage(char *program)\n+{\n+\tprintf(\"\\nusage : %s [EAL options] -- [application options]\\n\", program);\n+\tprintf(\"application options:\\n\");\n+\tprintf(\"\\t--test             : name of the test application to run\\n\"\n+\t       \"\\t--dev_id           : device id of the ML device\\n\"\n+\t       \"\\t--socket_id        : socket_id of application resources\\n\"\n+\t       \"\\t--debug            : enable debug mode\\n\"\n+\t       \"\\t--help             : print help\\n\");\n+\tprintf(\"\\n\");\n+\tprintf(\"available tests and test specific application options:\\n\");\n+\tml_test_dump_names(ml_dump_test_options);\n+}\n+\n+static struct option lgopts[] = {{ML_TEST, 1, 0, 0},\t  {ML_DEVICE_ID, 1, 0, 0},\n+\t\t\t\t {ML_SOCKET_ID, 1, 0, 0}, {ML_DEBUG, 0, 0, 0},\n+\t\t\t\t {ML_HELP, 0, 0, 0},\t  {NULL, 0, 0, 0}};\n+\n+static int\n+ml_opts_parse_long(int opt_idx, struct ml_options *opt)\n+{\n+\tunsigned int i;\n+\n+\tstruct long_opt_parser parsermap[] = {\n+\t\t{ML_TEST, ml_parse_test_name},\n+\t\t{ML_DEVICE_ID, ml_parse_dev_id},\n+\t\t{ML_SOCKET_ID, ml_parse_socket_id},\n+\t};\n+\n+\tfor (i = 0; i < RTE_DIM(parsermap); i++) {\n+\t\tif (strncmp(lgopts[opt_idx].name, parsermap[i].lgopt_name,\n+\t\t\t    strlen(lgopts[opt_idx].name)) == 0)\n+\t\t\treturn parsermap[i].parser_fn(opt, optarg);\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+int\n+ml_options_parse(struct ml_options *opt, int argc, char **argv)\n+{\n+\tint opt_idx;\n+\tint retval;\n+\tint opts;\n+\n+\twhile ((opts = getopt_long(argc, argv, \"\", lgopts, &opt_idx)) != EOF) {\n+\t\tswitch (opts) {\n+\t\tcase 0: /* parse long options */\n+\t\t\tif (!strcmp(lgopts[opt_idx].name, \"debug\")) {\n+\t\t\t\topt->debug = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tif (!strcmp(lgopts[opt_idx].name, \"help\")) {\n+\t\t\t\tprint_usage(argv[0]);\n+\t\t\t\texit(EXIT_SUCCESS);\n+\t\t\t}\n+\n+\t\t\tretval = ml_opts_parse_long(opt_idx, opt);\n+\t\t\tif (retval != 0)\n+\t\t\t\treturn retval;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void\n+ml_options_dump(struct ml_options *opt)\n+{\n+\tstruct rte_ml_dev_info dev_info;\n+\n+\trte_ml_dev_info_get(opt->dev_id, &dev_info);\n+\n+\tml_dump(\"driver\", \"%s\", dev_info.driver_name);\n+\tml_dump(\"test\", \"%s\", opt->test_name);\n+\tml_dump(\"dev_id\", \"%d\", opt->dev_id);\n+\n+\tif (opt->socket_id == SOCKET_ID_ANY)\n+\t\tml_dump(\"socket_id\", \"%d (SOCKET_ID_ANY)\", opt->socket_id);\n+\telse\n+\t\tml_dump(\"socket_id\", \"%d\", opt->socket_id);\n+\n+\tml_dump(\"debug\", \"%s\", (opt->debug ? \"true\" : \"false\"));\n+}\ndiff --git a/app/test-mldev/ml_options.h b/app/test-mldev/ml_options.h\nnew file mode 100644\nindex 0000000000..05311a9a47\n--- /dev/null\n+++ b/app/test-mldev/ml_options.h\n@@ -0,0 +1,31 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#ifndef _ML_OPTIONS_\n+#define _ML_OPTIONS_\n+\n+#include <stdbool.h>\n+#include <stdint.h>\n+\n+#define ML_TEST_NAME_MAX_LEN 32\n+\n+/* Options names */\n+#define ML_TEST\t     (\"test\")\n+#define ML_DEVICE_ID (\"dev_id\")\n+#define ML_SOCKET_ID (\"socket_id\")\n+#define ML_DEBUG     (\"debug\")\n+#define ML_HELP\t     (\"help\")\n+\n+struct ml_options {\n+\tchar test_name[ML_TEST_NAME_MAX_LEN];\n+\tint16_t dev_id;\n+\tint socket_id;\n+\tbool debug;\n+};\n+\n+void ml_options_default(struct ml_options *opt);\n+int ml_options_parse(struct ml_options *opt, int argc, char **argv);\n+void ml_options_dump(struct ml_options *opt);\n+\n+#endif /* _ML_OPTIONS_ */\ndiff --git a/app/test-mldev/ml_test.c b/app/test-mldev/ml_test.c\nnew file mode 100644\nindex 0000000000..2304712764\n--- /dev/null\n+++ b/app/test-mldev/ml_test.c\n@@ -0,0 +1,45 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#include <stdio.h>\n+#include <string.h>\n+#include <sys/queue.h>\n+\n+#include \"ml_test.h\"\n+\n+static STAILQ_HEAD(, ml_test_entry) head = STAILQ_HEAD_INITIALIZER(head);\n+\n+void\n+ml_test_register(struct ml_test_entry *entry)\n+{\n+\tSTAILQ_INSERT_TAIL(&head, entry, next);\n+}\n+\n+struct ml_test *\n+ml_test_get(const char *name)\n+{\n+\tstruct ml_test_entry *entry;\n+\n+\tif (!name)\n+\t\treturn NULL;\n+\n+\tSTAILQ_FOREACH(entry, &head, next)\n+\tif (!strncmp(entry->test.name, name, strlen(name)))\n+\t\treturn &entry->test;\n+\n+\treturn NULL;\n+}\n+\n+void\n+ml_test_dump_names(void (*f)(const char *name))\n+{\n+\tstruct ml_test_entry *entry;\n+\n+\tSTAILQ_FOREACH(entry, &head, next)\n+\t{\n+\t\tif (entry->test.name)\n+\t\t\tprintf(\"\\t %s\\n\", entry->test.name);\n+\t\tf(entry->test.name);\n+\t}\n+}\ndiff --git a/app/test-mldev/ml_test.h b/app/test-mldev/ml_test.h\nnew file mode 100644\nindex 0000000000..4a1430ec1b\n--- /dev/null\n+++ b/app/test-mldev/ml_test.h\n@@ -0,0 +1,75 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#ifndef _ML_TEST_\n+#define _ML_TEST_\n+\n+#include <stdbool.h>\n+#include <string.h>\n+#include <sys/queue.h>\n+\n+#include <rte_common.h>\n+\n+#include \"ml_options.h\"\n+\n+#define ML_TEST_MAX_POOL_SIZE 256\n+\n+enum ml_test_result {\n+\tML_TEST_SUCCESS,\n+\tML_TEST_FAILED,\n+\tML_TEST_UNSUPPORTED,\n+};\n+\n+struct ml_test;\n+\n+typedef bool (*ml_test_capability_check_t)(struct ml_options *opt);\n+typedef int (*ml_test_options_check_t)(struct ml_options *opt);\n+typedef void (*ml_test_options_dump_t)(struct ml_options *opt);\n+typedef int (*ml_test_setup_t)(struct ml_test *test, struct ml_options *opt);\n+typedef void (*ml_test_destroy_t)(struct ml_test *test, struct ml_options *opt);\n+typedef int (*ml_test_driver_t)(struct ml_test *test, struct ml_options *opt);\n+typedef int (*ml_test_result_t)(struct ml_test *test, struct ml_options *opt);\n+\n+struct ml_test_ops {\n+\tml_test_capability_check_t cap_check;\n+\tml_test_options_check_t opt_check;\n+\tml_test_options_dump_t opt_dump;\n+\tml_test_setup_t test_setup;\n+\tml_test_destroy_t test_destroy;\n+\tml_test_driver_t test_driver;\n+\tml_test_result_t test_result;\n+};\n+\n+struct ml_test {\n+\tconst char *name;\n+\tvoid *test_priv;\n+\tstruct ml_test_ops ops;\n+};\n+\n+struct ml_test_entry {\n+\tstruct ml_test test;\n+\n+\tSTAILQ_ENTRY(ml_test_entry) next;\n+};\n+\n+static inline void *\n+ml_test_priv(struct ml_test *test)\n+{\n+\treturn test->test_priv;\n+}\n+\n+struct ml_test *ml_test_get(const char *name);\n+void ml_test_register(struct ml_test_entry *test);\n+void ml_test_dump_names(void (*f)(const char *));\n+\n+#define ML_TEST_REGISTER(nm)                                                                       \\\n+\tstatic struct ml_test_entry _ml_test_entry_##nm;                                           \\\n+\tRTE_INIT(ml_test_##nm)                                                                     \\\n+\t{                                                                                          \\\n+\t\t_ml_test_entry_##nm.test.name = RTE_STR(nm);                                       \\\n+\t\tmemcpy(&_ml_test_entry_##nm.test.ops, &nm, sizeof(struct ml_test_ops));            \\\n+\t\tml_test_register(&_ml_test_entry_##nm);                                            \\\n+\t}\n+\n+#endif /* _ML_TEST_ */\ndiff --git a/app/test-mldev/parser.c b/app/test-mldev/parser.c\nnew file mode 100644\nindex 0000000000..0b7fb63fe5\n--- /dev/null\n+++ b/app/test-mldev/parser.c\n@@ -0,0 +1,380 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2016 Intel Corporation.\n+ * Copyright (c) 2017 Cavium, Inc.\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#include <ctype.h>\n+#include <errno.h>\n+#include <stdbool.h>\n+#include <stdint.h>\n+#include <stdlib.h>\n+#include <string.h>\n+\n+#include <rte_common.h>\n+\n+#include \"parser.h\"\n+\n+static uint32_t\n+get_hex_val(char c)\n+{\n+\tswitch (c) {\n+\tcase '0':\n+\tcase '1':\n+\tcase '2':\n+\tcase '3':\n+\tcase '4':\n+\tcase '5':\n+\tcase '6':\n+\tcase '7':\n+\tcase '8':\n+\tcase '9':\n+\t\treturn c - '0';\n+\tcase 'A':\n+\tcase 'B':\n+\tcase 'C':\n+\tcase 'D':\n+\tcase 'E':\n+\tcase 'F':\n+\t\treturn c - 'A' + 10;\n+\tcase 'a':\n+\tcase 'b':\n+\tcase 'c':\n+\tcase 'd':\n+\tcase 'e':\n+\tcase 'f':\n+\t\treturn c - 'a' + 10;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n+int\n+parser_read_arg_bool(const char *p)\n+{\n+\tp = skip_white_spaces(p);\n+\tint result = -EINVAL;\n+\n+\tif (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||\n+\t    ((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {\n+\t\tp += 3;\n+\t\tresult = 1;\n+\t}\n+\n+\tif (((p[0] == 'o') && (p[1] == 'n')) || ((p[0] == 'O') && (p[1] == 'N'))) {\n+\t\tp += 2;\n+\t\tresult = 1;\n+\t}\n+\n+\tif (((p[0] == 'n') && (p[1] == 'o')) || ((p[0] == 'N') && (p[1] == 'O'))) {\n+\t\tp += 2;\n+\t\tresult = 0;\n+\t}\n+\n+\tif (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||\n+\t    ((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {\n+\t\tp += 3;\n+\t\tresult = 0;\n+\t}\n+\n+\tp = skip_white_spaces(p);\n+\n+\tif (p[0] != '\\0')\n+\t\treturn -EINVAL;\n+\n+\treturn result;\n+}\n+\n+int\n+parser_read_uint64(uint64_t *value, const char *p)\n+{\n+\tchar *next;\n+\tuint64_t val;\n+\n+\tp = skip_white_spaces(p);\n+\tif (!isdigit(*p))\n+\t\treturn -EINVAL;\n+\n+\tval = strtoul(p, &next, 10);\n+\tif (p == next)\n+\t\treturn -EINVAL;\n+\n+\tp = next;\n+\tswitch (*p) {\n+\tcase 'T':\n+\t\tval *= 1024ULL;\n+\t\t/* fall through */\n+\tcase 'G':\n+\t\tval *= 1024ULL;\n+\t\t/* fall through */\n+\tcase 'M':\n+\t\tval *= 1024ULL;\n+\t\t/* fall through */\n+\tcase 'k':\n+\tcase 'K':\n+\t\tval *= 1024ULL;\n+\t\tp++;\n+\t\tbreak;\n+\t}\n+\n+\tp = skip_white_spaces(p);\n+\tif (*p != '\\0')\n+\t\treturn -EINVAL;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_int32(int32_t *value, const char *p)\n+{\n+\tchar *next;\n+\tint32_t val;\n+\n+\tp = skip_white_spaces(p);\n+\tif (!isdigit(*p))\n+\t\treturn -EINVAL;\n+\n+\tval = strtol(p, &next, 10);\n+\tif (p == next)\n+\t\treturn -EINVAL;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_int16(int16_t *value, const char *p)\n+{\n+\tchar *next;\n+\tint16_t val;\n+\n+\tp = skip_white_spaces(p);\n+\tif (!isdigit(*p))\n+\t\treturn -EINVAL;\n+\n+\tval = strtol(p, &next, 10);\n+\tif (p == next)\n+\t\treturn -EINVAL;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_uint64_hex(uint64_t *value, const char *p)\n+{\n+\tchar *next;\n+\tuint64_t val;\n+\n+\tp = skip_white_spaces(p);\n+\n+\tval = strtoul(p, &next, 16);\n+\tif (p == next)\n+\t\treturn -EINVAL;\n+\n+\tp = skip_white_spaces(next);\n+\tif (*p != '\\0')\n+\t\treturn -EINVAL;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_uint32(uint32_t *value, const char *p)\n+{\n+\tuint64_t val = 0;\n+\tint ret = parser_read_uint64(&val, p);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (val > UINT32_MAX)\n+\t\treturn -ERANGE;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_uint32_hex(uint32_t *value, const char *p)\n+{\n+\tuint64_t val = 0;\n+\tint ret = parser_read_uint64_hex(&val, p);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (val > UINT32_MAX)\n+\t\treturn -ERANGE;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_uint16(uint16_t *value, const char *p)\n+{\n+\tuint64_t val = 0;\n+\tint ret = parser_read_uint64(&val, p);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (val > UINT16_MAX)\n+\t\treturn -ERANGE;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_uint16_hex(uint16_t *value, const char *p)\n+{\n+\tuint64_t val = 0;\n+\tint ret = parser_read_uint64_hex(&val, p);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (val > UINT16_MAX)\n+\t\treturn -ERANGE;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_uint8(uint8_t *value, const char *p)\n+{\n+\tuint64_t val = 0;\n+\tint ret = parser_read_uint64(&val, p);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (val > UINT8_MAX)\n+\t\treturn -ERANGE;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parser_read_uint8_hex(uint8_t *value, const char *p)\n+{\n+\tuint64_t val = 0;\n+\tint ret = parser_read_uint64_hex(&val, p);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (val > UINT8_MAX)\n+\t\treturn -ERANGE;\n+\n+\t*value = val;\n+\treturn 0;\n+}\n+\n+int\n+parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)\n+{\n+\tuint32_t i;\n+\n+\tif ((string == NULL) || (tokens == NULL) || (*n_tokens < 1))\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < *n_tokens; i++) {\n+\t\ttokens[i] = strtok_r(string, PARSE_DELIMITER, &string);\n+\t\tif (tokens[i] == NULL)\n+\t\t\tbreak;\n+\t}\n+\n+\tif ((i == *n_tokens) && (strtok_r(string, PARSE_DELIMITER, &string) != NULL))\n+\t\treturn -E2BIG;\n+\n+\t*n_tokens = i;\n+\treturn 0;\n+}\n+\n+int\n+parse_hex_string(char *src, uint8_t *dst, uint32_t *size)\n+{\n+\tchar *c;\n+\tuint32_t len, i;\n+\n+\t/* Check input parameters */\n+\tif ((src == NULL) || (dst == NULL) || (size == NULL) || (*size == 0))\n+\t\treturn -1;\n+\n+\tlen = strlen(src);\n+\tif (((len & 3) != 0) || (len > (*size) * 2))\n+\t\treturn -1;\n+\t*size = len / 2;\n+\n+\tfor (c = src; *c != 0; c++) {\n+\t\tif ((((*c) >= '0') && ((*c) <= '9')) || (((*c) >= 'A') && ((*c) <= 'F')) ||\n+\t\t    (((*c) >= 'a') && ((*c) <= 'f')))\n+\t\t\tcontinue;\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/* Convert chars to bytes */\n+\tfor (i = 0; i < *size; i++)\n+\t\tdst[i] = get_hex_val(src[2 * i]) * 16 + get_hex_val(src[2 * i + 1]);\n+\n+\treturn 0;\n+}\n+\n+int\n+parse_lcores_list(bool lcores[], int lcores_num, const char *corelist)\n+{\n+\tint i, idx = 0;\n+\tint min, max;\n+\tchar *end = NULL;\n+\n+\tif (corelist == NULL)\n+\t\treturn -1;\n+\twhile (isblank(*corelist))\n+\t\tcorelist++;\n+\ti = strlen(corelist);\n+\twhile ((i > 0) && isblank(corelist[i - 1]))\n+\t\ti--;\n+\n+\t/* Get list of lcores */\n+\tmin = RTE_MAX_LCORE;\n+\tdo {\n+\t\twhile (isblank(*corelist))\n+\t\t\tcorelist++;\n+\t\tif (*corelist == '\\0')\n+\t\t\treturn -1;\n+\t\tidx = strtoul(corelist, &end, 10);\n+\t\tif (idx < 0 || idx > lcores_num)\n+\t\t\treturn -1;\n+\n+\t\tif (end == NULL)\n+\t\t\treturn -1;\n+\t\twhile (isblank(*end))\n+\t\t\tend++;\n+\t\tif (*end == '-') {\n+\t\t\tmin = idx;\n+\t\t} else if ((*end == ',') || (*end == '\\0')) {\n+\t\t\tmax = idx;\n+\t\t\tif (min == RTE_MAX_LCORE)\n+\t\t\t\tmin = idx;\n+\t\t\tfor (idx = min; idx <= max; idx++) {\n+\t\t\t\tif (lcores[idx] == 1)\n+\t\t\t\t\treturn -E2BIG;\n+\t\t\t\tlcores[idx] = 1;\n+\t\t\t}\n+\n+\t\t\tmin = RTE_MAX_LCORE;\n+\t\t} else\n+\t\t\treturn -1;\n+\t\tcorelist = end + 1;\n+\t} while (*end != '\\0');\n+\n+\treturn 0;\n+}\ndiff --git a/app/test-mldev/parser.h b/app/test-mldev/parser.h\nnew file mode 100644\nindex 0000000000..f0d5e79e4b\n--- /dev/null\n+++ b/app/test-mldev/parser.h\n@@ -0,0 +1,55 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2010-2016 Intel Corporation.\n+ * Copyright (c) 2022 Marvell.\n+ */\n+\n+#ifndef __INCLUDE_PARSER_H__\n+#define __INCLUDE_PARSER_H__\n+\n+#include <ctype.h>\n+#include <stdint.h>\n+#include <stdlib.h>\n+\n+#define PARSE_DELIMITER \" \\f\\n\\r\\t\\v\"\n+\n+#define skip_white_spaces(pos)                                                                     \\\n+\t({                                                                                         \\\n+\t\t__typeof__(pos) _p = (pos);                                                        \\\n+\t\tfor (; isspace(*_p); _p++)                                                         \\\n+\t\t\t;                                                                          \\\n+\t\t_p;                                                                                \\\n+\t})\n+\n+static inline size_t\n+skip_digits(const char *src)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; isdigit(src[i]); i++)\n+\t\t;\n+\n+\treturn i;\n+}\n+\n+int parser_read_arg_bool(const char *p);\n+\n+int parser_read_uint64(uint64_t *value, const char *p);\n+int parser_read_uint32(uint32_t *value, const char *p);\n+int parser_read_uint16(uint16_t *value, const char *p);\n+int parser_read_uint8(uint8_t *value, const char *p);\n+\n+int parser_read_uint64_hex(uint64_t *value, const char *p);\n+int parser_read_uint32_hex(uint32_t *value, const char *p);\n+int parser_read_uint16_hex(uint16_t *value, const char *p);\n+int parser_read_uint8_hex(uint8_t *value, const char *p);\n+\n+int parser_read_int32(int32_t *value, const char *p);\n+int parser_read_int16(int16_t *value, const char *p);\n+\n+int parse_hex_string(char *src, uint8_t *dst, uint32_t *size);\n+\n+int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);\n+\n+int parse_lcores_list(bool lcores[], int lcores_num, const char *corelist);\n+\n+#endif /* __INCLUDE_PARSER_H__ */\n",
    "prefixes": [
        "v2",
        "01/12"
    ]
}