mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 17:48:54 +08:00
This change enables performance monitoring unit (PMU) access from userspace on ARMv7-R architecture by adding CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS support and building PMU code for userspace when needed. Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
@@ -41,7 +41,7 @@ NSH (Flat Build)
|
|||||||
Configuring NuttX and compile::
|
Configuring NuttX and compile::
|
||||||
|
|
||||||
$ ./tools/configure.sh -l qemu-armv7r:nsh
|
$ ./tools/configure.sh -l qemu-armv7r:nsh
|
||||||
$ make -j`nproc`
|
$ make -j$(nproc)
|
||||||
|
|
||||||
Running with qemu::
|
Running with qemu::
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ with MPU support::
|
|||||||
|
|
||||||
$ cd nuttx
|
$ cd nuttx
|
||||||
$ ./tools/configure.sh qemu-armv7r:pnsh
|
$ ./tools/configure.sh qemu-armv7r:pnsh
|
||||||
$ make -j`nproc`
|
$ make -j$(nproc)
|
||||||
|
|
||||||
Running with qemu (note: both nuttx and nuttx_user must be loaded)::
|
Running with qemu (note: both nuttx and nuttx_user must be loaded)::
|
||||||
|
|
||||||
@@ -107,3 +107,92 @@ The nuttx ELF image can be debugged with QEMU.
|
|||||||
$ arm-none-eabi-gdb -tui --eval-command='target remote localhost:1234' nuttx
|
$ arm-none-eabi-gdb -tui --eval-command='target remote localhost:1234' nuttx
|
||||||
(gdb) add-symbol-file nuttx_user
|
(gdb) add-symbol-file nuttx_user
|
||||||
(gdb) c
|
(gdb) c
|
||||||
|
|
||||||
|
=====================
|
||||||
|
Userspace PMU Access
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
This document describes how to enable and use Performance Monitoring Unit (PMU)
|
||||||
|
access from userspace applications on the ARM v7-R QEMU board. The PMU provides
|
||||||
|
hardware performance counters that can be used to analyze and profile application
|
||||||
|
performance.
|
||||||
|
|
||||||
|
1. ARM v7-R QEMU board support
|
||||||
|
2. NuttX kernel with PMU support enabled
|
||||||
|
3. User-space access permissions configured
|
||||||
|
|
||||||
|
Kernel Configuration
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
To enable PMU support and userspace access, add the following configuration
|
||||||
|
options to your defconfig::
|
||||||
|
|
||||||
|
+CONFIG_ARCH_PERF_EVENTS_USER_ACCESS=y
|
||||||
|
+CONFIG_ARCH_PERF_EVENTS=y
|
||||||
|
|
||||||
|
|
||||||
|
Userspace API
|
||||||
|
|
||||||
|
**perf_gettime**
|
||||||
|
================
|
||||||
|
|
||||||
|
Basic Usage
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
clock_t start, end;
|
||||||
|
unsigned long frequency;
|
||||||
|
unsigned long cycles;
|
||||||
|
|
||||||
|
frequency = perf_getfreq();
|
||||||
|
if (frequency == 0) {
|
||||||
|
printf("ERROR: Performance frequency not available\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Operation Profiling Results:\n");
|
||||||
|
printf("CPU Frequency: %lu Hz\n\n", frequency);
|
||||||
|
printf("%-40s | %-12s | %-12s\n", "Operation", "Cycles", "Time (us)");
|
||||||
|
printf("%-40s-+-%-12s-+-%-12s\n",
|
||||||
|
"----------------------------------------",
|
||||||
|
"------------", "------------");
|
||||||
|
|
||||||
|
start = perf_gettime();
|
||||||
|
result = 1;
|
||||||
|
for (int i = 1; i < 1000; i++) {
|
||||||
|
result *= i;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = perf_gettime();
|
||||||
|
cycles = end - start;
|
||||||
|
printf("%-40s | %12lu | %12lu\n", "Multiplication (1K times)", cycles, (cycles * 1000000UL) / frequency);
|
||||||
|
|
||||||
|
start = perf_gettime();
|
||||||
|
result = 1000000;
|
||||||
|
for (int i = 1; i < 1000; i++) {
|
||||||
|
result /= (i + 1);
|
||||||
|
}
|
||||||
|
end = perf_gettime();
|
||||||
|
cycles = end - start;
|
||||||
|
|
||||||
|
printf("%-40s | %12lu | %12lu\n", "Division (1K times)", cycles, (cycles * 1000000UL) / frequency);
|
||||||
|
|
||||||
|
Testing with QEMU
|
||||||
|
=================
|
||||||
|
|
||||||
|
PNSH (Protected) Configuration
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
For protected build with userspace PMU access::
|
||||||
|
|
||||||
|
$ ./tools/configure.sh qemu-armv7r:pnsh
|
||||||
|
$ make -j$(nproc)
|
||||||
|
|
||||||
|
2. Run QEMU (load both kernel and userspace)::
|
||||||
|
|
||||||
|
$ qemu-system-arm -M virt -semihosting -nographic -cpu cortex-r5f -device loader,file=nuttx_user -device loader,file=nuttx
|
||||||
|
|
||||||
|
|||||||
@@ -1005,6 +1005,7 @@ config ARCH_ARMV7R
|
|||||||
default n
|
default n
|
||||||
select ARCH_HAVE_CPUINFO
|
select ARCH_HAVE_CPUINFO
|
||||||
select ARCH_HAVE_PERF_EVENTS
|
select ARCH_HAVE_PERF_EVENTS
|
||||||
|
select ARCH_HAVE_PERF_EVENTS_USER_ACCESS
|
||||||
|
|
||||||
config ARCH_CORTEXR4
|
config ARCH_CORTEXR4
|
||||||
bool
|
bool
|
||||||
|
|||||||
@@ -81,3 +81,8 @@ if(CONFIG_SMP)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_sources(arch PRIVATE ${SRCS})
|
target_sources(arch PRIVATE ${SRCS})
|
||||||
|
|
||||||
|
if(NOT CONFIG_BUILD_FLAT AND CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS)
|
||||||
|
target_sources(arch_interface PRIVATE arm_perf.c)
|
||||||
|
target_include_directories(arch_interface PRIVATE ${NUTTX_CHIP_ABS_DIR})
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -67,3 +67,7 @@ ifeq ($(CONFIG_SMP),y)
|
|||||||
CMN_CSRCS += arm_cpustart.c arm_smpcall.c
|
CMN_CSRCS += arm_cpustart.c arm_smpcall.c
|
||||||
CMN_CSRCS += arm_cpuidlestack.c arm_scu.c
|
CMN_CSRCS += arm_cpuidlestack.c arm_scu.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS),y)
|
||||||
|
CMN_UCSRCS += arm_perf.c
|
||||||
|
endif
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_ARCH_HAVE_PERF_EVENTS
|
#ifdef CONFIG_ARCH_HAVE_PERF_EVENTS
|
||||||
|
|
||||||
|
#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__)
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -84,11 +85,6 @@ unsigned long up_perf_getfreq(void)
|
|||||||
return g_cpu_freq;
|
return g_cpu_freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
clock_t up_perf_gettime(void)
|
|
||||||
{
|
|
||||||
return cp15_pmu_rdccr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void up_perf_convert(clock_t elapsed, struct timespec *ts)
|
void up_perf_convert(clock_t elapsed, struct timespec *ts)
|
||||||
{
|
{
|
||||||
clock_t left;
|
clock_t left;
|
||||||
@@ -97,4 +93,11 @@ void up_perf_convert(clock_t elapsed, struct timespec *ts)
|
|||||||
left = elapsed - ts->tv_sec * g_cpu_freq;
|
left = elapsed - ts->tv_sec * g_cpu_freq;
|
||||||
ts->tv_nsec = NSEC_PER_SEC * (uint64_t)left / g_cpu_freq;
|
ts->tv_nsec = NSEC_PER_SEC * (uint64_t)left / g_cpu_freq;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_BUILD_FLAT || __KERNEL__ */
|
||||||
|
|
||||||
|
clock_t up_perf_gettime(void)
|
||||||
|
{
|
||||||
|
return cp15_pmu_rdccr();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
#include <nuttx/spinlock.h>
|
#include <nuttx/spinlock.h>
|
||||||
#include <nuttx/wdog.h>
|
#include <nuttx/wdog.h>
|
||||||
|
|
||||||
#ifndef CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS
|
#ifndef CONFIG_ARCH_PERF_EVENTS_USER_ACCESS
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Preprocessors
|
* Preprocessors
|
||||||
@@ -134,7 +134,7 @@ clock_t perf_gettime(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# endif
|
# endif
|
||||||
#endif /* !CONFIG_ARCH_HAVE_PERF_EVENTS_USER_ACCESS */
|
#endif /* !CONFIG_ARCH_PERF_EVENTS_USER_ACCESS */
|
||||||
|
|
||||||
#if defined(CONFIG_ALARM_ARCH) || defined (CONFIG_TIMER_ARCH) || \
|
#if defined(CONFIG_ALARM_ARCH) || defined (CONFIG_TIMER_ARCH) || \
|
||||||
defined(CONFIG_ARCH_PERF_EVENTS)
|
defined(CONFIG_ARCH_PERF_EVENTS)
|
||||||
|
|||||||
Reference in New Issue
Block a user