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 348D7423FD; Tue, 17 Jan 2023 14:54:58 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 0D23A400EF; Tue, 17 Jan 2023 14:54:58 +0100 (CET) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mails.dpdk.org (Postfix) with ESMTP id C7972400D4 for ; Tue, 17 Jan 2023 14:54:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1673963696; x=1705499696; h=from:to:cc:subject:date:message-id:references: in-reply-to:content-transfer-encoding:mime-version; bh=eqvEkncmoA6TkwO0JDoifO1QxNqlBJ13Y/GwtLY7j8g=; b=kNaNM5kiVGeIdMc1iU5rM64jbhqEfrkwN2Fzgqhxk76xaKdtC0UQ1q6A NGLHX+VomCwvSZDD/fSAUc1HNqMlJh9dWUuEjPF9r5gU+xpXedZ2iGZsB IzFqx6LCN0PVb8T9QtDfV3j+ZbS4j25OB3Hq51pMGhhowbMQ3vTD9olvL l7NYiwShUD5monN7M9oercIFrxp5MpKvsLDckdgJujcjE24qjCHtHbXvS O+ep4Y6PCfHuufVyQvuiHbxOT4dj0rxR8Llk7soh1CHFtvwB/99BTek/R k54ro9Yk1I+GE+Bg2Mc+0xz+PbDs+IUDcO9BMI5ZoeafIp9ujqV6onNI+ w==; X-IronPort-AV: E=McAfee;i="6500,9779,10592"; a="304383011" X-IronPort-AV: E=Sophos;i="5.97,224,1669104000"; d="scan'208";a="304383011" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jan 2023 05:54:54 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10592"; a="659398250" X-IronPort-AV: E=Sophos;i="5.97,224,1669104000"; d="scan'208";a="659398250" Received: from orsmsx603.amr.corp.intel.com ([10.22.229.16]) by orsmga002.jf.intel.com with ESMTP; 17 Jan 2023 05:54:54 -0800 Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) 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.2507.16; Tue, 17 Jan 2023 05:54:53 -0800 Received: from ORSEDG602.ED.cps.intel.com (10.7.248.7) by orsmsx610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.16 via Frontend Transport; Tue, 17 Jan 2023 05:54:53 -0800 Received: from NAM11-DM6-obe.outbound.protection.outlook.com (104.47.57.175) 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.2507.16; Tue, 17 Jan 2023 05:54:53 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=OJD1IAryR0wmWoydD8aQErbqhsJe8c5QZuie9E4i4SnVsda/X7ubiZaxKYyf+vDSiY4pClR+zBwHz30e1lJqJ3Gj9MCoVw7zBnzGkG5K+5QvthOfJU/sc7fnQbG7lhpuUkfHePe5PP0rdW+iIcCZ+vJcgkxQk9X11SAog+Jjbl78D+Wrg+7uuGr8+/WLgXWA9X7mkagr//+dfZjISvIjW9NQ/CwRTVGopL/IABGuyRwcklCfS9ZhwqnNGRtZr7Wfx92Q+JMbqaA4gyjZ4jF3NF5PRsqkpELbfHxunbuhu8/mQJqtPPP6QkGWiZ8eI3ner21ptA7GNCDbB1iRW28K0Q== 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:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=TUVsKWUi5Q6yUpKKIRoIwqa2JDEhCYzxOnPDUXTIJ2Y=; b=WPNtIK4SU9+D0tLkSGuPDBmYJPGBZDLblB9JVzToWk+DpEJ8bWnEUd9jyanY8pa2PsDZdHWQICwGlTrK95ytUxO9hED7KCcQ6czd0cx18E694m5NBtBbSa82+TeHmupEcd9Sx3nAoh2MDgoXREk9EMxOPXZr7v1n2gyQfuHPl7sdV8enxkeNjzs6RY3nYGfaNEUqMUyx3Dzhornv0J0eE8jJqYi/oXOXVuWgnoDwnmop6cvql0SuFOZ7tj9vVONjaykENEwQwqJL547/ftIKSxavE0vigA2pwAC65BD/pfpuJCkrPukhCJySsyfQrOlJJxXZ8n/MCLeGAMc7EJuIRQ== 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 Received: from SN7PR11MB7019.namprd11.prod.outlook.com (2603:10b6:806:2ae::22) by DS0PR11MB8136.namprd11.prod.outlook.com (2603:10b6:8:159::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6002.13; Tue, 17 Jan 2023 13:54:51 +0000 Received: from SN7PR11MB7019.namprd11.prod.outlook.com ([fe80::bacc:6241:115b:b26]) by SN7PR11MB7019.namprd11.prod.outlook.com ([fe80::bacc:6241:115b:b26%8]) with mapi id 15.20.5986.023; Tue, 17 Jan 2023 13:54:50 +0000 From: "Jiang, Cheng1" To: "Richardson, Bruce" CC: "thomas@monjalon.net" , "mb@smartsharesystems.com" , "dev@dpdk.org" , "Hu, Jiayu" , "Ding, Xuan" , "Ma, WenwuX" , "Wang, YuanX" , "He, Xingguang" Subject: RE: [PATCH v2] app/dma-perf: introduce dma-perf application Thread-Topic: [PATCH v2] app/dma-perf: introduce dma-perf application Thread-Index: AQHZKh3zO4HQ3Vhh8EKYFblUSW0EA66ikwsAgAAAmyA= Date: Tue, 17 Jan 2023 13:54:50 +0000 Message-ID: References: <20221220010619.31829-1-cheng1.jiang@intel.com> <20230117015623.17606-1-cheng1.jiang@intel.com> In-Reply-To: Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=intel.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: SN7PR11MB7019:EE_|DS0PR11MB8136:EE_ x-ms-office365-filtering-correlation-id: f0722131-bf93-4437-e622-08daf892674d x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: vaN2RzEi0rDB5MsCXX0eAIubG6HybIMyUXyAzTF/mBxhFOwPmdDCheK2cHW1fd9AA4TRQtsHTuWOg0pwVOcgnoGd8ahLYFsA9r9aBMlahd0Zuzcv2vtf+8iVA6+AsxQ9TePeAzwOI0ccXjDYVDD0J125jU872mZRjyFyejaXA1RtcGjGYnf295pdbyqg5nOYpKiDdckUoJdEu1g2L69cLdgpt+WGaESbVdEZFqO1tlJwsvMoLy9qK2UyD0tIhL6Nfwzo3N4RDTVqA1CZoHtKKuzZfGzWkDSuzXujTZBtvyRnEpjVoyosttSnn2selLlXAdrneLlbJUnXhqie0PM9s9H/aSF5KPAFnU2jjEo36MQOrZNisFw6m6RJK4emRBHXhqrw33zRpdBwSUWiS0Wlam/jQ62WvbJePuLTrXjcBgbNwxnhh0fgHG9gDwCKLphGINcz486GyYMVmZZL9XqM7Xl6BCuqrzdzOzwOAXu9pLLEZLCIUtLMbxJrfF/fQGiO4OgE0cPIjNYYc6PCuz/a2vLM+M9vLMs94EwlqAHfg3Vf7vHx7gZxH1EZQhnEARyh38Sd6sG4uvGUoUfoV32DD6RlLKqbBj7fvuw9ObXhunrTPV797NB5BiRjd45P55zzrBFckxwg4H+9rEL2b3t1adZb8H/YN22jjrKPJRpDEzhJZTBV3fqvhw7pYlbqrPRMfTtPrEiFz4x+dppO4xmBhQ== x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:SN7PR11MB7019.namprd11.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230022)(376002)(366004)(39860400002)(396003)(346002)(136003)(451199015)(82960400001)(478600001)(41300700001)(38070700005)(66446008)(38100700002)(66574015)(33656002)(186003)(71200400001)(86362001)(316002)(54906003)(6636002)(7696005)(66476007)(66556008)(55016003)(66946007)(26005)(76116006)(4326008)(53546011)(5660300002)(107886003)(6506007)(2906002)(30864003)(9686003)(6862004)(64756008)(83380400001)(8936002)(8676002)(52536014)(122000001)(579004)(559001); DIR:OUT; SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?iso-8859-1?Q?wdkHZBhSuxXi1k402YqGODbbe6gxzLi5ECdZsFPyYuRISJp3UosPfUIf8c?= =?iso-8859-1?Q?tvuXUcJHOIB0QrbRW6oQXCZEbuUW3D2BuodO8wy/RJ3IUQdvp8ss8NYT5Y?= =?iso-8859-1?Q?jI6jf7OtdMyyYVKqNEx3/vTvRH80NLj1bvd1mfZZzjoCbRB0687nJOT6Ld?= =?iso-8859-1?Q?Qzi1wtHQ9ezV90T8aTkDEUh0Q88caYRQP0z+k570S4Lsa98BnWyMg0A+sy?= =?iso-8859-1?Q?BxRm05xz7GQd7Ptw7EmNvog8latNsjCS3CZpCGI62cctTN+uTearsTDVVQ?= =?iso-8859-1?Q?0YAreifpS1zhbhx/VMDp+hZe06Y+S50vR/Ge5CGnEEXTsnHvjjZwbgmafx?= =?iso-8859-1?Q?dc5scWhEeILwBuswNdxgkVqGUPEgXaHegMpmJoCFtW057Bexy54+8XKwbf?= =?iso-8859-1?Q?Gym7JQTLFizkz63aBJ2hJeoQdsdPYxDWBepsIxX6sGhCjH8yp/tMPrXnzN?= =?iso-8859-1?Q?kvXsyhX6x5EeN+ZEM9SSU4V3xvcSQ/c3JDlFgby++Lg7xfIzgsFTf0nkke?= =?iso-8859-1?Q?L+vw55e1ORqCT0Y8auNjIL2QLRT+09GCjgIB+LTN/7K2Jz3KGyxFK7g6Di?= =?iso-8859-1?Q?+9a5draQR9JCF221xwueDCa1BEmEvKk4ig4j1GIflB0zeLRvXR+an5e11X?= =?iso-8859-1?Q?D6OgzW5u1oJJhKbwIL8Oc3VZGJRA162zSz5q1AHWQgDp/2yl73taD+eDoG?= =?iso-8859-1?Q?GTmhRjK5B57cKJy3ZJtu8bcPSX5gHgyqcMZ7CqiFBo5SEtvuwd2xANd1GW?= =?iso-8859-1?Q?3yhstExW431KEtX0+OYl+TL0B0zNFOmGk+8HWNVhaXdYs1fbUkzC9dWQ8A?= =?iso-8859-1?Q?ctuv+RUqwGUKUPY4IlxIfwUjcWCVFfBk4KEM5B9RLPgc5mSswsRyt99wtF?= =?iso-8859-1?Q?UVeQU/np7su8dvN/yYphkUDxIANBq/N0Qtf8G3z6jJAbqd0JFi/3q/A4uF?= =?iso-8859-1?Q?hBX6Iy1jt0+wOJtKCufGLwOX36BhJ5vVLe7/wBlxRy1HNtlzeU5JlPIX8R?= =?iso-8859-1?Q?hMaG+yvWZ7UfKfgDr1MyhixILQAhcy7qUDUubDhk405ix9IuD7bvPnQas4?= =?iso-8859-1?Q?fbNBLcV+0SGTTEgt67bMZrfA5hv2TxGzcP2do/DuVesRQQ0AHiPpLMeMDR?= =?iso-8859-1?Q?dNZAzUw3s8QAl+3njlIoSaGzFy6iW7G0g1YhCTNEOadsGVsen6nrW0Ee0o?= =?iso-8859-1?Q?wlCiFu/wIh78iorlCM6SAm6kRCc4O1ClGrztqljobJsUB9m0QuENxWjWUc?= =?iso-8859-1?Q?jt60j3Mq3ByjhpVeJelDnsrKmgi/KYSdtBz/flK5KEVEo47oPVpR5fQ6s9?= =?iso-8859-1?Q?OUrxSRnkmkD5agy1gNzh3s9kdMd55wk5iAJB5FDhiTPpglNwDJZU05nUZ0?= =?iso-8859-1?Q?n64RZSqK8Wi9BB0nwnU247JDUwl+g62mvC5KUdOoPz8ezyNeMauJSBvdmr?= =?iso-8859-1?Q?XuFf3DyDiaYaaMjHi8P8rY4hWpl++vpouvnF+Grwq8N1QlY1FyLZ5KWcq+?= =?iso-8859-1?Q?AesmUjD+3WUJ0GQmg9SfjLjQzF4UnXBFitqI42orRtGZuA47e+e2qzSTsd?= =?iso-8859-1?Q?DuM/JJZkhMtBg0XWmD+CfNUXvd9GqRiXTv+RRsyDKrftTTM3xKF8aa3atl?= =?iso-8859-1?Q?bRRj6gr61CvTqvpaZB6rLmemJpoh00bXmL?= Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: SN7PR11MB7019.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: f0722131-bf93-4437-e622-08daf892674d X-MS-Exchange-CrossTenant-originalarrivaltime: 17 Jan 2023 13:54:50.8106 (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: K0QArGA2pEtNXIIyZ+zAyUqEDlIinopO5KvhDfbkAJ5mNGwH1EniEfaY+O8WueLlw38UfwxQVdUIwtRxlygZxQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR11MB8136 X-OriginatorOrg: intel.com 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 Hi Bruce, Thanks for your comments. Replies are inline. I'll fix them in the next version. Thanks, Cheng > -----Original Message----- > From: Richardson, Bruce > Sent: Tuesday, January 17, 2023 9:00 PM > To: Jiang, Cheng1 > Cc: thomas@monjalon.net; mb@smartsharesystems.com; dev@dpdk.org; > Hu, Jiayu ; Ding, Xuan ; Ma, > WenwuX ; Wang, YuanX > ; He, Xingguang > Subject: Re: [PATCH v2] app/dma-perf: introduce dma-perf application >=20 > On Tue, Jan 17, 2023 at 01:56:23AM +0000, Cheng Jiang wrote: > > There are many high-performance DMA devices supported in DPDK now, > and > > these DMA devices can also be integrated into other modules of DPDK as > > accelerators, such as Vhost. Before integrating DMA into applications, > > developers need to know the performance of these DMA devices in > > various scenarios and the performance of CPUs in the same scenario, > > such as different buffer lengths. Only in this way can we know the > > target performance of the application accelerated by using them. This > > patch introduces a high-performance testing tool, which supports > > comparing the performance of CPU and DMA in different scenarios > > automatically with a pre-set config file. Memory Copy performance test = are > supported for now. > > > > Signed-off-by: Cheng Jiang > > Signed-off-by: Jiayu Hu > > Signed-off-by: Yuan Wang > > Acked-by: Morten Br=F8rup > > --- > > v2: fixed some CI issues. >=20 > Some first review comments inline below. More will likely follow as I rev= iew it > further and try testing it out. >=20 > /Bruce >=20 > > > > app/meson.build | 1 + > > app/test-dma-perf/benchmark.c | 539 > > ++++++++++++++++++++++++++++++++++ > > app/test-dma-perf/benchmark.h | 12 + app/test-dma-perf/config.ini > > | 61 ++++ > > app/test-dma-perf/main.c | 434 +++++++++++++++++++++++++++ > > app/test-dma-perf/main.h | 53 ++++ > > app/test-dma-perf/meson.build | 22 ++ > > 7 files changed, 1122 insertions(+) > > create mode 100644 app/test-dma-perf/benchmark.c create mode 100644 > > app/test-dma-perf/benchmark.h create mode 100644 > > app/test-dma-perf/config.ini create mode 100644 > > app/test-dma-perf/main.c create mode 100644 app/test-dma-perf/main.h > > create mode 100644 app/test-dma-perf/meson.build > > > > diff --git a/app/meson.build b/app/meson.build index > > e32ea4bd5c..a060ad2725 100644 > > --- a/app/meson.build > > +++ b/app/meson.build > > @@ -28,6 +28,7 @@ apps =3D [ > > 'test-regex', > > 'test-sad', > > 'test-security-perf', > > + 'test-dma-perf', > > ] >=20 > Lists in DPDK are always alphabetical when no other order is required, > therefore this new app should be further up the list, after "test-crypto-= perf". Sure, I'll fix it in the next version. >=20 > > > > default_cflags =3D machine_args + ['-DALLOW_EXPERIMENTAL_API'] diff > > --git a/app/test-dma-perf/benchmark.c b/app/test-dma- > perf/benchmark.c > > new file mode 100644 index 0000000000..1cb5b0b291 > > --- /dev/null > > +++ b/app/test-dma-perf/benchmark.c > > @@ -0,0 +1,539 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2022 Intel Corporation */ > > + > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "main.h" > > +#include "benchmark.h" > > + > > + > > +#define MAX_DMA_CPL_NB 255 > > + > > +#define CSV_LINE_DMA_FMT "Scenario %u,%u,%u,%u,%u,%u,%" PRIu64 > ",%.3lf,%" PRIu64 "\n" > > +#define CSV_LINE_CPU_FMT "Scenario %u,%u,NA,%u,%u,%u,%" PRIu64 > ",%.3lf,%" PRIu64 "\n" > > + > > +struct lcore_params { > > + uint16_t dev_id; > > + uint32_t nr_buf; > > + uint16_t kick_batch; > > + uint32_t buf_size; > > + uint32_t repeat_times; > > + uint16_t mpool_iter_step; > > + struct rte_mbuf **srcs; > > + struct rte_mbuf **dsts; > > + uint8_t scenario_id; > > +}; > > + > > +struct buf_info { > > + struct rte_mbuf **array; > > + uint32_t nr_buf; > > + uint32_t buf_size; > > +}; > > + > > +static struct rte_mempool *src_pool; > > +static struct rte_mempool *dst_pool; > > + > > +uint16_t dmadev_ids[MAX_WORKER_NB]; > > +uint32_t nb_dmadevs; > > + > > +#define PRINT_ERR(...) print_err(__func__, __LINE__, __VA_ARGS__) > > + > > +static inline int > > +__rte_format_printf(3, 4) > > +print_err(const char *func, int lineno, const char *format, ...) { > > + va_list ap; > > + int ret; > > + > > + ret =3D fprintf(stderr, "In %s:%d - ", func, lineno); > > + va_start(ap, format); > > + ret +=3D vfprintf(stderr, format, ap); > > + va_end(ap); > > + > > + return ret; > > +} > > + > > +static inline void > > +calc_result(struct lcore_params *p, uint64_t cp_cycle_sum, double > time_sec, > > + uint32_t repeat_times, uint32_t *memory, uint64_t > *ave_cycle, > > + float *bandwidth, uint64_t *ops) > > +{ > > + *memory =3D (p->buf_size * p->nr_buf * 2) / (1024 * 1024); > > + *ave_cycle =3D cp_cycle_sum / (p->repeat_times * p->nr_buf); > > + *bandwidth =3D p->buf_size * 8 * rte_get_timer_hz() / (*ave_cycle * > 1000 * 1000 * 1000.0); > > + *ops =3D (double)p->nr_buf * repeat_times / time_sec; } > > + > > +static void > > +output_result(uint8_t scenario_id, uint32_t lcore_id, uint16_t dev_id, > uint64_t ave_cycle, > > + uint32_t buf_size, uint32_t nr_buf, uint32_t memory, > > + float bandwidth, uint64_t ops, bool is_dma) { > > + if (is_dma) > > + printf("lcore %u, DMA %u:\n" > > + "average cycles: %" PRIu64 "," > > + " buffer size: %u, nr_buf: %u," > > + " memory: %uMB, frequency: %" PRIu64 > ".\n", > > + lcore_id, > > + dev_id, > > + ave_cycle, > > + buf_size, > > + nr_buf, > > + memory, > > + rte_get_timer_hz()); >=20 > Longer lines are allowed for strings, so you can merge each line of outpu= t to a > single line, which will improve readability. > Also, to shorten the code, there is no reason each parameter needs to go = on > its own line. Yes, totally make sense. I'll fix it in the next version. >=20 > > + else > > + printf("lcore %u\n" > > + "average cycles: %" PRIu64 "," > > + " buffer size: %u, nr_buf: %u," > > + " memory: %uMB, frequency: %" PRIu64 ".\n", > > + lcore_id, > > + ave_cycle, > > + buf_size, > > + nr_buf, > > + memory, > > + rte_get_timer_hz()); >=20 > Suggestion, rather than duplicating the whole output, only the first line > needs to change based on SW vs HW copies. How about: >=20 > if (is_dma) > printf("lcore %u, DMA %u\n", lcore_id, dev_id); > else > printf("lcore %u\n", lcore_id); > printf("average cycles: ..." , ...); >=20 Got it, good point. I'll fix it. > > + > > + printf("Average bandwidth: %.3lfGbps, OPS: %" PRIu64 "\n", > > +bandwidth, ops); > > + > > + if (is_dma) > > + snprintf(output_str[lcore_id], MAX_OUTPUT_STR_LEN, > > + CSV_LINE_DMA_FMT, > > + scenario_id, lcore_id, dev_id, buf_size, > > + nr_buf, memory, ave_cycle, bandwidth, ops); > > + else > > + snprintf(output_str[lcore_id], MAX_OUTPUT_STR_LEN, > > + CSV_LINE_CPU_FMT, > > + scenario_id, lcore_id, buf_size, > > + nr_buf, memory, ave_cycle, bandwidth, ops); } > > + > > +static inline void > > +cache_flush_buf(void *arg) >=20 > For non-x86 builds, you probably need to mark "arg" as unused to avoid > compiler warnings. Sure, I was wandering how to avoid compiler warnings, thanks for your advic= e. >=20 > Why is the parameter type given as a void pointer, when the type is > unconditionally cast below as "struct buf_info"? Void pointer type should > only be needed if you need to call this via a generic function pointer. You are right, I'll fix it. >=20 > > +{ > > +#ifdef RTE_ARCH_X86_64 > > + char *data; > > + char *addr; > > + struct buf_info *info =3D arg; > > + struct rte_mbuf **srcs =3D info->array; > > + uint32_t i, k; > > + > > + for (i =3D 0; i < info->nr_buf; i++) { > > + data =3D rte_pktmbuf_mtod(srcs[i], char *); > > + for (k =3D 0; k < info->buf_size / 64; k++) { > > + addr =3D (k * 64 + data); > > + __builtin_ia32_clflush(addr); > > + } >=20 > inner loop may be shorter by incrementing loop var by 64, rather than > dividing and then multiplying, since you can eliminate variable "addr". > Also can be more readable with a variable rename: >=20 > for (offset =3D 0; offset < info->buf_size; offset +=3D 64) > __buildin_ia32_clflush(data + offset); >=20 Sure, totally make sense to me, thanks. > > + } > > +#endif > > +} > > + > > +/* Configuration of device. */ > > +static void > > +configure_dmadev_queue(uint32_t dev_id, uint32_t ring_size) { > > + uint16_t vchan =3D 0; > > + struct rte_dma_info info; > > + struct rte_dma_conf dev_config =3D { .nb_vchans =3D 1 }; > > + struct rte_dma_vchan_conf qconf =3D { > > + .direction =3D RTE_DMA_DIR_MEM_TO_MEM, > > + .nb_desc =3D ring_size > > + }; > > + > > + if (rte_dma_configure(dev_id, &dev_config) !=3D 0) > > + rte_exit(EXIT_FAILURE, "Error with rte_dma_configure()\n"); > > + > > + if (rte_dma_vchan_setup(dev_id, vchan, &qconf) !=3D 0) { > > + printf("Error with queue configuration\n"); > > + rte_panic(); > > + } > > + >=20 > Inconsistency here - and below too. Either use rte_exit on failure or use > rte_panic, but don't mix them. Panic seems a little severe, so I suggest = just > using rte_exit() in all cases. Sure. >=20 > > + rte_dma_info_get(dev_id, &info); > > + if (info.nb_vchans !=3D 1) { > > + printf("Error, no configured queues reported on device > id %u\n", dev_id); > > + rte_panic(); > > + } > > + if (rte_dma_start(dev_id) !=3D 0) > > + rte_exit(EXIT_FAILURE, "Error with rte_dma_start()\n"); } > > + > > +static int > > +config_dmadevs(uint32_t nb_workers, uint32_t ring_size) { > > + int16_t dev_id =3D rte_dma_next_dev(0); > > + uint32_t i; > > + > > + nb_dmadevs =3D 0; > > + > > + for (i =3D 0; i < nb_workers; i++) { > > + if (dev_id =3D=3D -1) > > + goto end; > > + > > + dmadev_ids[i] =3D dev_id; > > + configure_dmadev_queue(dmadev_ids[i], ring_size); > > + dev_id =3D rte_dma_next_dev(dev_id + 1); > > + ++nb_dmadevs; >=20 > Very minor nit, but I'd suggest swapping these last two lines, incrementi= ng > nb_dmadevs right after configuring the device, but before finding a new o= ne. > It just makes more sense to me. Sure. >=20 > > + } > > + > > +end: > > + if (nb_dmadevs < nb_workers) { > > + printf("Not enough dmadevs (%u) for all workers (%u).\n", > nb_dmadevs, nb_workers); > > + return -1; > > + } > > + > > + RTE_LOG(INFO, DMA, "Number of used dmadevs: %u.\n", > nb_dmadevs); > > + > > + return 0; > > +} > > + > > +static inline void > > +do_dma_mem_copy(uint16_t dev_id, uint32_t nr_buf, uint16_t > kick_batch, uint32_t buf_size, > > + uint16_t mpool_iter_step, struct rte_mbuf **srcs, > struct rte_mbuf > > +**dsts) { > > + int64_t async_cnt =3D 0; > > + int nr_cpl =3D 0; > > + uint32_t index; > > + uint16_t offset; > > + uint32_t i; > > + > > + for (offset =3D 0; offset < mpool_iter_step; offset++) { > > + for (i =3D 0; index =3D i * mpool_iter_step + offset, index < nr_buf= ; > > +i++) { >=20 > Assignment in the condition part of a loop seems wrong. I suggest reworki= ng > this to avoid it. Sure, I'll reconsider it. >=20 > > + if (unlikely(rte_dma_copy(dev_id, > > + 0, > > + srcs[index]->buf_iova + > srcs[index]->data_off, > > + dsts[index]->buf_iova + > dsts[index]->data_off, >=20 > rte_pktmbuf_iova() macro can be used here. Sure, sorry I missed it. >=20 > > + buf_size, > > + 0) < 0)) { > > + rte_dma_submit(dev_id, 0); > > + while (rte_dma_burst_capacity(dev_id, 0) =3D=3D > 0) { > > + nr_cpl =3D rte_dma_completed(dev_id, > 0, MAX_DMA_CPL_NB, > > + NULL, NULL); > > + async_cnt -=3D nr_cpl; > > + } > > + if (rte_dma_copy(dev_id, > > + 0, > > + srcs[index]->buf_iova + > srcs[index]->data_off, > > + dsts[index]->buf_iova + > dsts[index]->data_off, > > + buf_size, > > + 0) < 0) { > > + printf("enqueue fail again at %u\n", > index); > > + printf("space:%d\n", > rte_dma_burst_capacity(dev_id, 0)); > > + rte_exit(EXIT_FAILURE, "DMA > enqueue failed\n"); > > + } > > + } > > + async_cnt++; > > + > > + /** > > + * When '&' is used to wrap an index, mask must be a > power of 2. > > + * That is, kick_batch must be 2^n. >=20 > I assume that is checked on input processing when parsing the config file= ? I'll check it in the next version. >=20 > > + */ > > + if (unlikely((async_cnt % kick_batch) =3D=3D 0)) { >=20 > This is an expected condition that will occur with repeatable frequency. > Therefore, unlikely is not really appropriate. Sure, I'll reconsider it. >=20 > > + rte_dma_submit(dev_id, 0); > > + /* add a poll to avoid ring full */ > > + nr_cpl =3D rte_dma_completed(dev_id, 0, > MAX_DMA_CPL_NB, NULL, NULL); > > + async_cnt -=3D nr_cpl; > > + } > > + } > > + > > + rte_dma_submit(dev_id, 0); > > + while (async_cnt > 0) { > > + nr_cpl =3D rte_dma_completed(dev_id, 0, > MAX_DMA_CPL_NB, NULL, NULL); > > + async_cnt -=3D nr_cpl; > > + } >=20 > Do we need a timeout here or in the loop above incase of errors that caus= e > us to not get all the elements back? Make sense, I'll consider it in the next version. Thanks. >=20 > > + } > > +} > > + > > +static int > > +dma_mem_copy(void *p) > > +{ >=20 > I see the call to this function within "remote_launch" uses a cast on the > function. I don't think that typecast should be necessary, but if you kee= p it, > you can avoid using the void pointer here and just mark the input type as > "struct lcore_params" directly. OK, make sense to me. >=20 > > + uint64_t ops; > > + uint32_t memory; > > + float bandwidth; > > + double time_sec; > > + uint32_t lcore_id =3D rte_lcore_id(); > > + struct lcore_params *params =3D (struct lcore_params *)p; > > + uint32_t repeat_times =3D params->repeat_times; > > + uint32_t buf_size =3D params->buf_size; > > + uint16_t kick_batch =3D params->kick_batch; > > + uint32_t lcore_nr_buf =3D params->nr_buf; > > + uint16_t dev_id =3D params->dev_id; > > + uint16_t mpool_iter_step =3D params->mpool_iter_step; > > + struct rte_mbuf **srcs =3D params->srcs; > > + struct rte_mbuf **dsts =3D params->dsts; > > + uint64_t begin, end, total_cycles =3D 0, avg_cycles =3D 0; > > + uint32_t r; > > + > > + begin =3D rte_rdtsc(); > > + > > + for (r =3D 0; r < repeat_times; r++) > > + do_dma_mem_copy(dev_id, lcore_nr_buf, kick_batch, > buf_size, > > + mpool_iter_step, srcs, dsts); > > + > > + end =3D rte_rdtsc(); > > + total_cycles =3D end - begin; >=20 > You can do without "end" easily enough: > total_cycles =3D rte_rdtsc() - begin; Got it, thanks for your advice. >=20 > > + time_sec =3D (double)total_cycles / rte_get_timer_hz(); > > + > > + calc_result(params, total_cycles, time_sec, repeat_times, &memory, > > + &avg_cycles, &bandwidth, &ops); > > + output_result(params->scenario_id, lcore_id, dev_id, avg_cycles, > buf_size, lcore_nr_buf, > > + memory, bandwidth, ops, true); > > + > > + rte_free(p); > > + > > + return 0; > > +} > > + > > +static int > > +cpu_mem_copy(void *p) > > +{ >=20 > Most of comments from above, also apply here. Sure, I'll fix them in the next version. >=20 > > + uint32_t idx; > > + uint32_t lcore_id; > > + uint32_t memory; > > + uint64_t ops; > > + float bandwidth; > > + double time_sec; > > + struct lcore_params *params =3D (struct lcore_params *)p; > > + uint32_t repeat_times =3D params->repeat_times; > > + uint32_t buf_size =3D params->buf_size; > > + uint32_t lcore_nr_buf =3D params->nr_buf; > > + uint16_t mpool_iter_step =3D params->mpool_iter_step; > > + struct rte_mbuf **srcs =3D params->srcs; > > + struct rte_mbuf **dsts =3D params->dsts; > > + uint64_t begin, end, total_cycles =3D 0, avg_cycles =3D 0; > > + uint32_t k, j, offset; > > + > > + begin =3D rte_rdtsc(); > > + > > + for (k =3D 0; k < repeat_times; k++) { > > + /* copy buffer form src to dst */ > > + for (offset =3D 0; offset < mpool_iter_step; offset++) { > > + for (j =3D 0; idx =3D j * mpool_iter_step + offset, idx < > lcore_nr_buf; j++) { > > + rte_memcpy((void > *)(uintptr_t)rte_mbuf_data_iova(dsts[idx]), > > + (void > *)(uintptr_t)rte_mbuf_data_iova(srcs[idx]), > > + (size_t)buf_size); > > + } > > + } > > + } > > + > > + end =3D rte_rdtsc(); > > + total_cycles =3D end - begin; > > + time_sec =3D (double)total_cycles / rte_get_timer_hz(); > > + > > + lcore_id =3D rte_lcore_id(); > > + > > + calc_result(params, total_cycles, time_sec, repeat_times, &memory, > > + &avg_cycles, &bandwidth, &ops); > > + output_result(params->scenario_id, lcore_id, 0, avg_cycles, buf_size, > lcore_nr_buf, > > + memory, bandwidth, ops, false); > > + > > + rte_free(p); > > + > > + return 0; > > +} > > + > > +static int > > +setup_memory_env(struct test_configure *cfg, struct rte_mbuf ***srcs, > > + struct rte_mbuf ***dsts) > > +{ > > + uint32_t i; > > + unsigned int buf_size =3D cfg->buf_size.cur; > > + unsigned int nr_sockets; > > + uint32_t nr_buf =3D cfg->nr_buf; > > + > > + nr_sockets =3D rte_socket_count(); > > + if (cfg->src_numa_node >=3D nr_sockets || > > + cfg->dst_numa_node >=3D nr_sockets) { > > + printf("Error: Source or destination numa exceeds the acture > numa nodes.\n"); > > + return -1; > > + } > > + > > + src_pool =3D rte_pktmbuf_pool_create("Benchmark_DMA_SRC", > > + nr_buf, /* n =3D=3D num elements */ > > + 64, /* cache size */ > > + 0, /* priv size */ > > + buf_size + RTE_PKTMBUF_HEADROOM, > > + cfg->src_numa_node); > > + if (src_pool =3D=3D NULL) { > > + PRINT_ERR("Error with source mempool creation.\n"); > > + return -1; > > + } > > + > > + dst_pool =3D rte_pktmbuf_pool_create("Benchmark_DMA_DST", > > + nr_buf, /* n =3D=3D num elements */ > > + 64, /* cache size */ > > + 0, /* priv size */ > > + buf_size + RTE_PKTMBUF_HEADROOM, > > + cfg->dst_numa_node); > > + if (dst_pool =3D=3D NULL) { > > + PRINT_ERR("Error with destination mempool creation.\n"); > > + return -1; > > + } > > + > > + *srcs =3D (struct rte_mbuf **)(malloc(nr_buf * sizeof(struct rte_mbuf > > +*))); >=20 > Typecast for void * to other types aren't actually necessary in C. > I note some inconsistency in this file with regards to malloc. Here you u= se > regular malloc, while when building the parameters to pass to the memcpy > functions you use rte_malloc. I suggest standardizing on one or the other > rather than mixing. Good point, thanks. >=20 > > + if (*srcs =3D=3D NULL) { > > + printf("Error: srcs malloc failed.\n"); > > + return -1; > > + } > > + > > + *dsts =3D (struct rte_mbuf **)(malloc(nr_buf * sizeof(struct rte_mbuf > *))); > > + if (*dsts =3D=3D NULL) { > > + printf("Error: dsts malloc failed.\n"); > > + return -1; > > + } > > + > > + for (i =3D 0; i < nr_buf; i++) { > > + (*srcs)[i] =3D rte_pktmbuf_alloc(src_pool); > > + (*dsts)[i] =3D rte_pktmbuf_alloc(dst_pool); >=20 > Rather than individually allocating you may well manage with > rte_mempool_get_bulk() to allocate all mbufs in one call. Sure, thanks. >=20 > > + if ((!(*srcs)[i]) || (!(*dsts)[i])) { > > + printf("src: %p, dst: %p\n", (*srcs)[i], (*dsts)[i]); > > + return -1; > > + } > > + > > + (*srcs)[i]->data_len =3D (*srcs)[i]->pkt_len =3D buf_size; > > + (*dsts)[i]->data_len =3D (*dsts)[i]->pkt_len =3D buf_size; >=20 > rte_pktmbuf_append() macro can be used here, rather than setting the > lengths manually. However, these values are not actually used anywhere > else in the code, I believe, so setting them is unnecessary. You are manu= ally > tracking the copy lengths throughout the test, and nothing else is workin= g on > the mbufs, so the length the mbuf reports is immaterial.. Sure, it will be fixed. >=20 >=20 > > + } > > + > > + return 0; > > +} > > + > > +void > > +dma_mem_copy_benchmark(struct test_configure *cfg) { > > + uint32_t i; > > + uint32_t offset; > > + unsigned int lcore_id =3D 0; > > + struct rte_mbuf **srcs =3D NULL, **dsts =3D NULL; > > + unsigned int buf_size =3D cfg->buf_size.cur; > > + uint16_t kick_batch =3D cfg->kick_batch.cur; > > + uint16_t mpool_iter_step =3D cfg->mpool_iter_step; > > + uint32_t nr_buf =3D cfg->nr_buf =3D (cfg->mem_size.cur * 1024 * 1024)= / > (cfg->buf_size.cur * 2); > > + uint16_t nb_workers =3D cfg->nb_workers; > > + uint32_t repeat_times =3D cfg->repeat_times; > > + > > + if (setup_memory_env(cfg, &srcs, &dsts) < 0) > > + goto out; > > + > > + if (config_dmadevs(nb_workers, cfg->ring_size.cur) < 0) > > + goto out; > > + > > + if (cfg->cache_flush) { > > + struct buf_info info; > > + > > + info.array =3D srcs; > > + info.buf_size =3D buf_size; > > + info.nr_buf =3D nr_buf; > > + cache_flush_buf(&info); > > + >=20 > From what I can see, struct buf_info is only used for passing parameters = to > the cache_flush_buf function. The code would be a lot simpler to remove > the structure and just pass 3 parameters to the function directly. Good point, thanks. >=20 > > + info.array =3D dsts; > > + cache_flush_buf(&info); > > + rte_mb(); > > + } > > + > > + printf("Start testing....\n"); > > + > > + for (i =3D 0; i < nb_workers; i++) { > > + lcore_id =3D rte_get_next_lcore(lcore_id, true, true); > > + offset =3D nr_buf / nb_workers * i; > > + > > + struct lcore_params *p =3D rte_malloc(NULL, sizeof(*p), 0); > > + if (!p) { > > + printf("lcore parameters malloc failure for > lcore %d\n", lcore_id); > > + break; > > + } > > + *p =3D (struct lcore_params) { > > + dmadev_ids[i], > > + (uint32_t)(nr_buf/nb_workers), > > + kick_batch, > > + buf_size, > > + repeat_times, > > + mpool_iter_step, > > + srcs + offset, > > + dsts + offset, > > + cfg->scenario_id > > + }; > > + > > + rte_eal_remote_launch((lcore_function_t > *)dma_mem_copy, p, lcore_id); > > + } > > + > > + rte_eal_mp_wait_lcore(); > > + > > +out: > > + /* free env */ > > + if (srcs) { > > + for (i =3D 0; i < nr_buf; i++) > > + rte_pktmbuf_free(srcs[i]); > > + free(srcs); > > + } > > + if (dsts) { > > + for (i =3D 0; i < nr_buf; i++) > > + rte_pktmbuf_free(dsts[i]); > > + free(dsts); > > + } > > + > > + if (src_pool) > > + rte_mempool_free(src_pool); > > + if (dst_pool) > > + rte_mempool_free(dst_pool); > > + > > + for (i =3D 0; i < nb_dmadevs; i++) { > > + printf("Stopping dmadev %d\n", dmadev_ids[i]); > > + rte_dma_stop(dmadev_ids[i]); > > + } > > +} > > + > > +void > > +cpu_mem_copy_benchmark(struct test_configure *cfg) { > > + uint32_t i, offset; > > + uint32_t repeat_times =3D cfg->repeat_times; > > + uint32_t kick_batch =3D cfg->kick_batch.cur; > > + uint32_t buf_size =3D cfg->buf_size.cur; > > + uint32_t nr_buf =3D cfg->nr_buf =3D (cfg->mem_size.cur * 1024 * 1024)= / > (cfg->buf_size.cur * 2); > > + uint16_t nb_workers =3D cfg->nb_workers; > > + uint16_t mpool_iter_step =3D cfg->mpool_iter_step; > > + struct rte_mbuf **srcs =3D NULL, **dsts =3D NULL; > > + unsigned int lcore_id =3D 0; > > + > > + if (setup_memory_env(cfg, &srcs, &dsts) < 0) > > + goto out; > > + > > + for (i =3D 0; i < nb_workers; i++) { > > + lcore_id =3D rte_get_next_lcore(lcore_id, rte_lcore_count() > > 1 ? 1 : 0, 1); > > + offset =3D nr_buf / nb_workers * i; > > + struct lcore_params *p =3D rte_malloc(NULL, sizeof(*p), 0); > > + if (!p) { > > + printf("lcore parameters malloc failure for > lcore %d\n", lcore_id); > > + break; > > + } > > + *p =3D (struct lcore_params) { 0, nr_buf/nb_workers, > kick_batch, > > + buf_size, repeat_times, > mpool_iter_step, > > + srcs + offset, dsts + offset, > cfg->scenario_id }; >=20 > Formatting should be the same as function above. Sure. >=20 > > + rte_eal_remote_launch((lcore_function_t *)cpu_mem_copy, > p, lcore_id); > > + } > > + > > + rte_eal_mp_wait_lcore(); > > + > > +out: > > + /* free env */ > > + if (srcs) { > > + for (i =3D 0; i < nr_buf; i++) > > + rte_pktmbuf_free(srcs[i]); > > + free(srcs); > > + } > > + if (dsts) { > > + for (i =3D 0; i < nr_buf; i++) > > + rte_pktmbuf_free(dsts[i]); > > + free(dsts); > > + } > > + > > + if (src_pool) > > + rte_mempool_free(src_pool); > > + if (dst_pool) > > + rte_mempool_free(dst_pool); > > +} >=20 > There seems a quite a bit of common code between the > dma_mem_copy_benchmark and cpu_mem_copy_benchmark. Might be > worth investigating if they can be merged while still keeping readability= . Yes you're right. I'll consider it. >=20 > > diff --git a/app/test-dma-perf/benchmark.h > > b/app/test-dma-perf/benchmark.h new file mode 100644 index > > 0000000000..f5ad8d6d99 > > --- /dev/null > > +++ b/app/test-dma-perf/benchmark.h > > @@ -0,0 +1,12 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2022 Intel Corporation */ > > + > > +#ifndef _BENCHMARK_H_ > > +#define _BENCHMARK_H_ > > + > > +void dma_mem_copy_benchmark(struct test_configure *cfg); > > + > > +void cpu_mem_copy_benchmark(struct test_configure *cfg); > > + > > +#endif /* _BENCHMARK_H_ */ >=20 > You don't really need two separate headers in this application. Both main= .h > and benchmark.h can be merged into one header, since both are always > included in both c files. Sure, make sense. >=20 > > diff --git a/app/test-dma-perf/config.ini > > b/app/test-dma-perf/config.ini new file mode 100644 index > > 0000000000..e24bb19414 > > --- /dev/null > > +++ b/app/test-dma-perf/config.ini > > @@ -0,0 +1,61 @@ > > + > > +; Supported test types: > > +; DMA_MEM_COPY|CPU_MEM_COPY > > + > > +; Parameters: > > +; "mem_size","buf_size","dma_ring_size","kick_batch". > > +; "mem_size" means the size of the memory footprint. > > +; "buf_size" means the memory size of a single operation. > > +; "dma_ring_size" means the dma ring buffer size. > > +; "kick_batch" means dma operation batch size. > > + > > +; Format: variable=3Dfirst[,last,increment[,ADD|MUL]] > > +; ADD is the default mode. > > + > > +; src_numa_node is used to control the numa node where the source > memory is allocated. > > +; dst_numa_node is used to control the numa node where the > destination memory is allocated. > > + > > +; cache_flush is used to control if the cache should be flushed. > > + > > +; repeat_times is used to control the repeat times of the whole case. > > + > > +; worker_threads is used to control the threads number of the test app= . > > +; It should be less than the core number. > > + > > +; mpool_iter_step is used to control the buffer continuity. > > + > > +; Bind DMA to lcore: > > +; Specify the "lcore_dma" parameter. > > +; The number of "lcore_dma" should be greater than or equal to the > number of "worker_threads". > > +; Otherwise the remaining DMA devices will be automatically allocated > > +to threads that are not ; specified. If EAL parameters "-l" and "-a" > > +are specified, the "lcore_dma" should be within ; their range. > > + > > +[case1] > > +type=3DDMA_MEM_COPY > > +mem_size=3D10 > > +buf_size=3D64,8192,2,MUL > > +dma_ring_size=3D1024 > > +kick_batch=3D32 > > +src_numa_node=3D0 > > +dst_numa_node=3D0 > > +cache_flush=3D0 > > +repeat_times=3D10 > > +worker_threads=3D1 > > +mpool_iter_step=3D1 > > +lcore_dma=3Dlcore3@0000:00:04.0 > > +eal_args=3D--legacy-mem --file-prefix=3Dtest > > + > > +[case2] > > +type=3DCPU_MEM_COPY > > +mem_size=3D10 > > +buf_size=3D64,8192,2,MUL > > +dma_ring_size=3D1024 > > +kick_batch=3D32 > > +src_numa_node=3D0 > > +dst_numa_node=3D1 > > +cache_flush=3D0 > > +repeat_times=3D100 > > +worker_threads=3D1 > > +mpool_iter_step=3D1 > > +eal_args=3D--no-pci > > diff --git a/app/test-dma-perf/main.c b/app/test-dma-perf/main.c new > > file mode 100644 index 0000000000..94ba369539 > > --- /dev/null > > +++ b/app/test-dma-perf/main.c > > @@ -0,0 +1,434 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2022 Intel Corporation */ > > + > > +#include > > +#if !defined(RTE_EXEC_ENV_LINUX) > > + > > +int > > +main(int argc, char *argv[]) > > +{ > > + printf("OS not supported, skipping test\n"); > > + return 0; > > +} > > + >=20 > What is linux-specific about this app? >=20 > If we do need to limit the app to Linux-only I suggest using meson to do = so > rather than putting #ifdefs in the code. Got it. Thanks! >=20 > > +#else > > + > > +#include > > +#include > > +#include >=20 >