From 1ac95584603258402ea4e9c48977e52f494f4c77 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 26 Nov 2018 11:29:20 -0600 Subject: [PATCH] sched/irq and sched/sched: Measurement of interrupt handler duration used to be available only in Tickless mode since it used the high resolution Tickless timer to measure interrupt time. This commit adds CONFIG_SCHED_IRQMONITOR_GETTIME which, if enabled, will force the interrupt duration caculation to use the same high-resolution, platform-specific timer as is used with the Critical Section Monitor. This leads to two improvements: (1) You can now measure interrupt duration in non-Tickless mode, and (2) in either mode, the interrupt duration and the critical section measures will use the same high-resulotion timer and should, therefore, never be any descripancy due to different clock sources. --- sched/Kconfig | 43 ++++++++++++++++++++++++---- sched/irq/irq.h | 2 -- sched/irq/irq_dispatch.c | 50 ++++++++++++++++++++++++++++++++- sched/sched/sched_critmonitor.c | 15 +++++++--- 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/sched/Kconfig b/sched/Kconfig index 5629665663..d5226e9673 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -716,6 +716,39 @@ config SCHED_IRQMONITOR counts will be available in the mounted procfs file systems at the top-level file, "irqs". +config SCHED_IRQMONITOR_GETTIME + bool "Custom Platform-specific Timer" + default y if SCHED_CRITMONITOR + default n if !SCHED_CRITMONITOR + depends on SCHED_IRQMONITOR && SCHED_TICKLESS + ---help--- + If CONFIG_SCHED_TICKLESS is enabled, then the high resolution + Tickless timer will be used by default. Otherwise, a platform- + specific timer is expected (the same timer used with the Critical + Section Monitor). The option will force use of that platform- + specifier timer even the CONFIG_SCHED_TICKLESs is defined. + + if CONFIG_SCHED_TICKLESS is not enabled or CONFIG_SCHED_IRQMONITOR_GETTIME + is selected, then platform-specific logic must provide the following in + order to support high resolution timing: + + uint32_t up_critmon_gettime(void); + void up_critmon_convert(uint32_t elapsed, FAR struct timespec *ts); + + The first interface simply provides the current time value in unknown + units. NOTE: This function may be called early before the timer has + been initialized. In that event, the function should just return a + start time of zero. + + Nothing is assumed about the units of this time value. The following + are assumed, however: (1) The time is an unsigned integer value, (2) + the time is monotonically increasing, and (3) the elapsed time (also + in unknown units) can be obtained by subtracting a start time from + the current time. + + The second interface simple converts an elapsed time into well known + units for presentation by the ProcFS file system. + config SCHED_CRITMONITOR bool "Enable Critical Section monitoring" default n @@ -744,13 +777,13 @@ config SCHED_CRITMONITOR start time of zero. Nothing is assumed about the units of this time value. The following - are assumed, however: (1) The time is an unsigned is an unsigned integer - value, (2) is is monotonically increasing, and (3) the elapsed time - (also in unknown units) can be obtained by subtracting a start time - from the current time. + are assumed, however: (1) The time is an unsigned integer value, (2) + the time is monotonically increasing, and (3) the elapsed time (also + in unknown units) can be obtained by subtracting a start time from + the current time. The second interface simple converts an elapsed time into well known - units for presentation by the ProcFS file system.. + units for presentation by the ProcFS file system. config SCHED_CPULOAD bool "Enable CPU load monitoring" diff --git a/sched/irq/irq.h b/sched/irq/irq.h index 124f26bf3b..b22da747a4 100644 --- a/sched/irq/irq.h +++ b/sched/irq/irq.h @@ -82,10 +82,8 @@ struct irq_info_s uint32_t mscount; /* Number of interrupts on this IRQ (MS) */ uint32_t lscount; /* Number of interrupts on this IRQ (LS) */ #endif -#ifdef CONFIG_SCHED_TICKLESS uint32_t time; /* Maximum execution time on this IRQ */ #endif -#endif }; #ifdef CONFIG_SCHED_IRQMONITOR diff --git a/sched/irq/irq_dispatch.c b/sched/irq/irq_dispatch.c index e217c8bc79..c09773a34d 100644 --- a/sched/irq/irq_dispatch.c +++ b/sched/irq/irq_dispatch.c @@ -81,7 +81,8 @@ * request */ -#if defined(CONFIG_SCHED_IRQMONITOR) && defined(CONFIG_SCHED_TICKLESS) +#ifdef CONFIG_SCHED_IRQMONITOR +#if defined(CONFIG_SCHED_TICKLESS) && !defined(CONFIG_SCHED_IRQMONITOR_GETTIME) # define CALL_VECTOR(ndx, vector, irq, context, arg) \ do \ { \ @@ -99,8 +100,55 @@ } \ while (0) #else +# define CALL_VECTOR(ndx, vector, irq, context, arg) \ + do \ + { \ + struct timespec delta; \ + uint32_t start; \ + uint32_t elapsed; \ + start = up_critmon_gettime(); \ + vector(irq, context, arg); \ + elapsed = up_critmon_gettime() - start; \ + up_critmon_convert(elapsed, &delta); \ + if (delta.tv_nsec > g_irqvector[ndx].time) \ + { \ + g_irqvector[ndx].time = delta.tv_nsec; \ + } \ + } \ + while (0) +#endif /* CONFIGSCHED_TICKLESS */ +#else # define CALL_VECTOR(ndx, vector, irq, context, arg) \ vector(irq, context, arg) +#endif /* CONFIG_SCHED_IRQMONITOR */ + +/**************************************************************************** + * External Function Prototypes + ****************************************************************************/ + +#ifndef CONFIG_SCHED_TICKLESS +/* If CONFIG_SCHED_TICKLESS is enabled, then the high resolution Tickless + * timer will be used. Otherwise, the platform specific logic must provide + * the following in order to support high resolution timing: + */ + +uint32_t up_critmon_gettime(void); +void up_critmon_convert(uint32_t elapsed, FAR struct timespec *ts); + +/* The first interface simply provides the current time value in unknown + * units. NOTE: This function may be called early before the timer has + * been initialized. In that event, the function should just return a + * start time of zero. + * + * Nothing is assumed about the units of this time value. The following + * are assumed, however: (1) The time is an unsigned integer value, (2) + * the time is monotonically increasing, and (3) the elapsed time (also + * in unknown units) can be obtained by subtracting a start time from + * the current time. + * + * The second interface simple converts an elapsed time into well known + * units. + */ #endif /**************************************************************************** diff --git a/sched/sched/sched_critmonitor.c b/sched/sched/sched_critmonitor.c index 0dc5629587..cc17d0eb61 100644 --- a/sched/sched/sched_critmonitor.c +++ b/sched/sched/sched_critmonitor.c @@ -37,8 +37,11 @@ * Included Files ****************************************************************************/ +#include + #include #include + #include "sched/sched.h" #ifdef CONFIG_SCHED_CRITMONITOR @@ -101,7 +104,8 @@ uint32_t g_crit_max[1]; * Called when there is any change in pre-emptible state of a thread. * * Assumptions: - * Called within a critical section. + * - Called within a critical section. + * - Never called from an interrupt handler * ****************************************************************************/ @@ -165,7 +169,8 @@ void sched_critmon_preemption(FAR struct tcb_s *tcb, bool state) * Called when a thread enters or leaves a critical section. * * Assumptions: - * Called within a critical section. + * - Called within a critical section. + * - Never called from an interrupt handler * ****************************************************************************/ @@ -229,7 +234,8 @@ void sched_critmon_csection(FAR struct tcb_s *tcb, bool state) * critical section or a non-pre-emptible state. * * Assumptions: - * Called within a critical section. + * - Called within a critical section. + * - Might be called from an interrupt handler * ****************************************************************************/ @@ -305,7 +311,8 @@ void sched_critmon_resume(FAR struct tcb_s *tcb) * critical section or a non-preemptible state. * * Assumptions: - * Called within a critical section. + * - Called within a critical section. + * - Might be called from an interrupt handler * ****************************************************************************/