From patchwork Tue Nov 28 14:07:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Euan Bourke X-Patchwork-Id: 134692 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: 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]) by inbox.dpdk.org (Postfix) with ESMTP id 8F00843402; Wed, 29 Nov 2023 17:06:44 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 2F30F42E34; Wed, 29 Nov 2023 17:06:39 +0100 (CET) Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.24]) by mails.dpdk.org (Postfix) with ESMTP id AAD1342D89 for ; Tue, 28 Nov 2023 15:08:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1701180493; x=1732716493; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QbYdaPGNXoLY6Fr+VjU9HEuWmyg9z/vp6syFAK9Ubz0=; b=jWgtjKzZHqcqii4zd3HWoQU2HYRPlQHllLLG+coqnCbxkfzaqqcmXGAm v8YBEKTI6DoqJD1ntxQrmOcI4BJNQc9jE48nw+L69Khswrc8wI+MVeV5y kJ13aEonxOZcU/bOAxFpO2wyW2IHP18eq4cbbKia33gWDVNVm/MeOlFlm gLRgeXppdVHdpi3dBWwmpODMtxSOCy0RKTqMR3bwac2VTOhmm/C0neeD5 mdxYSk2pHXBl2o9RqMGqTjLfHtvwE7GzOv6rfUuwC7O6+KgCEYcLXnd9j 55bRRT0hrkGbXbkkHu7qrF2imtmIm1AWfgTnv+iOnbXV1aG2lQNnxTHqP w==; X-IronPort-AV: E=McAfee;i="6600,9927,10907"; a="395747342" X-IronPort-AV: E=Sophos;i="6.04,234,1695711600"; d="scan'208";a="395747342" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Nov 2023 06:07:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10907"; a="912450871" X-IronPort-AV: E=Sophos;i="6.04,234,1695711600"; d="scan'208";a="912450871" Received: from unknown (HELO silpixa00400630.ir.intel.com) ([10.237.213.151]) by fmsmga001.fm.intel.com with ESMTP; 28 Nov 2023 06:07:50 -0800 From: Euan Bourke To: dev@dpdk.org Cc: Euan Bourke , Thomas Monjalon , Bruce Richardson Subject: [PATCH 24.03 v2 1/5] arg_parser: new library for command line parsing Date: Tue, 28 Nov 2023 14:07:41 +0000 Message-Id: <20231128140745.595481-2-euan.bourke@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231128140745.595481-1-euan.bourke@intel.com> References: <20231122164550.3873633-1-euan.bourke@intel.com> <20231128140745.595481-1-euan.bourke@intel.com> MIME-Version: 1.0 X-Mailman-Approved-At: Wed, 29 Nov 2023 17:06:37 +0100 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add a new library to make it easier for eal and other libraries to parse command line arguments. The first function in this library is one to parse a corelist string into an array of individual core ids. The function will then return the total number of cores described in the corelist. Signed-off-by: Euan Bourke --- .mailmap | 1 + MAINTAINERS | 4 ++ doc/api/doxy-api-index.md | 3 +- doc/api/doxy-api.conf.in | 1 + lib/arg_parser/arg_parser.c | 113 ++++++++++++++++++++++++++++++++ lib/arg_parser/meson.build | 7 ++ lib/arg_parser/rte_arg_parser.h | 65 ++++++++++++++++++ lib/arg_parser/version.map | 10 +++ lib/meson.build | 2 + 9 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 lib/arg_parser/arg_parser.c create mode 100644 lib/arg_parser/meson.build create mode 100644 lib/arg_parser/rte_arg_parser.h create mode 100644 lib/arg_parser/version.map diff --git a/.mailmap b/.mailmap index ab0742a382..528bc68a30 100644 --- a/.mailmap +++ b/.mailmap @@ -379,6 +379,7 @@ Eric Zhang Erik Gabriel Carrillo Erik Ziegenbalg Erlu Chen +Euan Bourke Eugenio PĂ©rez Eugeny Parshutin Evan Swanson diff --git a/MAINTAINERS b/MAINTAINERS index 0d1c8126e3..68ef5ba14b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1756,6 +1756,10 @@ M: Nithin Dabilpuram M: Pavan Nikhilesh F: lib/node/ +Argument parsing +M: Bruce Richardson +F: lib/arg_parser/ + Test Applications ----------------- diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index a6a768bd7c..f711010140 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -221,7 +221,8 @@ The public API headers are grouped by topics: [config file](@ref rte_cfgfile.h), [key/value args](@ref rte_kvargs.h), [string](@ref rte_string_fns.h), - [thread](@ref rte_thread.h) + [thread](@ref rte_thread.h), + [argument parsing](@ref rte_arg_parser.h) - **debug**: [jobstats](@ref rte_jobstats.h), diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index e94c9e4e46..05718ba6ed 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -28,6 +28,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/lib/eal/include \ @TOPDIR@/lib/eal/include/generic \ @TOPDIR@/lib/acl \ + @TOPDIR@/lib/arg_parser \ @TOPDIR@/lib/bbdev \ @TOPDIR@/lib/bitratestats \ @TOPDIR@/lib/bpf \ diff --git a/lib/arg_parser/arg_parser.c b/lib/arg_parser/arg_parser.c new file mode 100644 index 0000000000..4aa876b4ed --- /dev/null +++ b/lib/arg_parser/arg_parser.c @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ + +#include "errno.h" +#include "stdlib.h" +#include "ctype.h" +#include "string.h" +#include "stdbool.h" + +#include +#include + + +struct core_bits { + uint8_t bits[(UINT16_MAX + 1)/CHAR_BIT]; + uint16_t max_bit_set; + uint16_t min_bit_set; + uint32_t total_bits_set; +}; + +static inline bool +get_core_bit(struct core_bits *mask, uint16_t idx) +{ + return !!(mask->bits[idx / 8] & (1 << (idx % 8))); +} + +static inline void +set_core_bit(struct core_bits *mask, uint16_t idx) +{ + if (get_core_bit(mask, idx)) + return; + + mask->bits[idx/8] |= 1 << (idx % 8); + /* Update min and max bit if its first time setting a bit */ + if (++(mask->total_bits_set) == 1) { + mask->min_bit_set = idx; + mask->max_bit_set = idx; + return; + } + + if (idx > mask->max_bit_set) + mask->max_bit_set = idx; + + if (idx < mask->min_bit_set) + mask->min_bit_set = idx; +} + +static inline uint32_t +corebits_to_array(struct core_bits *mask, uint16_t *cores, size_t max_cores) +{ + uint32_t count = 0; + for (uint32_t i = mask->min_bit_set; i <= mask->max_bit_set && count < max_cores; i++) { + if (get_core_bit(mask, i)) + cores[count++] = i; + } + return mask->total_bits_set; +} + + +int +rte_parse_corelist(const char *corelist, uint16_t *cores, uint32_t cores_len) +{ + int32_t min = -1; + char *end = NULL; + + struct core_bits *mask = malloc(sizeof(struct core_bits)); + if (mask == NULL) + return -1; + memset(mask, 0, sizeof(struct core_bits)); + + min = -1; + do { + uint32_t idx; + int32_t max; + + while (isblank(*corelist)) + corelist++; + if (!isdigit(*corelist)) + return -1; + + errno = 0; + idx = strtol(corelist, &end, 10); + if (errno || end == NULL || idx > UINT16_MAX) + return -1; + while (isblank(*end)) + end++; + if (*end == '-') + min = idx; + + else if (*end == ',' || *end == '\0') { + max = idx; + if (min == -1) + min = idx; + + /* Swap min and max if min is larger than max */ + if (min > max) + RTE_SWAP(min, max); + + for (; min <= max; min++) + set_core_bit(mask, min); + + min = -1; + } else + return -1; + corelist = end + 1; + } while (*end != '\0'); + + uint32_t total_count = corebits_to_array(mask, cores, cores_len); + free(mask); + + return total_count; +} diff --git a/lib/arg_parser/meson.build b/lib/arg_parser/meson.build new file mode 100644 index 0000000000..6ee228bd69 --- /dev/null +++ b/lib/arg_parser/meson.build @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation + +sources = files('arg_parser.c') +headers = files('rte_arg_parser.h') + +includes += global_inc diff --git a/lib/arg_parser/rte_arg_parser.h b/lib/arg_parser/rte_arg_parser.h new file mode 100644 index 0000000000..cf9291d13a --- /dev/null +++ b/lib/arg_parser/rte_arg_parser.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ + +#ifndef _RTE_ARG_PARSER_H_ +#define _RTE_ARG_PARSER_H_ + +/** + * @file + * + * RTE Argument Parsing API + * + * The argument parsing API is a collection of functions to help parse + * command line arguments. The API takes a string input and will return + * it to the user in a more usable format. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + + +/** + * Convert a string describing a list of core ids into an array of core ids. + * + * On success, the passed array is filled with the core ids present in the + * list up to the "cores_len", and the length of the array is returned. + * For example, passing a 1-3,6 "corelist" results in an array of [1, 2, 3, 6] + * and would return 4. + * + * Like the snprintf function for strings, if the length of the input array is + * insufficient to hold the number of cores in the "corelist", the input array is + * filled to capacity and the return value is the number of elements which would + * be returned if the array had been big enough. + * Function can also be called with a NULL array and 0 "cores_len" to find out + * the "cores_len" required. + * + * @param corelist + * Input string describing a list of core ids. + * @param cores + * An array where to store the core ids. + * Array can be NULL if "cores_len" is 0. + * @param cores_len + * The length of the "cores" array. + * If the size is smaller than that needed to hold all cores from "corelist", + * only "cores_len" elements will be written to the array. + * @return + * n: the number of unique cores present in "corelist". + * -1 if the string was invalid. + * NOTE: if n > "cores_len", then only "cores_len" elements in the "cores" array are valid. + */ +__rte_experimental +int +rte_parse_corelist(const char *corelist, uint16_t *cores, uint32_t cores_len); + + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_ARG_PARSER_H_ */ diff --git a/lib/arg_parser/version.map b/lib/arg_parser/version.map new file mode 100644 index 0000000000..588e14c7ad --- /dev/null +++ b/lib/arg_parser/version.map @@ -0,0 +1,10 @@ +DPDK_24 { + local: *; +}; + +EXPERIMENTAL { + global: + + # added in 24.03 + rte_parse_corelist; +}; diff --git a/lib/meson.build b/lib/meson.build index 6c143ce5a6..db9e769033 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -11,6 +11,7 @@ libraries = [ 'log', 'kvargs', # eal depends on kvargs + 'arg_parser', 'telemetry', # basic info querying 'eal', # everything depends on eal 'ring', @@ -72,6 +73,7 @@ if is_ms_compiler 'log', 'kvargs', 'telemetry', + 'arg_parser', ] endif