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 79B1B45D0F; Fri, 15 Nov 2024 11:21:08 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 390C142FB5; Fri, 15 Nov 2024 11:21:08 +0100 (CET) Received: from mx0a-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by mails.dpdk.org (Postfix) with ESMTP id 50046402EB for ; Fri, 15 Nov 2024 11:21:06 +0100 (CET) Received: from pps.filterd (m0431384.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4AFAEw5c020274; Fri, 15 Nov 2024 02:20:58 -0800 Received: from nam10-bn7-obe.outbound.protection.outlook.com (mail-bn7nam10lp2047.outbound.protection.outlook.com [104.47.70.47]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 42x4cgr08g-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 15 Nov 2024 02:20:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=dzzlj9HfR2cEhP9xH0nxO8CZsUTC3Zw8opi73EEp5sKjU+zUFJaepjj3/pefuVkr//+/SFcNOinZkOQdhlSPGi+js31ZY05Uiu/OP8B2AfxVTCQDp676lMekiba3daJV/AsBSxdvH7GdySCQXiw/HoIOND3+Kl1PVq7PGzSeS6GPN3N6TOnlBuNV9Ib5v1XNxovPxq+Ug25zJD7tKqp7zIw08DgCfrfqUY2gMTHziXm8g/O2flaL1qAHJXrzfX3weqTzs3kM9ZbHXYw/PUdK/PyE25CwyqzcmY6+al1AeMKOIOHuZsqyTlj6C0V9/ZKnAk/sfuKInGskqIe2wVGs4A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=zVwC7bIL4WMrNcjKPxtl+9wAz+xG6rI3Z3+Cne/O11s=; b=N9Omf/ddsz7ITfIa8OYELpdnFOdNal79Rg16r8+Msdmv3eE8Wi4UaOcopJDB8DPQWdPNzcd7TKqRGA2UCw1rvNYMGTyfv9kxBkYDlu706kh4Qt+yZheGKxvN/FM1CzA/ijrZBnRV2LM3bBGkv09+4y0c0rg6GPDC8bjGYVkkkMpX7EC961Hj8XwqFlqWc3dZkS2kLHVdxJVzWXUI/6O67Jg+U0rd/AWgDNkoMwJoElYsudzSd8tzVvdf1swJJWF2GHuK17mqLuyowJeGqwv3FfyqnMNaH+xxgQAhRmmd3d7v/itt6wrYi5TdBJ+Jg2Lx2aKcNAbZjK3mMzpXOyYwDg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=marvell.com; dmarc=pass action=none header.from=marvell.com; dkim=pass header.d=marvell.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=zVwC7bIL4WMrNcjKPxtl+9wAz+xG6rI3Z3+Cne/O11s=; b=lfr6z1SggZHiyFUvOZIhCH7hx6vg16LrQFlWNjTLSAY3NWz68F8JNhq8yoHv4ZAmem3pw2sgqf0EnKaJKgnZj6CY0cD8Hxd0ga8ab4GSYJeZI1DWc+T+h7WItu8g4goFw3ljlqFMLv4VZ5F6yFiicxoAHZQdqH/DowxyBeD/SKI= Received: from DM4PR18MB4368.namprd18.prod.outlook.com (2603:10b6:5:39d::6) by CO6PR18MB3842.namprd18.prod.outlook.com (2603:10b6:5:341::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8158.19; Fri, 15 Nov 2024 10:20:53 +0000 Received: from DM4PR18MB4368.namprd18.prod.outlook.com ([fe80::1679:98:2091:7e98]) by DM4PR18MB4368.namprd18.prod.outlook.com ([fe80::1679:98:2091:7e98%5]) with mapi id 15.20.8158.013; Fri, 15 Nov 2024 10:20:53 +0000 From: Tomasz Duszynski To: Konstantin Ananyev , Thomas Monjalon CC: "Ruifeng.Wang@arm.com" , "bruce.richardson@intel.com" , "david.marchand@redhat.com" , "dev@dpdk.org" , Jerin Jacob , "konstantin.v.ananyev@yandex.ru" , "mattias.ronnblom@ericsson.com" , "mb@smartsharesystems.com" , "roretzla@linux.microsoft.com" , "stephen@networkplumber.org" , "zhoumin@loongson.cn" Subject: RE: [PATCH v15 1/4] lib: add generic support for reading PMU events Thread-Topic: [PATCH v15 1/4] lib: add generic support for reading PMU events Thread-Index: AQHbJruLVbdROvW51Uyxa9RIrjo2vrKoldGAgA+lLyA= Date: Fri, 15 Nov 2024 10:20:53 +0000 Message-ID: References: <20241011094944.3586051-1-tduszynski@marvell.com> <20241025085414.3412068-1-tduszynski@marvell.com> <20241025085414.3412068-2-tduszynski@marvell.com> <5f678ae6bb1d4e25bf1f537415799fcc@huawei.com> In-Reply-To: <5f678ae6bb1d4e25bf1f537415799fcc@huawei.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: DM4PR18MB4368:EE_|CO6PR18MB3842:EE_ x-ms-office365-filtering-correlation-id: 78f80320-8c3a-4dba-5b76-08dd055f2f81 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; ARA:13230040|1800799024|366016|7416014|376014|38070700018; x-microsoft-antispam-message-info: =?utf-8?B?MWNPRVBLdnNXZzk2SHprckpseWt2R1FjQy9RSFN1Q1BKank4N2V6ZDZ0MzdK?= =?utf-8?B?WGNyZ0tUd0JsYmFHZkhwWDlXNWZtbjNGYUgwNlVPZUg2blNFc2FtL1lBR2xk?= =?utf-8?B?am5VSm1TRFM3NVB5U1hENytWcG5IeGxOUmVCT2dDakhoU2Vwc1lHMm55L095?= =?utf-8?B?bW9DUXdGNjRoRS9VT1c1MHM5bzhtakZYTVdyWTRWWnVCclhQNlIreHBOU05T?= =?utf-8?B?S3FTTXRQNVdFc0JxcTZNcVBQSitERnlGdmxabXBPazJrOFNnQ1M0a2Jya215?= =?utf-8?B?OVBNcXJiSzNnMS9XMUM4MGtNSzBRRFFWODArOFFoZXlBZnNoZUxHTTM4cW81?= =?utf-8?B?eUhTeWw1VU5hVHdRVmFQTm9vek5FTmNGeG5uUVBIRUxiVWlnNWY5S2FCQy9s?= =?utf-8?B?NU0zK3FnUXNLNEVxMks2YXNZWUEvUWY1dk9MVHJML2RQZnY3elgrYTQ0SDFW?= =?utf-8?B?WVlGQUpGRnN4MVdGS2tuUzJlaE9SNGRFUnVWTE5pUDFtRWRPbENZWS9wdlpE?= =?utf-8?B?bFhEV3NzZGR4Mlk2bnh4SW4vUzIzTXIxU1kxVEk1V3NvRk5oYTBpTFdqNDcz?= =?utf-8?B?SC9uWm8rd1FPdzRsaUF6dkE5blErZWUxakNaVmZVUTJzK2NJNEZtZG1xUXFW?= =?utf-8?B?Y3VUUkZtMk9MQ05KTmU3TjJScFhib0RUd3dXeFZwQXo3bFlOUGJaRUFuV2h3?= =?utf-8?B?MTVvQVpGYmtZcnZNN0QvVzJPOEhkUm9rSVllL3lIWjdsR0dJVitlaGxvQ0Vi?= =?utf-8?B?M0tKSXd3YzdQVDRLeVR0SGtHV1VnNGlmenUwcTVPWnFtbCtCZ1V4TndXN2lK?= =?utf-8?B?RmVnZW5iUFZkVXE3eDZpeXdDM2hLMTBLSWY3N1Z0VFpYZGRjbGFab1ZyL0dL?= =?utf-8?B?azNkRXJpNjN4M1p6djVhRWNCbHd3WHhBcjcxVXBRMWhpZzZOdk1VRThORFdP?= =?utf-8?B?MG5maGppdG4xdEp2aU9KbkdBTHN5cDZReThHRnlaQ1R2Qy94ZUtMSStTb0dR?= =?utf-8?B?M3dxREZmR2ZLUHU1dktoMkNNelp1czduclhjZ1VuUGhHWWdKMUMzbURpenVX?= =?utf-8?B?a3JiWit5cVZzZG8zTnNHTUs5eTA5QS8xcEM2RGpYcEpFSmxMQ2I5MVpRc01Q?= =?utf-8?B?bUtnSVhOTzNUcGdoaG9RRTJUSkNqd0JuREFLM01NWWdUYU5VVmJyZXFpUWlz?= =?utf-8?B?Z0pXeGwyNmlnZHFydWpvckM4R1Q3REVzMTdRcVRaUStObGNNcDFCbGhnRmVP?= =?utf-8?B?VEJmbjJ1VVlsUkF5WWd3TU9uMWlXVmFJSzZ4Q2s4M1RKSzRnUVR4NzY2Qldr?= =?utf-8?B?YVZrUHhGOGhUWWYyMm5EYzVnSGZMZjZFTHBzakFnRTIxUVozZjRhS3FENXgz?= =?utf-8?B?Z0pTTFA1ZVVPbXhDckkrUFdvSDFEMEg2QUhpMG9mVHlXV3JrdXAzMG1TTU51?= =?utf-8?B?T0NzY0lCdGZLNUZzcko1L0o4TFFGQ2ROSzFjVHN5TlZYRVNaT05pcXVueUZH?= =?utf-8?B?V2k4NTY0ZUovc3FhUUdtUC9ISk9pUzJFZzBFeVJwVStGL091VVRRWXBKMHBE?= =?utf-8?B?dUY3MzRpODNIcldVUUdRNzRLQTJIdGhDQ2FsRS9JcHl1dlRCdmNBWU5wRHBR?= =?utf-8?B?UVh4bGVZVGV4V21ocFhvRFB6WlA4d0JwcHhXT2RPZ3lhTFRmMlNUaVp4djlS?= =?utf-8?B?alRiVUcveVl1RnZOSlFpNnRRWmlOci9qa2NieFZRSGlUdllZRWtaWjVGOVZN?= =?utf-8?Q?AII4vhCC7a3vnDutGWyRe1FOaa/2VktRimEiM1m?= x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:DM4PR18MB4368.namprd18.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(1800799024)(366016)(7416014)(376014)(38070700018); DIR:OUT; SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?utf-8?B?anNTU0dySlVnTU82cUdENkM1VFhPdkdtM09BZk5xMzh3YTd3dHhwc2RDQmRu?= =?utf-8?B?YytiNi9QMzJySUVoZ3FRZVpvNE5HOUF4UWVLc0s5eEd5b1ZZY1prdTBQa0ZN?= =?utf-8?B?d3dHYUZLeVR5VmxrTGJpSmM5UThncmtUK0wreEhUSkNrYlp4M2sxQjhjaEQ3?= =?utf-8?B?WTViOEx5djBMVmgxcDdrWFAyMm9ERXEvWHUyRjFybDhlM0g4dzl3NjJqa2Fq?= =?utf-8?B?RHR1cG1HMndQQ2dpd1NmSmZLWjV0K0NOQVVEaUYyWmRlOHdKZ3AvT1Q0Sko5?= =?utf-8?B?SnM5M09FM1JTMTcxcGVhb2VjeHJ1RjJWaTNob2ZkSittTzhQZ2JrOG9ER09V?= =?utf-8?B?YkZwcG96RWYrSjNVQkM5by9mK1NxNG5MYmtMelZGSlJhak1XcmNkUmI4Vjd2?= =?utf-8?B?NWUwSldpV0ZESDJ6eGlQQjcwdkxIQ2lra3NPanYwT3NHT0tmVXVob1dHanVs?= =?utf-8?B?UU5xTVB2eHJvOEhVOCtvZEVlQ1BjeEh2dTNUdnNGRmJSZFRZc21zVzIvMUd1?= =?utf-8?B?Vnh6Tm80aEJUVzYrRVY2eDlSWjNEVDhYMGRFb2xlMWFMQTIwbjFCb3FFS211?= =?utf-8?B?bDh0QWpHSjNPMmVVVmdrQTJHQ0Rvd2JWTlhzZUhaUUJaSHhZMlZZc00wZE5I?= =?utf-8?B?enlGQ2JBanRFbmY3RVdwdnhacWlGWXYrRktVMXU1Q3JXa0xqbU5hc3AxczB1?= =?utf-8?B?WWRCcTl5UEQvUkFBK0NqQjlFRnB2RnVBSmNqd0F4TXVSQ2IxT29SbWZLd2V2?= =?utf-8?B?a3FpbFRWU2l2M09rWEhEcVp0WU9UT3M3OHI3RmRXblp6M3V6Z3ZjWHFoOVd1?= =?utf-8?B?aVhJYkpqczZubVBJUHpjeXRjQ1R6TnZ6OFMxbGh3dXg4RmRjM0Yyck1kSWYz?= =?utf-8?B?SFluMk1EbWJ1OUlsV3lTVWJPRFJnUWkzcUZ5VW5UVUFpY1MrSWRlMjNKLzZF?= =?utf-8?B?TE1OY2dEVjdUK0IwK1JmR3BsSHRGVUlrb0VtNWhnSE8xK2tqK2RnTXZPOW12?= =?utf-8?B?Wkd2TDJsY3ovQlJPc1M5MFZTaUcvRWlNbTdBc1ZzVXBybnNkOXhHd1VqVTNO?= =?utf-8?B?V2laQ1Q1WjBvbkZoTCthc2ExSEpIOTNraHpoaHpMd3JUUWMycDBGN2llUzlm?= =?utf-8?B?cktWcWlBWWZ5blorYkxoSVpqTG1ZM3BXdDJmdWlHdjR1U3dKd01FUHBRNW1r?= =?utf-8?B?U3VFQjh0bEpCdzlTSmVqRGdyQXN5Q3ppalNsaVRxdVdVS2FYWEdmL20yUWg4?= =?utf-8?B?UzRuOFZIeDVTQXdrb2d4SG1lbDQ5TFBJYTg5R0g0TmdMYWV5S3NoV0UyWmNm?= =?utf-8?B?aEJhajdjMmZ2SEF5VHZUeEFBN3hES0doRGlZNmtHU0RCeEhxSUYzUkJoR20w?= =?utf-8?B?Wk84Z0MwNWpQTUVPT1hVdU1vWVU1TU9aSnNKeVFueEFwekxhanIrZmNDRDJm?= =?utf-8?B?dU56YVBwdU5oUG0zMTdSaWQ4dEdRNWVaU1BySjJHNzR2K3c0ZlZPbGhvOGw0?= =?utf-8?B?YU9scHlqSjZ3dTBXRE5jbk9XTXorVE41UnJDd3QreGpnbnhiV3hHb1h5RS9a?= =?utf-8?B?T0Yxemh1aktYWjVWbTFGcXRCc25ualM4d2p0c3FrMmdNckFRRVBRV09ZSmxF?= =?utf-8?B?eFFWY0ErK0d2SDZBU0g3QkZCaitCb0tqZEtkSDB1ME1qeU8xZ29qYkRNNUZY?= =?utf-8?B?bEJ1MWU0dW12azNaTWxGMllmcGM1YWpGNVNJVEZocDRtOTN1YngzUmFxZWFI?= =?utf-8?B?SWQrbjNhQmZKR2xqd3ljanU3K1Q3R1prSlNCU05OSEhiNWpEM1h5bWYrWnUz?= =?utf-8?B?dDJtNjB6TWs2eG5ZamdUMFk5QXdEalpjeGYrdGszRVhaeU5kUE9JSXpZbTBY?= =?utf-8?B?b0xqd2psLzZmcE5aSG1ZamZ4RUFpaVpjOGhMK3RUWm1GWW5nQTY1RHRmVHdX?= =?utf-8?B?VlB4amN3cldlaElWeXVRL0I0WVpwN21scmRMc2hHUThGMW12NHJTNHhsSkZB?= =?utf-8?B?dXFyT2FsaFVWSGd2aTlWTkJ4cmFTbWc2RS9yNU1GM0lxUFVYS3psQ3NUbnVD?= =?utf-8?B?MTAxdWF6SzAyQ3hZU1NZa0ZaQXdDNjlqSS9NMXRPblhycFhYMkJFUkVLU1Ir?= =?utf-8?Q?sBsTCo+W2l5DRrdTeuXbF+a3m?= MIME-Version: 1.0 X-OriginatorOrg: marvell.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: DM4PR18MB4368.namprd18.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 78f80320-8c3a-4dba-5b76-08dd055f2f81 X-MS-Exchange-CrossTenant-originalarrivaltime: 15 Nov 2024 10:20:53.3384 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 70e1fb47-1155-421d-87fc-2e58f638b6e0 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: 0gQ+gbj/43l4bJc3GWB692OEkm7ZlTOjJwxf9LcMwj93rrlFUMteaRldAn9GY7KHF9Lr3DxmBKU5rf0SYM5C6Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO6PR18MB3842 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Proofpoint-GUID: dTKGQzfpO0jZvWYbZXtCxDq5k4c3nXIA X-Proofpoint-ORIG-GUID: dTKGQzfpO0jZvWYbZXtCxDq5k4c3nXIA X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.687,Hydra:6.0.235,FMLib:17.0.607.475 definitions=2020-10-13_15,2020-10-13_02,2020-04-07_01 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 >-----Original Message----- >From: Konstantin Ananyev >Sent: Tuesday, November 5, 2024 11:58 AM >To: Tomasz Duszynski ; Thomas Monjalon >Cc: Ruifeng.Wang@arm.com; bruce.richardson@intel.com; david.marchand@redha= t.com; dev@dpdk.org; >Jerin Jacob ; konstantin.v.ananyev@yandex.ru; mattias.= ronnblom@ericsson.com; >mb@smartsharesystems.com; roretzla@linux.microsoft.com; stephen@networkplu= mber.org; >zhoumin@loongson.cn >Subject: [EXTERNAL] RE: [PATCH v15 1/4] lib: add generic support for readi= ng PMU events > >> Add support for programming PMU counters and reading their values > in >> runtime bypassing kernel completely. > > This is especially useful in >> cases where CPU cores are isolated > i.=E2=80=8Ae run dedicated tasks. I= n such >> cases one cannot > > > >> Add support for programming PMU counters and reading their values in >> runtime bypassing kernel completely. >> >> This is especially useful in cases where CPU cores are isolated i.e >> run dedicated tasks. In such cases one cannot use standard perf >> utility without sacrificing latency and performance. > >LGTM in general, just few questions, nits - majority about docs/comments. > >> Signed-off-by: Tomasz Duszynski >> --- >> MAINTAINERS | 5 + >> app/test/meson.build | 1 + >> app/test/test_pmu.c | 49 +++ >> doc/api/doxy-api-index.md | 3 +- >> doc/api/doxy-api.conf.in | 1 + >> doc/guides/prog_guide/profile_app.rst | 29 ++ >> doc/guides/rel_notes/release_24_11.rst | 7 + >> lib/eal/meson.build | 3 + >> lib/meson.build | 1 + >> lib/pmu/meson.build | 13 + >> lib/pmu/pmu_private.h | 32 ++ >> lib/pmu/rte_pmu.c | 473 +++++++++++++++++++++++++ >> lib/pmu/rte_pmu.h | 205 +++++++++++ >> lib/pmu/version.map | 13 + >> 14 files changed, 834 insertions(+), 1 deletion(-) create mode >> 100644 app/test/test_pmu.c create mode 100644 lib/pmu/meson.build >> create mode 100644 lib/pmu/pmu_private.h create mode 100644 >> lib/pmu/rte_pmu.c create mode 100644 lib/pmu/rte_pmu.h create mode >> 100644 lib/pmu/version.map >> >> diff --git a/MAINTAINERS b/MAINTAINERS index cd78bc7db1..077efe41cf >> 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -1816,6 +1816,11 @@ M: Nithin Dabilpuram >> M: Pavan Nikhilesh >> F: lib/node/ >> >> +PMU - EXPERIMENTAL >> +M: Tomasz Duszynski >> +F: lib/pmu/ >> +F: app/test/test_pmu* >> + >> >> Test Applications >> ----------------- >> diff --git a/app/test/meson.build b/app/test/meson.build index >> 0f7e11969a..5f1622ecab 100644 >> --- a/app/test/meson.build >> +++ b/app/test/meson.build >> @@ -141,6 +141,7 @@ source_file_deps =3D { >> 'test_pmd_perf.c': ['ethdev', 'net'] + packet_burst_generator_deps, >> 'test_pmd_ring.c': ['net_ring', 'ethdev', 'bus_vdev'], >> 'test_pmd_ring_perf.c': ['ethdev', 'net_ring', 'bus_vdev'], >> + 'test_pmu.c': ['pmu'], >> 'test_power.c': ['power'], >> 'test_power_cpufreq.c': ['power'], >> 'test_power_intel_uncore.c': ['power'], diff --git >> a/app/test/test_pmu.c b/app/test/test_pmu.c new file mode 100644 index >> 0000000000..464e5068ec >> --- /dev/null >> +++ b/app/test/test_pmu.c >> @@ -0,0 +1,49 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause >> + * Copyright(C) 2024 Marvell International Ltd. >> + */ >> + >> +#include >> + >> +#include "test.h" >> + >> +static int >> +test_pmu_read(void) >> +{ >> + const char *name =3D NULL; >> + int tries =3D 10, event; >> + uint64_t val =3D 0; >> + >> + if (name =3D=3D NULL) { >> + printf("PMU not supported on this arch\n"); >> + return TEST_SKIPPED; >> + } >> + >> + if (rte_pmu_init() < 0) >> + return TEST_FAILED; >> + >> + event =3D rte_pmu_add_event(name); >> + while (tries--) >> + val +=3D rte_pmu_read(event); >> + >> + rte_pmu_fini(); >> + >> + return val ? TEST_SUCCESS : TEST_FAILED; } >> + >> +static struct unit_test_suite pmu_tests =3D { >> + .suite_name =3D "pmu autotest", >> + .setup =3D NULL, >> + .teardown =3D NULL, >> + .unit_test_cases =3D { >> + TEST_CASE(test_pmu_read), >> + TEST_CASES_END() >> + } >> +}; >> + >> +static int >> +test_pmu(void) >> +{ >> + return unit_test_suite_runner(&pmu_tests); >> +} >> + >> +REGISTER_FAST_TEST(pmu_autotest, true, true, test_pmu); >> diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md >> index 266c8b90dc..3e6020f367 100644 >> --- a/doc/api/doxy-api-index.md >> +++ b/doc/api/doxy-api-index.md >> @@ -240,7 +240,8 @@ The public API headers are grouped by topics: >> [log](@ref rte_log.h), >> [errno](@ref rte_errno.h), >> [trace](@ref rte_trace.h), >> - [trace_point](@ref rte_trace_point.h) >> + [trace_point](@ref rte_trace_point.h), [pmu](@ref rte_pmu.h) >> >> - **misc**: >> [EAL config](@ref rte_eal.h), >> diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index >> c94f02d411..f4b382e073 100644 >> --- a/doc/api/doxy-api.conf.in >> +++ b/doc/api/doxy-api.conf.in >> @@ -69,6 +69,7 @@ INPUT =3D @TOPDIR@/doc/api/doxy-api-= index.md \ >> @TOPDIR@/lib/pdcp \ >> @TOPDIR@/lib/pdump \ >> @TOPDIR@/lib/pipeline \ >> + @TOPDIR@/lib/pmu \ >> @TOPDIR@/lib/port \ >> @TOPDIR@/lib/power \ >> @TOPDIR@/lib/ptr_compress \ diff --git >> a/doc/guides/prog_guide/profile_app.rst >> b/doc/guides/prog_guide/profile_app.rst >> index a6b5fb4d5e..854c515a61 100644 >> --- a/doc/guides/prog_guide/profile_app.rst >> +++ b/doc/guides/prog_guide/profile_app.rst >> @@ -7,6 +7,35 @@ Profile Your Application The following sections >> describe methods of profiling DPDK applications on different >> architectures. >> >> +Performance counter based profiling >> +----------------------------------- >> + >> +Majority of architectures support some performance monitoring unit (PMU= ). >> +Such unit provides programmable counters that monitor specific events. >> + >> +Different tools gather that information, like for example perf. >> +However, in some scenarios when CPU cores are isolated and run >> +dedicated tasks interrupting those tasks with perf may be undesirable. >> + >> +In such cases, an application can use the PMU library to read such even= ts via >``rte_pmu_read()``. >> + >> +By default, userspace applications are not allowed to access PMU >> +internals. That can be changed by setting >> +``/sys/kernel/perf_event_paranoid`` to 2 (that should be a default >> +value anyway) and adding ``CAP_PERFMON`` capability to DPDK >> +application. Please refer to ``Documentation/admin-guide/perf-security.= rst`` under Linux sources >for more information. Fairly recent kernel, i.e >=3D 5.9, is advised too. >> + >> +As of now implementation imposes certain limitations: >> + >> +* Management APIs that normally return a non-negative value will >> +return error (``-ENOTSUP``) while >> + ``rte_pmu_read()`` will return ``UINT64_MAX`` if running under unsupp= orted operating system. >> + >> +* Only EAL lcores are supported >> + >> +* EAL lcores must not share a cpu >> + >> +* Each EAL lcore measures same group of events >> + >> >> Profiling on x86 >> ---------------- >> diff --git a/doc/guides/rel_notes/release_24_11.rst >> b/doc/guides/rel_notes/release_24_11.rst >> index fa4822d928..d34ecb55e0 100644 >> --- a/doc/guides/rel_notes/release_24_11.rst >> +++ b/doc/guides/rel_notes/release_24_11.rst >> @@ -247,6 +247,13 @@ New Features >> Added ability for node to advertise and update multiple xstat counter= s, >> that can be retrieved using ``rte_graph_cluster_stats_get``. >> >> +* **Added PMU library.** >> + >> + Added a new performance monitoring unit (PMU) library which allows >> + applications to perform self monitoring activities without depending = on external utilities >like perf. >> + After integration with :doc:`../prog_guide/trace_lib` data gathered >> + from hardware counters can be stored in CTF format for further analys= is. >> + >> >> Removed Items >> ------------- >> diff --git a/lib/eal/meson.build b/lib/eal/meson.build index >> e1d6c4cf17..1349624653 100644 >> --- a/lib/eal/meson.build >> +++ b/lib/eal/meson.build >> @@ -18,6 +18,9 @@ deps +=3D ['log', 'kvargs'] if not is_windows >> deps +=3D ['telemetry'] >> endif >> +if dpdk_conf.has('RTE_LIB_PMU') >> + deps +=3D ['pmu'] >> +endif >> if dpdk_conf.has('RTE_USE_LIBBSD') >> ext_deps +=3D libbsd >> endif >> diff --git a/lib/meson.build b/lib/meson.build index >> ce92cb5537..968ad29e8d 100644 >> --- a/lib/meson.build >> +++ b/lib/meson.build >> @@ -13,6 +13,7 @@ libraries =3D [ >> 'kvargs', # eal depends on kvargs >> 'argparse', >> 'telemetry', # basic info querying >> + 'pmu', >> 'eal', # everything depends on eal >> 'ptr_compress', >> 'ring', >> diff --git a/lib/pmu/meson.build b/lib/pmu/meson.build new file mode >> 100644 index 0000000000..f173b6f55c >> --- /dev/null >> +++ b/lib/pmu/meson.build >> @@ -0,0 +1,13 @@ >> +# SPDX-License-Identifier: BSD-3-Clause # Copyright(C) 2024 Marvell >> +International Ltd. >> + >> +if not is_linux >> + build =3D false >> + reason =3D 'only supported on Linux' >> + subdir_done() >> +endif >> + >> +headers =3D files('rte_pmu.h') >> +sources =3D files('rte_pmu.c') >> + >> +deps +=3D ['log'] >> diff --git a/lib/pmu/pmu_private.h b/lib/pmu/pmu_private.h new file >> mode 100644 index 0000000000..d2b15615bf >> --- /dev/null >> +++ b/lib/pmu/pmu_private.h >> @@ -0,0 +1,32 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause >> + * Copyright(c) 2024 Marvell >> + */ >> + >> +#ifndef _PMU_PRIVATE_H_ >> +#define _PMU_PRIVATE_H_ >> + >> +/** >> + * Architecture specific PMU init callback. >> + * >> + * @return >> + * 0 in case of success, negative value otherwise. >> + */ >> +int >> +pmu_arch_init(void); >> + >> +/** >> + * Architecture specific PMU cleanup callback. >> + */ >> +void >> +pmu_arch_fini(void); >> + >> +/** >> + * Apply architecture specific settings to config before passing it to = syscall. >> + * >> + * @param config >> + * Architecture specific event configuration. Consult kernel sources = for available options. >> + */ >> +void >> +pmu_arch_fixup_config(uint64_t config[3]); >> + >> +#endif /* _PMU_PRIVATE_H_ */ >> diff --git a/lib/pmu/rte_pmu.c b/lib/pmu/rte_pmu.c new file mode >> 100644 index 0000000000..dd57961627 >> --- /dev/null >> +++ b/lib/pmu/rte_pmu.c >> @@ -0,0 +1,473 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause >> + * Copyright(C) 2024 Marvell International Ltd. >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "pmu_private.h" >> + >> +#define EVENT_SOURCE_DEVICES_PATH "/sys/bus/event_source/devices" >> + >> +#define FIELD_PREP(m, v) (((uint64_t)(v) << (__builtin_ffsll(m) - 1)) >> +& (m)) >> + >> +RTE_LOG_REGISTER_DEFAULT(rte_pmu_logtype, INFO) #define >> +RTE_LOGTYPE_PMU rte_pmu_logtype >> + >> +#define PMU_LOG(level, ...) \ >> + RTE_LOG_LINE(level, PMU, ## __VA_ARGS__) >> + >> +/* A structure describing an event */ struct rte_pmu_event { >> + char *name; >> + unsigned int index; >> + TAILQ_ENTRY(rte_pmu_event) next; >> +}; >> + >> +struct rte_pmu rte_pmu; >> + >> +/* >> + * Following __rte_weak functions provide default no-op. >> +Architectures should override them if >> + * necessary. >> + */ >> + >> +int >> +__rte_weak pmu_arch_init(void) >> +{ >> + return 0; >> +} >> + >> +void >> +__rte_weak pmu_arch_fini(void) >> +{ >> +} >> + >> +void >> +__rte_weak pmu_arch_fixup_config(uint64_t __rte_unused config[3]) { } >> + >> +static int >> +get_term_format(const char *name, int *num, uint64_t *mask) { >> + char path[PATH_MAX]; >> + char *config =3D NULL; >> + int high, low, ret; >> + FILE *fp; >> + >> + *num =3D *mask =3D 0; >> + snprintf(path, sizeof(path), EVENT_SOURCE_DEVICES_PATH "/%s/format/%s"= , rte_pmu.name, name); >> + fp =3D fopen(path, "r"); >> + if (fp =3D=3D NULL) >> + return -errno; >> + >> + errno =3D 0; >> + ret =3D fscanf(fp, "%m[^:]:%d-%d", &config, &low, &high); >> + if (ret < 2) { >> + ret =3D -ENODATA; >> + goto out; >> + } >> + if (errno) { >> + ret =3D -errno; >> + goto out; >> + } >> + >> + if (ret =3D=3D 2) >> + high =3D low; >> + >> + *mask =3D RTE_GENMASK64(high, low); >> + /* Last digit should be [012]. If last digit is missing 0 is implied. = */ >> + *num =3D config[strlen(config) - 1]; >> + *num =3D isdigit(*num) ? *num - '0' : 0; >> + >> + ret =3D 0; >> +out: >> + free(config); >> + fclose(fp); >> + >> + return ret; >> +} >> + >> +static int >> +parse_event(char *buf, uint64_t config[3]) { >> + char *token, *term; >> + int num, ret, val; >> + uint64_t mask; >> + >> + config[0] =3D config[1] =3D config[2] =3D 0; >> + >> + token =3D strtok(buf, ","); >> + while (token) { >> + errno =3D 0; >> + /* =3D */ >> + ret =3D sscanf(token, "%m[^=3D]=3D%i", &term, &val); >> + if (ret < 1) >> + return -ENODATA; >> + if (errno) >> + return -errno; >> + if (ret =3D=3D 1) >> + val =3D 1; >> + >> + ret =3D get_term_format(term, &num, &mask); >> + free(term); >> + if (ret) >> + return ret; >> + >> + config[num] |=3D FIELD_PREP(mask, val); >> + token =3D strtok(NULL, ","); >> + } >> + >> + return 0; >> +} >> + >> +static int >> +get_event_config(const char *name, uint64_t config[3]) { >> + char path[PATH_MAX], buf[BUFSIZ]; >> + FILE *fp; >> + int ret; >> + >> + snprintf(path, sizeof(path), EVENT_SOURCE_DEVICES_PATH "/%s/events/%s"= , rte_pmu.name, name); >> + fp =3D fopen(path, "r"); >> + if (fp =3D=3D NULL) >> + return -errno; >> + >> + ret =3D fread(buf, 1, sizeof(buf), fp); >> + if (ret =3D=3D 0) { >> + fclose(fp); >> + >> + return -EINVAL; >> + } >> + fclose(fp); >> + buf[ret] =3D '\0'; >> + >> + return parse_event(buf, config); >> +} >> + >> +static int >> +do_perf_event_open(uint64_t config[3], int group_fd) { >> + struct perf_event_attr attr =3D { >> + .size =3D sizeof(struct perf_event_attr), >> + .type =3D PERF_TYPE_RAW, >> + .exclude_kernel =3D 1, >> + .exclude_hv =3D 1, >> + .disabled =3D 1, >> + .pinned =3D group_fd =3D=3D -1, >> + }; >> + >> + pmu_arch_fixup_config(config); >> + >> + attr.config =3D config[0]; >> + attr.config1 =3D config[1]; >> + attr.config2 =3D config[2]; >> + >> + return syscall(SYS_perf_event_open, &attr, 0, -1, group_fd, 0); } >> + >> +static int >> +open_events(struct rte_pmu_event_group *group) { >> + struct rte_pmu_event *event; >> + uint64_t config[3]; >> + int num =3D 0, ret; >> + >> + /* group leader gets created first, with fd =3D -1 */ >> + group->fds[0] =3D -1; >> + >> + TAILQ_FOREACH(event, &rte_pmu.event_list, next) { >> + ret =3D get_event_config(event->name, config); >> + if (ret) >> + continue; >> + >> + ret =3D do_perf_event_open(config, group->fds[0]); >> + if (ret =3D=3D -1) { >> + ret =3D -errno; >> + goto out; >> + } >> + >> + group->fds[event->index] =3D ret; >> + num++; >> + } >> + >> + return 0; >> +out: >> + for (--num; num >=3D 0; num--) { >> + close(group->fds[num]); >> + group->fds[num] =3D -1; >> + } >> + >> + return ret; >> +} >> + >> +static int >> +mmap_events(struct rte_pmu_event_group *group) { >> + long page_size =3D sysconf(_SC_PAGE_SIZE); >> + unsigned int i; >> + void *addr; >> + int ret; >> + >> + for (i =3D 0; i < rte_pmu.num_group_events; i++) { >> + addr =3D mmap(0, page_size, PROT_READ, MAP_SHARED, group->fds[i], 0); >> + if (addr =3D=3D MAP_FAILED) { >> + ret =3D -errno; >> + goto out; >> + } >> + >> + group->mmap_pages[i] =3D addr; >> + } >> + >> + return 0; >> +out: >> + for (; i; i--) { >> + munmap(group->mmap_pages[i - 1], page_size); >> + group->mmap_pages[i - 1] =3D NULL; >> + } >> + >> + return ret; >> +} >> + >> +static void >> +cleanup_events(struct rte_pmu_event_group *group) { >> + unsigned int i; >> + >> + if (group->fds[0] !=3D -1) >> + ioctl(group->fds[0], PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP); >> + >> + for (i =3D 0; i < rte_pmu.num_group_events; i++) { >> + if (group->mmap_pages[i]) { >> + munmap(group->mmap_pages[i], sysconf(_SC_PAGE_SIZE)); >> + group->mmap_pages[i] =3D NULL; >> + } >> + >> + if (group->fds[i] !=3D -1) { >> + close(group->fds[i]); >> + group->fds[i] =3D -1; >> + } >> + } >> + >> + group->enabled =3D false; >> +} >> + >> +int >> +__rte_pmu_enable_group(struct rte_pmu_event_group *group) { >> + int ret; >> + >> + if (rte_pmu.num_group_events =3D=3D 0) >> + return -ENODEV; >> + >> + ret =3D open_events(group); >> + if (ret) >> + goto out; >> + >> + ret =3D mmap_events(group); >> + if (ret) >> + goto out; >> + >> + if (ioctl(group->fds[0], PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) = =3D=3D -1) { >> + ret =3D -errno; >> + goto out; >> + } >> + >> + if (ioctl(group->fds[0], PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) = =3D=3D -1) { >> + ret =3D -errno; >> + goto out; >> + } >> + >> + group->enabled =3D true; >> + >> + return 0; >> +out: >> + cleanup_events(group); >> + >> + return ret; >> +} >> + >> +static int >> +scan_pmus(void) >> +{ >> + char path[PATH_MAX]; >> + struct dirent *dent; >> + const char *name; >> + DIR *dirp; >> + >> + dirp =3D opendir(EVENT_SOURCE_DEVICES_PATH); >> + if (dirp =3D=3D NULL) >> + return -errno; >> + >> + while ((dent =3D readdir(dirp))) { >> + name =3D dent->d_name; >> + if (name[0] =3D=3D '.') >> + continue; >> + >> + /* sysfs entry should either contain cpus or be a cpu */ >> + if (!strcmp(name, "cpu")) >> + break; >> + >> + snprintf(path, sizeof(path), EVENT_SOURCE_DEVICES_PATH "/%s/cpus", na= me); >> + if (access(path, F_OK) =3D=3D 0) >> + break; >> + } >> + >> + if (dent) { >> + rte_pmu.name =3D strdup(name); >> + if (rte_pmu.name =3D=3D NULL) { >> + closedir(dirp); >> + >> + return -ENOMEM; >> + } >> + } >> + >> + closedir(dirp); >> + >> + return rte_pmu.name ? 0 : -ENODEV; >> +} >> + >> +static struct rte_pmu_event * >> +new_event(const char *name) >> +{ >> + struct rte_pmu_event *event; >> + >> + event =3D calloc(1, sizeof(*event)); >> + if (event =3D=3D NULL) >> + goto out; >> + >> + event->name =3D strdup(name); >> + if (event->name =3D=3D NULL) { >> + free(event); >> + event =3D NULL; >> + } >> + >> +out: >> + return event; >> +} >> + >> +static void >> +free_event(struct rte_pmu_event *event) { >> + free(event->name); >> + free(event); >> +} >> + >> +int >> +rte_pmu_add_event(const char *name) >> +{ >> + struct rte_pmu_event *event; >> + char path[PATH_MAX]; >> + >> + if (!rte_pmu.initialized) { >> + PMU_LOG(ERR, "PMU is not initialized"); >> + return -ENODEV; >> + } >> + >> + if (rte_pmu.num_group_events + 1 >=3D RTE_MAX_NUM_GROUP_EVENTS) { >> + PMU_LOG(ERR, "Excessive number of events in a group (%d > %d)", >> + rte_pmu.num_group_events, RTE_MAX_NUM_GROUP_EVENTS); >> + return -ENOSPC; >> + } >> + >> + snprintf(path, sizeof(path), EVENT_SOURCE_DEVICES_PATH "/%s/events/%s"= , rte_pmu.name, name); >> + if (access(path, R_OK)) { >> + PMU_LOG(ERR, "Cannot access %s", path); >> + return -ENODEV; >> + } >> + >> + TAILQ_FOREACH(event, &rte_pmu.event_list, next) { >> + if (strcmp(event->name, name)) >> + continue; >> + >> + return event->index; >> + } >> + >> + event =3D new_event(name); >> + if (event =3D=3D NULL) { >> + PMU_LOG(ERR, "Failed to create event %s", name); >> + return -ENOMEM; >> + } >> + >> + event->index =3D rte_pmu.num_group_events++; >> + TAILQ_INSERT_TAIL(&rte_pmu.event_list, event, next); >> + >> + return event->index; >> +} >> + >> +int >> +rte_pmu_init(void) >> +{ >> + int ret; >> + >> + if (rte_pmu.initialized) >> + return 0; >> + >> + ret =3D scan_pmus(); >> + if (ret) { >> + PMU_LOG(ERR, "Failed to scan for event sources"); >> + goto out; >> + } >> + >> + ret =3D pmu_arch_init(); >> + if (ret) { >> + PMU_LOG(ERR, "Failed to setup arch internals"); >> + goto out; >> + } >> + >> + TAILQ_INIT(&rte_pmu.event_list); >> + rte_pmu.initialized =3D 1; >> +out: >> + if (ret) { >> + free(rte_pmu.name); >> + rte_pmu.name =3D NULL; >> + } >> + >> + return ret; >> +} >> + >> +void >> +rte_pmu_fini(void) >> +{ >> + struct rte_pmu_event *event, *tmp_event; >> + struct rte_pmu_event_group *group; >> + unsigned int i; >> + >> + if (!rte_pmu.initialized) >> + return; >> + >> + RTE_TAILQ_FOREACH_SAFE(event, &rte_pmu.event_list, next, tmp_event) { >> + TAILQ_REMOVE(&rte_pmu.event_list, event, next); >> + free_event(event); >> + } >> + >> + for (i =3D 0; i < RTE_DIM(rte_pmu.event_groups); i++) { >> + group =3D &rte_pmu.event_groups[i]; >> + if (!group->enabled) >> + continue; >> + >> + cleanup_events(group); >> + } >> + >> + pmu_arch_fini(); >> + free(rte_pmu.name); >> + rte_pmu.name =3D NULL; >> + rte_pmu.num_group_events =3D 0; >> +} >> diff --git a/lib/pmu/rte_pmu.h b/lib/pmu/rte_pmu.h new file mode >> 100644 index 0000000000..7d10a0dc56 >> --- /dev/null >> +++ b/lib/pmu/rte_pmu.h >> @@ -0,0 +1,205 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause >> + * Copyright(c) 2024 Marvell >> + */ >> + >> +#ifndef _RTE_PMU_H_ >> +#define _RTE_PMU_H_ >> + >> +/** >> + * @file >> + * >> + * PMU event tracing operations >> + * >> + * This file defines generic API and types necessary to setup PMU and >> + * read selected counters in runtime. Exported APIs are generally not M= T-safe. >> + * One exception is rte_pmu_read() which can be called concurrently >> +once >> + * everything has been setup. >> + */ >> + > >>From reading the code - I can see ithat PMU API is not MT safe. >The only function that can run in parallel is rte_pmu_read(), correct? >All other combinations: let say pmu_read() and add_event() are not possibl= e, right? >If so, then it is probably worth to articulate that explicitly in the publ= ic API comments, after >all extra comment doesn't hurt. > Yes, when it comes to this version pmu_read() is the only function that can= be called concurrently on different lcores. Okay, I'll try to rewrite existing comment to make tha= t more explicit. =20 >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +/** Maximum number of events in a group */ #define >> +RTE_MAX_NUM_GROUP_EVENTS 8 >> + >> +/** >> + * A structure describing a group of events. >> + */ >> +struct __rte_cache_aligned rte_pmu_event_group { >> + /** array of user pages */ >> + struct perf_event_mmap_page *mmap_pages[RTE_MAX_NUM_GROUP_EVENTS]; >> + int fds[RTE_MAX_NUM_GROUP_EVENTS]; /**< array of event descriptors */ >> + TAILQ_ENTRY(rte_pmu_event_group) next; /**< list entry */ >> + bool enabled; /**< true if group was enabled on particular lcore */ >> +}; >> + >> +/** >> + * A PMU state container. >> + */ >> +struct rte_pmu { >> + struct rte_pmu_event_group event_groups[RTE_MAX_LCORE]; /**< event gro= ups */ >> + unsigned int num_group_events; /**< number of events in a group */ >> + unsigned int initialized; /**< initialization counter */ >> + char *name; /**< name of core PMU listed under /sys/bus/event_source/d= evices */ >> + TAILQ_HEAD(, rte_pmu_event) event_list; /**< list of matching events >> +*/ }; >> + >> +/** PMU state container */ >> +extern struct rte_pmu rte_pmu; >> + >> +/** Each architecture supporting PMU needs to provide its own version >> +*/ #ifndef rte_pmu_pmc_read #define rte_pmu_pmc_read(index) ({ >> +(void)(index); 0; }) #endif >> + >> +/** >> + * @warning >> + * @b EXPERIMENTAL: this API may change without prior notice >> + * >> + * Read PMU counter. >> + * >> + * @warning This should not be called directly. >> + * >> + * @param pc >> + * Pointer to the mmapped user page. >> + * @return >> + * Counter value read from hardware. >> + */ >> +__rte_experimental >> +static __rte_always_inline uint64_t >> +__rte_pmu_read_userpage(struct perf_event_mmap_page *pc) { #define >> +__RTE_PMU_READ_ONCE(x) (*(const volatile typeof(x) *)&(x)) >> + uint64_t width, offset; >> + uint32_t seq, index; >> + int64_t pmc; >> + >> + for (;;) { >> + seq =3D __RTE_PMU_READ_ONCE(pc->lock); >> + rte_compiler_barrier(); >> + index =3D __RTE_PMU_READ_ONCE(pc->index); >> + offset =3D __RTE_PMU_READ_ONCE(pc->offset); >> + width =3D __RTE_PMU_READ_ONCE(pc->pmc_width); >> + >> + /* index set to 0 means that particular counter cannot be used */ >> + if (likely(pc->cap_user_rdpmc && index)) { >> + pmc =3D rte_pmu_pmc_read(index - 1); >> + pmc <<=3D 64 - width; >> + pmc >>=3D 64 - width; >> + offset +=3D pmc; >> + } >> + >> + rte_compiler_barrier(); >> + >> + if (likely(__RTE_PMU_READ_ONCE(pc->lock) =3D=3D seq)) >> + return offset; >> + } >> + >> + return 0; >> +} >> + >> +/** >> + * @warning >> + * @b EXPERIMENTAL: this API may change without prior notice >> + * >> + * Enable group of events on the calling lcore. >> + * >> + * @warning This should not be called directly. >> + * >> + * @param group >> + * Pointer to the group which will be enabled. >> + * @return >> + * 0 in case of success, negative value otherwise. >> + */ >> +__rte_experimental >> +int >> +__rte_pmu_enable_group(struct rte_pmu_event_group *group); >> + >> +/** >> + * @warning >> + * @b EXPERIMENTAL: this API may change without prior notice >> + * >> + * Initialize PMU library. >> + * >> + * @return >> + * 0 in case of success, negative value otherwise. >> + */ >> +__rte_experimental >> +int >> +rte_pmu_init(void); >> + >> +/** >> + * @warning >> + * @b EXPERIMENTAL: this API may change without prior notice >> + * >> + * Finalize PMU library. >> + */ >> +__rte_experimental >> +void >> +rte_pmu_fini(void); >> + >> +/** >> + * @warning >> + * @b EXPERIMENTAL: this API may change without prior notice >> + * >> + * Add event to the group of enabled events. >> + * >> + * @param name >> + * Name of an event listed under /sys/bus/event_source/devices//= events. >> + * @return >> + * Event index in case of success, negative value otherwise. >> + */ >> +__rte_experimental >> +int >> +rte_pmu_add_event(const char *name); >> + >> +/** >> + * @warning >> + * @b EXPERIMENTAL: this API may change without prior notice >> + * >> + * Read hardware counter configured to count occurrences of an event. >> + * >> + * @param index >> + * Index of an event to be read. >> + * @return >> + * Event value read from register. In case of errors or lack of suppo= rt >> + * 0 is returned. In other words, stream of zeros in a trace file >> + * indicates problem with reading particular PMU event register. >> + */ > >As I remember that function implies to be called from the thread bind to o= ne particular cpu. >If that is still the case - please state it explicitly in the comments abo= ve. > Yes, that still the case. Will mention that.=20 >> +__rte_experimental >> +static __rte_always_inline uint64_t >> +rte_pmu_read(unsigned int index) >> +{ >> + struct rte_pmu_event_group *group =3D >> +&rte_pmu.event_groups[rte_lcore_id()]; > >I think we better check here value returned by rte_lcore_id() before using= it as an index. > I'll add this check. Hopefully it will disappear once this gets switched to= per-lcore-variables (given performance won't deteriorate). =20 >> + int ret; >> + >> + if (unlikely(!rte_pmu.initialized)) >> + return 0; >> + >> + if (unlikely(!group->enabled)) { >> + ret =3D __rte_pmu_enable_group(group); >> + if (ret) >> + return 0; >> + } >> + >> + if (unlikely(index >=3D rte_pmu.num_group_events)) >> + return 0; >> + >> + return __rte_pmu_read_userpage(group->mmap_pages[index]); >> +} >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif /* _RTE_PMU_H_ */ >> diff --git a/lib/pmu/version.map b/lib/pmu/version.map new file mode >> 100644 index 0000000000..d0f907d13d >> --- /dev/null >> +++ b/lib/pmu/version.map >> @@ -0,0 +1,13 @@ >> +EXPERIMENTAL { >> + global: >> + >> + # added in 24.11 >> + __rte_pmu_enable_group; >> + rte_pmu; >> + rte_pmu_add_event; >> + rte_pmu_fini; >> + rte_pmu_init; >> + rte_pmu_read; >> + >> + local: *; >> +}; >> -- >> 2.34.1