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.

This commit is contained in:
Gregory Nutt 2018-11-26 11:29:20 -06:00
parent b88ce04770
commit 1ac9558460
4 changed files with 98 additions and 12 deletions

View File

@ -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"

View File

@ -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

View File

@ -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
/****************************************************************************

View File

@ -37,8 +37,11 @@
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sched.h>
#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
*
****************************************************************************/