From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C6345A0C4C; Thu, 2 Sep 2021 18:09:57 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 51C6140041; Thu, 2 Sep 2021 18:09:57 +0200 (CEST) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mails.dpdk.org (Postfix) with ESMTP id BBD094003E for ; Thu, 2 Sep 2021 18:09:54 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10095"; a="199395819" X-IronPort-AV: E=Sophos;i="5.85,262,1624345200"; d="scan'208";a="199395819" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Sep 2021 09:08:28 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.85,262,1624345200"; d="scan'208";a="689188589" Received: from orsmsx603.amr.corp.intel.com ([10.22.229.16]) by fmsmga006.fm.intel.com with ESMTP; 02 Sep 2021 09:08:27 -0700 Received: from orsmsx605.amr.corp.intel.com (10.22.229.18) by ORSMSX603.amr.corp.intel.com (10.22.229.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2242.12; Thu, 2 Sep 2021 09:08:27 -0700 Received: from ORSEDG602.ED.cps.intel.com (10.7.248.7) by orsmsx605.amr.corp.intel.com (10.22.229.18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2242.12 via Frontend Transport; Thu, 2 Sep 2021 09:08:27 -0700 Received: from NAM11-BN8-obe.outbound.protection.outlook.com (104.47.58.171) by edgegateway.intel.com (134.134.137.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2242.10; Thu, 2 Sep 2021 09:08:26 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=MocH77syObW28x2xWmsUTT8ia+YIkAUCf9id1U3nMVTLVPpTXJLPSRd429TAC+Ib9SodWZZ8XtKi/Z4dxNQdGuMNJmVhBwXxuaWG/gRKOPP1qxVob2JdyTw9chFiMcQgH6PGHSusP5LlFuB/If6Vv/Dr7KUzNSd7Fd7IcPVst7c44TfNammVtPwjcQKCpe0E0OCrwS/llTrWpK1f99m8Gb8z3R3xbOWKqMlVPK54Q55yTxz/1MIdH4KwVQdfi11bPiDtcDs4Gb1Oe7kGLmYO7IP/VBErsAiHV8g3qHAkSrS/76DHI7INQ2YjmIf6AX2XJHeKGHE8MT4ansMWFMeYnQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=BMLLGt4XIlvcrdVA7x96juV+CdwHxT62nKusZQ922ho=; b=GO/LlS7rlO4P5EyYTJ2jLIuc4cM6B5LapBqYqzBSCb0F68HzgA5h7vAsY8ATrXJOF+FC/mlrHpJmmINNNZ2T8oA27DPfh75QqaQUPB39MqSfjES2G86CAaCrg1nqTp9OIMJ5TSunnPib2e+yBVa6oR4lpoNXqyP5kby+Q8LGcygvYvLVmITomTvf/3ppLZAp4AEiMd8WC+IylISi7KsrrIspN/VewJw6q0zI5MKYwvU6Qo0jIYSQQlLx6SIIIJYl3vytTf84Hm/cuzmoi6G3PjPVsgHYOGzqjs2jS27H1xwIx9jMPCpyjBJShyM/EDGTKZi8aHkoDWaAW2j7w5Surw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=intel.onmicrosoft.com; s=selector2-intel-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=BMLLGt4XIlvcrdVA7x96juV+CdwHxT62nKusZQ922ho=; b=EQ0ibqw1bIJtH3wUzu5YyE6I/0NKX8PVy4l5ppzwyQ/+taDDA/6K65mrQ8QA3v6mRB0mLZYTaXGkq1p6Cdn9e+y4h5kRTKQP5Jq9VJiBybvySNXv3I3xUAgd0DccbVjUmNiMsnmAQeWP+s2JOV18HPO5cb23fgaw5GMEf0fUAeg= Authentication-Results: intel.com; dkim=none (message not signed) header.d=none;intel.com; dmarc=none action=none header.from=intel.com; Received: from PH0PR11MB5000.namprd11.prod.outlook.com (2603:10b6:510:41::19) by PH0PR11MB4790.namprd11.prod.outlook.com (2603:10b6:510:40::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4478.19; Thu, 2 Sep 2021 16:08:25 +0000 Received: from PH0PR11MB5000.namprd11.prod.outlook.com ([fe80::747b:3a08:d1ec:31fc]) by PH0PR11MB5000.namprd11.prod.outlook.com ([fe80::747b:3a08:d1ec:31fc%5]) with mapi id 15.20.4478.020; Thu, 2 Sep 2021 16:08:25 +0000 To: Andrew Rybchenko , Xiaoyun Li CC: , David Marchand , Ivan Ilchenko , Ciara Power References: <20210723131515.2317168-12-andrew.rybchenko@oktetlabs.ru> <20210820135534.3542981-1-andrew.rybchenko@oktetlabs.ru> From: Ferruh Yigit X-User: ferruhy Message-ID: <9cb348fe-6bee-39f0-232e-6e4309b348e9@intel.com> Date: Thu, 2 Sep 2021 17:08:18 +0100 In-Reply-To: <20210820135534.3542981-1-andrew.rybchenko@oktetlabs.ru> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit X-ClientProxiedBy: DB8PR03CA0018.eurprd03.prod.outlook.com (2603:10a6:10:be::31) To PH0PR11MB5000.namprd11.prod.outlook.com (2603:10b6:510:41::19) MIME-Version: 1.0 Received: from [192.168.0.206] (37.228.236.146) by DB8PR03CA0018.eurprd03.prod.outlook.com (2603:10a6:10:be::31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4478.19 via Frontend Transport; Thu, 2 Sep 2021 16:08:23 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: a8bb2f77-5e2a-4c21-5d13-08d96e2be44d X-MS-TrafficTypeDiagnostic: PH0PR11MB4790: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:1332; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: +1CKfmVZ3vy+m24QxpwK6saAao28v7x8cP5lAfVyL0XFus77lLYIAX6KYMIi388BcCiPeovEGQGz7Gj0iTrte2N5wBuj9gjNgP3t9z5M4vuk2XVfcm5ycVPLB6Zv66rQW1MjsJDIFasoYZjstijgF9Y61a6YdUY1l4yK0A4FTpTy3gdIlzWaSGhobFtx2pDdzWUx1hJNytPLahDj/8D3NyC2pOD3zP30qn0NjLUgwCyg4KJ+xkkz1ovZQ+LxyNZ0uL0RxVDS1CFFE12Hx/5wYsKQikls9RuZRh8qRT1lwcJ9Kdhkg2hNPBxFTSVNCf6TRxqbV6xmx2TBzeG+klBcceunhHP7paVWeUe2dyt7chnaTniamLbkCt7nml5eXXnHE1UwT59RGSd58gffUhkoU4JKj/WFC8w0tNcg0xuOZpYn94C//TVXd2EhXpfZdITtOAO6uEqysyfs6kyYqLUHhFKImmuWw1cGUmd5l0e8pbfyGtdG4EW2J/GzJ5ZLfeWr+TYXY0mVyNBzqsE6F7DpYVIqRO9bMarCuvR7tIePGQpakTeggddJm7HXqlpZhS/XpRVu5T0teiqZCq82VwpJqSwodllfIIq/ZCdfFhhdwAHTiLVkBOUBTa6TmaTfPSAA09zP3MfVdUHjH0F/EX8VZvqDseKFiFsU18vGV1HIWQIVHdtFk19kifXfUbUidVZDWvhk0XtvE+te/nbSMpwW9Q== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PH0PR11MB5000.namprd11.prod.outlook.com; PTR:; CAT:NONE; SFS:(4636009)(376002)(136003)(39860400002)(346002)(366004)(396003)(36756003)(16576012)(316002)(31686004)(110136005)(54906003)(83380400001)(8676002)(4326008)(8936002)(2616005)(6636002)(44832011)(956004)(86362001)(6486002)(31696002)(38100700002)(66946007)(66556008)(6666004)(66476007)(186003)(2906002)(53546011)(30864003)(107886003)(478600001)(26005)(5660300002)(45980500001); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?RERMeFV6MWE5cGZOdkNuS3N1VzRnYzhneStLRTNiV202WWdic2VEMnY1dUx2?= =?utf-8?B?dzZKeVNWekRBNGwzQ2czU0pJL1RyRkJRend4YjBTQm5id0dlM3R5dlM2WDVq?= =?utf-8?B?a052d2E2WDFMZEI1SjNDWkRvTGczQ04wM0tWUU1vT3VyTFJjcU0wRjBXZ3Bl?= =?utf-8?B?ZGcwSWJwUC83bTBBZloySWxIS2pPSXlJZ1hTV3g5cUNEdVdGWHB5VVh6RTdu?= =?utf-8?B?djR1WjdGR25CL3BiU2ZlZlYzQm90dG0zcEVkZXplN0RkWXFWbWJYakI1cHI5?= =?utf-8?B?T0dGck95OVhtc0JTUGgwYlNlb2p1bkdCMVJ5YkZjYTVFV0ZiQ2ZyUkJOSWF1?= =?utf-8?B?MzZkcTN0ak1lSlV5TEF0aWplaHl1aUxkM0VxcENGS3ZGMjZLdHdDcmFaLzBC?= =?utf-8?B?V1hsQnVZaGordnVGdS9ndmZTYjVkQ3RncWMrMi9iUFFMSWJxTnd3TG1sWCsy?= =?utf-8?B?ZEVRbW4weDFGVHFrWTdkWlBIemF6enRsSTJjNkJsa3Q1QWRGOFA4ZFRNa1Yw?= =?utf-8?B?L21NT0U5RUlmaWJEUjYrdGlLaXBuZ0VHTTFMUXluNlowLzF2RFBFWFdwZm4z?= =?utf-8?B?cG9PSjFzUEQ4b25wVk04SjNKanlKeDRMVGFGTW1YUFhuOVcyY3kwaEtDTWZT?= =?utf-8?B?MjJBd3VlUUt4YjFjM21Gc3g3UktURVY3SkdrZUZWazlMNGxhMmxYRzYzY2JE?= =?utf-8?B?UytBWVJWeFRBeUxGNHd3ZERmUk9uK2NkbVhlMjBVOHpmVVFpRlNBd0RQMmxE?= =?utf-8?B?dmNmYVdxcjJSbXFLVlMzM2hWdTNEcFhQWXNON3RNMWJRdUt4Z1RwUCttKzJh?= =?utf-8?B?YkZzNjA4dzcrQWJjRFpHengvanNyZ0x6Z1pLa2tVQkN3QlJHbU0yTjFnK3BF?= =?utf-8?B?Ly9sNlM2RElrckcycnEvUFhVNHlBUjZjVFlaZ1hZUjZNVmNBMVdsNmpMTzhn?= =?utf-8?B?VjJISTRtRmdlQUlxdkNzYlBXa1VROTcrbms1dGd5cnVVQnRCMnM5cjRQY09T?= =?utf-8?B?eTF1M3Z3TlpBenloV3pBWWVXT3hKekxzNi82TnN3T0pIbjdFRXk2WkpUdmZG?= =?utf-8?B?THIvRWplWTVpNTFNWXdNS0N5MFY1MVkvWldzelFQdzhKUkZvZUpnVUVVNU5S?= =?utf-8?B?MEw4ZStMUEFzcTFpUmgxK0ViRk5DTUp1RWJ4THpweVFHOUpmYTF3MktVc0p1?= =?utf-8?B?ZzJ4bllGdVlaN1ptUVorWWxoUjlvL2tiQzNkbFcycWwxOS9LNXF6UzgrWlJ6?= =?utf-8?B?QWlVcTBvYUFnOGFRbldBNXZOVHhqZnJBdGVoQVhoeldnM2szUUxZRzBjWlBl?= =?utf-8?B?OTYzaTRIQXNMa2FxY2paaGoyN1BqTGtVME9iZWNIVDBtbkZOK3V5bnYxNnJ4?= =?utf-8?B?a2l2QVI3bUxSNk5GWlVVYlREa2VjM3Fkc1BHcTdsKzVBeHNRNUxmWVV3MEFX?= =?utf-8?B?QWJwOHdUVHJUSGsrcDRkekR5Y21XTWFCUUdXQmhScE16S05KZ09DMjlIeG90?= =?utf-8?B?R01vWEFDNXJpZWQrTlAwakJ0cnU2TFhFd1JHbGIrTjd0RlZuWDN6bi84c0Yx?= =?utf-8?B?T0tRYVNtNjNXRDRITEtDRzNHUGVucW5ud0Q3RXo0TUw0UUxrYW42VStIZWU4?= =?utf-8?B?SWtrQjB1SmxoaVM3M3BvVkh4UzNaV1lEYXNLbkk4U2ZxekdtMEJtL3QvTUJm?= =?utf-8?B?V3dQVUpGL0VqR0daOG0rWG42amYzY3BWc0IzenRpd1kvRk16NmFKM2FsM2Jv?= =?utf-8?Q?5LXPpXXpMJUn/wPZuPjKn4CeDbAPnSGADzumpt1?= X-MS-Exchange-CrossTenant-Network-Message-Id: a8bb2f77-5e2a-4c21-5d13-08d96e2be44d X-MS-Exchange-CrossTenant-AuthSource: PH0PR11MB5000.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Sep 2021 16:08:25.1301 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: fay74jRjNAn2UFyVmaTTeqXrZ9RwhMzRf+BCxZCv6nbjA9eVgXLZy0s58nSX+B9XuV3Gczhrs55VKrfIsGMHVA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR11MB4790 X-OriginatorOrg: intel.com Subject: Re: [dpdk-dev] [PATCH v4] app/testpmd: add option to display extended statistics 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 Sender: "dev" On 8/20/2021 2:55 PM, Andrew Rybchenko wrote: > From: Ivan Ilchenko > > Add 'display-xstats' option for using in accompanying with Rx/Tx statistics > (i.e. 'stats-period' option or 'show port stats' interactive command) to > display specified list of extended statistics. > Overall +1 to the feature. Just a reminder that same thing can be done via telemetry, custom xstat values can be retrieved from any dpdk application (including testpmd) by a telemetry client. cc'ed Ciara if more detail is required. > Signed-off-by: Ivan Ilchenko > Signed-off-by: Andrew Rybchenko > --- > v4: > - split from patch series > - move xstats information to rte_port structure to avoid > extra global structure > > app/test-pmd/cmdline.c | 55 +++++++++++++ > app/test-pmd/config.c | 66 ++++++++++++++++ > app/test-pmd/parameters.c | 14 ++++ > app/test-pmd/testpmd.c | 110 ++++++++++++++++++++++++++ > app/test-pmd/testpmd.h | 23 ++++++ > doc/guides/testpmd_app_ug/run_app.rst | 5 ++ > 6 files changed, 273 insertions(+) > > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c > index 82253bc751..cd538ace30 100644 > --- a/app/test-pmd/cmdline.c > +++ b/app/test-pmd/cmdline.c > @@ -3621,6 +3621,61 @@ cmdline_parse_inst_t cmd_stop = { > > /* *** SET CORELIST and PORTLIST CONFIGURATION *** */ > Inserting the below function between the above comment and its function makes the comment wrong. This is in file 'cmdline.c', which has command line functions and static functions that are needed for the command. Below function is to parse the application parameter, and called by a function in 'parameters.c'. Since that is the only consumer of this function, why not move this function to 'parameters.c' file and make it static? > +int > +parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats, > + unsigned int *xstats_num) > +{ > + int max_names_nb, names_nb; > + int stringlen; > + char **names; > + char *str; > + int ret; > + int i; > + > + names = NULL; > + str = strdup(in_str); 'in_str' is an user input, it is coming from 'lgopts()', can you please double check if it is guaranteed that it will be null terminated? > + if (str == NULL) { > + ret = ENOMEM; Please return negative error values. Only net/sfc has positive error values, since that is the syntax in its base code and we let to keep the syntax, but for rest of the DPDK please use negative error values. > + goto out; > + } > + stringlen = strlen(str); > +> + for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) { > + if (str[i] == ',') > + max_names_nb++; > + } > + > + names = calloc(max_names_nb, sizeof(*names)); > + if (names == NULL) { > + ret = ENOMEM; > + goto out; > + } > + > + names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ','); > + if (names_nb < 0) { > + ret = EINVAL; > + goto out; > + } Should we check the length of each 'names' to prevent unnecessary allocation for the cause user provided something like --display-xstats ',,,,,'? I think this check can be done during copy below. > + > + *xstats = calloc(names_nb, sizeof(**xstats)); > + if (*xstats == NULL) { > + ret = ENOMEM; > + goto out; > + } > + When and how 'xstats' ('xstats_display') is freed? > + for (i = 0; i < names_nb; i++) > + rte_strscpy((*xstats)[i].name, names[i], > + sizeof((*xstats)[i].name)); > + > + *xstats_num = names_nb; > + ret = 0; > + > +out: > + free(names); > + free(str); > + return ret; > +} > + > unsigned int > parse_item_list(const char *str, const char *item_name, unsigned int max_items, > unsigned int *parsed_items, int check_unique_values) > diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c > index 31d8ba1b91..ea5b59f54f 100644 > --- a/app/test-pmd/config.c > +++ b/app/test-pmd/config.c > @@ -173,6 +173,70 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr) > printf("%s%s", name, buf); > } > > +static void > +nic_xstats_display_periodic(portid_t port_id) > +{ > + struct xstat_display_info *xstats_info; > + uint64_t *prev_values, *curr_values; > + uint64_t diff_value, value_rate; > + uint64_t *ids, *ids_supp; > + struct timespec cur_time; > + unsigned int i, i_supp; > + size_t ids_supp_sz; > + uint64_t diff_ns; > + int rc; > + > + xstats_info = &ports[port_id].xstats_info; > + > + ids_supp_sz = xstats_info->ids_supp_sz; > + if (xstats_display_num == 0 || ids_supp_sz == 0) > + return; > + > + printf("\n"); > + > + ids = xstats_info->ids; > + ids_supp = xstats_info->ids_supp; > + prev_values = xstats_info->prev_values; > + curr_values = xstats_info->curr_values; > + > + rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values, > + ids_supp_sz); > + if (rc != (int)ids_supp_sz) { > + fprintf(stderr, "%s: Failed to get values of %zu supported xstats for port %u - return code %d\n", Can you break the line after 'stderr, ' to reduce the line length? Also I think you can drop 'supported' word in this context, because you already know all requested xstat is supported and retrieving it is failing, so for this log it is failing to get values of xstat. > + __func__, ids_supp_sz, port_id, rc); Not sure if __func__is required here? > + return; > + } > + > + diff_ns = 0; > + if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) { > + uint64_t ns; > + > + ns = cur_time.tv_sec * NS_PER_SEC; > + ns += cur_time.tv_nsec; > + > + if (xstats_info->prev_ns != 0) > + diff_ns = ns - xstats_info->prev_ns; > + xstats_info->prev_ns = ns; > + } > + > + printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)"); > + for (i = i_supp = 0; i < xstats_display_num; i++) { > + if (ids[i] == XSTAT_ID_INVALID) > + continue; > + > + diff_value = (curr_values[i_supp] > prev_values[i]) ? > + (curr_values[i_supp] - prev_values[i]) : 0; > + prev_values[i] = curr_values[i_supp]; > + value_rate = diff_ns > 0 ? > + (double)diff_value / diff_ns * NS_PER_SEC : 0; > + > + printf(" %-25s%12"PRIu64" %15"PRIu64"\n", > + xstats_display[i].name, curr_values[i_supp], value_rate); > + > + i_supp++; > + } > +} > + > void > nic_stats_display(portid_t port_id) > { > @@ -243,6 +307,8 @@ nic_stats_display(portid_t port_id) > PRIu64" Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8, > mpps_tx, mbps_tx * 8); > > + nic_xstats_display_periodic(port_id); > + What do you think to call the function if 'xstats_display_num > 0'? I can see there is already check in the function but I assume '--display-xstats' won't be set for majority of use cases, and checking it in advance can prevent unnecessary function call. > printf(" %s############################%s\n", > nic_stats_border, nic_stats_border); > } > diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c > index 7c13210f04..e78929795c 100644 > --- a/app/test-pmd/parameters.c > +++ b/app/test-pmd/parameters.c > @@ -61,6 +61,9 @@ usage(char* progname) > "(only if interactive is disabled).\n"); > printf(" --stats-period=PERIOD: statistics will be shown " > "every PERIOD seconds (only if interactive is disabled).\n"); > + printf(" --display-xstats xstat1[,...]: extended statistics to show. " > + "Used with --stats-period specified or interactive commands " > + "that show Rx/Tx statistics (i.e. 'show port stats').\n"); > printf(" --nb-cores=N: set the number of forwarding cores " > "(1 <= N <= %d).\n", nb_lcores); > printf(" --nb-ports=N: set the number of forwarding ports " > @@ -535,6 +538,7 @@ launch_args_parse(int argc, char** argv) > #endif > { "tx-first", 0, 0, 0 }, > { "stats-period", 1, 0, 0 }, > + { "display-xstats", 1, 0, 0 }, > { "nb-cores", 1, 0, 0 }, > { "nb-ports", 1, 0, 0 }, > { "coremask", 1, 0, 0 }, > @@ -692,6 +696,16 @@ launch_args_parse(int argc, char** argv) > stats_period = n; > break; > } > + if (!strcmp(lgopts[opt_idx].name, "display-xstats")) { > + char rc; > + > + rc = parse_xstats_list(optarg, &xstats_display, > + &xstats_display_num); > + if (rc != 0) > + rte_exit(EXIT_FAILURE, > + "Failed to fill xstats to display: %d\n", What about updating the error message something like: 'failed to parse display-xstats argument' > + rc); > + } > if (!strcmp(lgopts[opt_idx].name, > "eth-peers-configfile")) { > if (init_peer_eth_addrs(optarg) != 0) > diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c > index 6cbe9ba3c8..69a6a6913c 100644 > --- a/app/test-pmd/testpmd.c > +++ b/app/test-pmd/testpmd.c > @@ -208,6 +208,11 @@ uint32_t param_total_num_mbufs = 0; /**< number of mbufs in all pools - if > * specified on command-line. */ > uint16_t stats_period; /**< Period to show statistics (disabled by default) */ > > +/** Extended statistics to show. */ > +struct rte_eth_xstat_name *xstats_display; > + > +unsigned int xstats_display_num; /**< Size of extended statistics to show */ > + what about renaming 'num' as 'size'? no strong opinion. > /* > * In container, it cannot terminate the process which running with 'stats-period' > * option. Set flag to exit stats period loop after received SIGINT/SIGTERM. > @@ -542,6 +547,12 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN; > /* Holds the registered mbuf dynamic flags names. */ > char dynf_names[64][RTE_MBUF_DYN_NAMESIZE]; > > +/** Fill helper structures for specified port to show extended statistics. */ > +static void fill_display_xstats_info_for_port(portid_t pi); > + Can you please eliminate need of function declaration by rearranging the placement of static function? > +/** Fill helper structures for all ports to show extended statistics. */ > +static void fill_display_xstats_info(void); > + This declaration seems can't be eliminated because of cross call (cyclic dependency) between functions. > /* > * Helper function to check if socket is already discovered. > * If yes, return positive value. If not, return zero. > @@ -2685,6 +2696,8 @@ start_port(portid_t pid) > } > } > > + fill_display_xstats_info_for_port(pid); > + Why do we need to do the 'fill' in each start? Let's assume we are in the interactive mode and on each stop/start, the 'xstat_display_info' will filled again with exact same values, because names get via application parameter and they won't change. Will it work to call this function in port init? > printf("Done\n"); > return 0; > } > @@ -3719,6 +3732,40 @@ init_port_dcb_config(portid_t pid, > return 0; > } > > +static int > +alloc_display_xstats_info(portid_t pi) both 'xstats_display' and 'display_xstats' wording seems used for this feature, I suggest picking one and stick to it. And I am not sure about 'xstats_display', there are other commands in testpmd that displays the 'xstats', but not sure how to rename it. > +{ > + uint64_t **ids = &ports[pi].xstats_info.ids; > + uint64_t **ids_supp = &ports[pi].xstats_info.ids_supp; > + uint64_t **prev_values = &ports[pi].xstats_info.prev_values; > + uint64_t **curr_values = &ports[pi].xstats_info.curr_values; > + > + if (xstats_display_num == 0) > + return 0; > + > + *ids = calloc(xstats_display_num, sizeof(**ids)); > + if (*ids == NULL) > + return -ENOMEM; > + > + *ids_supp = calloc(xstats_display_num, sizeof(**ids_supp)); > + if (*ids_supp == NULL) > + return -ENOMEM; > + > + *prev_values = calloc(xstats_display_num, > + sizeof(**prev_values)); > + if (*prev_values == NULL) > + return -ENOMEM; > + > + *curr_values = calloc(xstats_display_num, > + sizeof(**curr_values)); > + if (*curr_values == NULL) > + return -ENOMEM; > + > + ports[pi].xstats_info.allocated = true; > + We should free these memory at some point ... > + return 0; > +} > + > static void > init_port(void) > { > @@ -3733,6 +3780,8 @@ init_port(void) > "rte_zmalloc(%d struct rte_port) failed\n", > RTE_MAX_ETHPORTS); > } > + for (i = 0; i < RTE_MAX_ETHPORTS; i++) > + ports[i].xstats_info.allocated = false; > for (i = 0; i < RTE_MAX_ETHPORTS; i++) > LIST_INIT(&ports[i].flow_tunnel_list); > /* Initialize ports NUMA structures */ > @@ -3748,6 +3797,67 @@ force_quit(void) > prompt_exit(); > } > > +static void > +fill_display_xstats_info_for_port(portid_t pi) > +{ > + unsigned int stat, stat_supp; > + uint64_t *ids, *ids_supp; > + const char *xstat_name; > + struct rte_port *port; > + int rc; > + > + if (xstats_display_num == 0) > + return; > + > + if (pi == (portid_t)RTE_PORT_ALL) { > + fill_display_xstats_info(); > + return; > + } > + > + port = &ports[pi]; > + if (port->port_status != RTE_PORT_STARTED) Why this requirement? Why port has to be started to get the ids of xstat names? > + return; > + > + if (!port->xstats_info.allocated && alloc_display_xstats_info(pi) != 0) > + rte_exit(EXIT_FAILURE, > + "Failed to allocate xstats display memory\n"); > + > + ids = port->xstats_info.ids; > + ids_supp = port->xstats_info.ids_supp; > + > + for (stat = stat_supp = 0; stat < xstats_display_num; stat++) { > + xstat_name = xstats_display[stat].name; > + > + rc = rte_eth_xstats_get_id_by_name(pi, xstat_name, > + ids + stat); > + if (rc != 0) { > + ids[stat] = XSTAT_ID_INVALID; > + fprintf(stderr, "No xstat '%s' on port %u - skip it\n", > + xstat_name, pi); > + continue; > + } > + ids_supp[stat_supp++] = ids[stat]; > + } > + > + port->xstats_info.ids_supp_sz = stat_supp; > +} > + > +static void > +fill_display_xstats_info(void) > +{ > + portid_t pi; > + > + if (xstats_display_num == 0) > + return; > + > + RTE_ETH_FOREACH_DEV(pi) { > + if (pi == (portid_t)RTE_PORT_ALL) > + continue; Do we really need this check? Can testpmd created more than 'RTE_PORT_ALL' port? > + > + fill_display_xstats_info_for_port(pi); > + } > +} > + > static void > print_stats(void) > { > diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h > index 16a3598e48..68f182944b 100644 > --- a/app/test-pmd/testpmd.h > +++ b/app/test-pmd/testpmd.h > @@ -195,6 +195,19 @@ struct tunnel_ops { > uint32_t items:1; > }; > > +/** Information for an extended statistics to show. */ > +struct xstat_display_info { > + /** IDs of xstats in the order of xstats_display */ > + uint64_t *ids; I think we can drop 'ids' and just keep 'ids_supp', please see below comment on 'XSTAT_ID_INVALID'. > + /** Supported xstats IDs in the order of xstats_display */ > + uint64_t *ids_supp; > + size_t ids_supp_sz; > + uint64_t *prev_values; > + uint64_t *curr_values; > + uint64_t prev_ns; > + bool allocated; > +}; > + > /** > * The data structure associated with each port. > */ > @@ -234,6 +247,7 @@ struct rte_port { > /**< dynamic flags. */ > uint64_t mbuf_dynf; > const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1]; > + struct xstat_display_info xstats_info; > }; > > /** > @@ -434,6 +448,13 @@ extern uint32_t param_total_num_mbufs; > > extern uint16_t stats_period; > > +extern struct rte_eth_xstat_name *xstats_display; > +extern unsigned int xstats_display_num; > + > +#define XSTAT_ID_INVALID UINT64_MAX Why you need this flag? Instead marking invalid xstats, why not just save the valid one and ignore invalid ones? Briefly, in 'xstat_display_info', drop the 'ids' and just keep 'ids_supp'. > + > +extern struct xstat_display_info xstats_per_port[]; > + Is 'xstats_per_port' residue of previous implementations? It seems it is not needed. > extern uint16_t hairpin_mode; > > #ifdef RTE_LIB_LATENCYSTATS > @@ -766,6 +787,8 @@ inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx) > unsigned int parse_item_list(const char *str, const char *item_name, > unsigned int max_items, > unsigned int *parsed_items, int check_unique_values); > +int parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats, > + unsigned int *xstats_num); > void launch_args_parse(int argc, char** argv); > void cmdline_read_from_file(const char *filename); > void prompt(void); > diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst > index 6061674239..d77afeb633 100644 > --- a/doc/guides/testpmd_app_ug/run_app.rst > +++ b/doc/guides/testpmd_app_ug/run_app.rst > @@ -56,6 +56,11 @@ The command line options are: > Display statistics every PERIOD seconds, if interactive mode is disabled. > The default value is 0, which means that the statistics will not be displayed. > > +* ``--display-xstats xstat1[,...]`` > + > + Display extended statistics every PERIOD seconds as specified in ``--stats-period`` > + or when used with interactive commands that show Rx/Tx statistics (i.e. 'show port stats'). > + Can you please highlight 'xstat1' is the xstat name, to prevent it to be confused with xstat id? Also can you please highlight that list should be comma separated, the short 'xstat1[,...]' usage implies this already but better to say it explicitly in the document. > * ``--nb-cores=N`` > > Set the number of forwarding cores, >