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 <[email protected]> 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 <[email protected]> --- 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)
