You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ji...@apache.org on 2026/01/26 13:14:48 UTC
(nuttx) 05/06: libc/perf: userspace PMU access
This is an automated email from the ASF dual-hosted git repository.
jiuzhudong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 8f0e30b07c0a16d60da20f77d5135d778d32d19f
Author: Yanfeng Liu <p-...@xiaomi.com>
AuthorDate: Mon May 19 07:46:23 2025 +0800
libc/perf: userspace PMU access
Add ARCH_HAVE_PERF_EVENTS_USER_ACCESS capability to allow applications
to directly access hardware perf counters via perf_gettime() from
userspace, enabling performance monitoring and profiling without syscalls.
Signed-off-by: Yanfeng Liu <p-...@xiaomi.com>
---
arch/Kconfig | 7 ++++
libs/libc/sched/CMakeLists.txt | 4 ++
libs/libc/sched/Make.defs | 4 ++
libs/libc/sched/clock_perf.c | 91 ++++++++++++++++++++++++++++++++++++++++++
sched/clock/clock_perf.c | 17 +++++---
5 files changed, 118 insertions(+), 5 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 4a44cf7d335..63005207278 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -605,6 +605,13 @@ config ARCH_HAVE_PERF_EVENTS
---help---
The architecture supports hardware performance counting.
+config ARCH_HAVE_PERF_EVENTS_USER_ACCESS
+ bool
+ default n
+ select ARCH_HAVE_PERF_EVENTS
+ ---help---
+ Select if hardware allows userspace perf counter access.
+
config ARCH_PERF_EVENTS
bool "Configure hardware performance counting"
default y if SCHED_CRITMONITOR || SCHED_IRQMONITOR || RPMSG_PING || SEGGER_SYSVIEW
diff --git a/libs/libc/sched/CMakeLists.txt b/libs/libc/sched/CMakeLists.txt
index 70f76c1e014..9fb42c09fe2 100644
--- a/libs/libc/sched/CMakeLists.txt
+++ b/libs/libc/sched/CMakeLists.txt
@@ -43,4 +43,8 @@ if(NOT CONFIG_BUILD_KERNEL)
list(APPEND SRCS task_startup.c)
endif()
+if(CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS)
+ list(APPEND SRCS clock_perf.c)
+endif()
+
target_sources(c PRIVATE ${SRCS})
diff --git a/libs/libc/sched/Make.defs b/libs/libc/sched/Make.defs
index 24793634708..f3ffae413c2 100644
--- a/libs/libc/sched/Make.defs
+++ b/libs/libc/sched/Make.defs
@@ -39,6 +39,10 @@ ifneq ($(CONFIG_BUILD_KERNEL),y)
CSRCS += task_startup.c
endif # CONFIG_BUILD_KERNEL
+ifeq ($(CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS),y)
+ CSRCS += clock_perf.c
+endif
+
# Add the sched directory to the build
DEPPATH += --dep-path sched
diff --git a/libs/libc/sched/clock_perf.c b/libs/libc/sched/clock_perf.c
new file mode 100644
index 00000000000..097d85bd0d7
--- /dev/null
+++ b/libs/libc/sched/clock_perf.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * libs/libc/sched/clock_perf.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/bits.h>
+#include <nuttx/clock.h>
+
+#if defined(CONFIG_PERF_OVERFLOW_CORRECTION) && ULONG_MAX != UINT64_MAX
+
+/****************************************************************************
+ * Preprocessors
+ ****************************************************************************/
+
+#define MASK_LO GENMASK_ULL(31, 0)
+#define MASK_HI GENMASK_ULL(63, 32)
+
+#define LO(x) (uint32_t)((x) & MASK_LO)
+#define HI(x) (uint32_t)(((x) & MASK_HI) >> 32)
+
+#define PACK64(hi,lo) ((MASK_LO & (lo)) | (((uint64_t)(hi)) << 32))
+#define CLOCK_T(p) (LO(p) | ((clock_t)HI(p) << \
+ CONFIG_ARCH_PERF_COUNT_BITWIDTH))
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static atomic64_t g_perf; /* hi word is overflow, lo word is last */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * perf_gettime
+ ****************************************************************************/
+
+clock_t perf_gettime(void)
+{
+ uint64_t snap;
+ uint64_t result;
+ clock_t now;
+
+ do
+ {
+ snap = atomic64_read(&g_perf);
+ now = up_perf_gettime();
+ result = PACK64(now < LO(snap) ? HI(snap) + 1 : HI(snap), now);
+ }
+ while (!atomic64_try_cmpxchg(&g_perf, &snap, result));
+
+ return CLOCK_T(result);
+}
+
+#else
+
+/****************************************************************************
+ * perf_gettime
+ ****************************************************************************/
+
+clock_t perf_gettime(void)
+{
+ return up_perf_gettime();
+}
+
+#endif
diff --git a/sched/clock/clock_perf.c b/sched/clock/clock_perf.c
index 76db84aabe9..33c8398410c 100644
--- a/sched/clock/clock_perf.c
+++ b/sched/clock/clock_perf.c
@@ -31,7 +31,13 @@
#include <nuttx/spinlock.h>
#include <nuttx/wdog.h>
-#if defined(CONFIG_PERF_OVERFLOW_CORRECTION) && ULONG_MAX != UINT64_MAX
+#ifndef CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS
+
+/****************************************************************************
+ * Preprocessors
+ ****************************************************************************/
+
+# if defined(CONFIG_PERF_OVERFLOW_CORRECTION) && ULONG_MAX != UINT64_MAX
/****************************************************************************
* Private Types
@@ -104,8 +110,8 @@ clock_t perf_gettime(void)
return result;
}
-#elif defined(CONFIG_ALARM_ARCH) || defined (CONFIG_TIMER_ARCH) || \
- defined(CONFIG_ARCH_PERF_EVENTS)
+# elif defined(CONFIG_ALARM_ARCH) || defined (CONFIG_TIMER_ARCH) || \
+ defined(CONFIG_ARCH_PERF_EVENTS)
/****************************************************************************
* perf_gettime
@@ -116,7 +122,7 @@ clock_t perf_gettime(void)
return up_perf_gettime();
}
-#else
+# else
/****************************************************************************
* perf_gettime
@@ -127,7 +133,8 @@ clock_t perf_gettime(void)
return clock_systime_ticks();
}
-#endif
+# endif
+#endif /* !CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS */
#if defined(CONFIG_ALARM_ARCH) || defined (CONFIG_TIMER_ARCH) || \
defined(CONFIG_ARCH_PERF_EVENTS)