diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c index 61412527dca..698575548b4 100644 --- a/fs/procfs/fs_procfsproc.c +++ b/fs/procfs/fs_procfsproc.c @@ -53,6 +53,10 @@ #include #include +#ifdef CONFIG_SCHED_CRITMONITOR +# include +#endif + #include #include #include @@ -62,7 +66,7 @@ #include #include -#ifdef CONFIG_SCHED_CPULOAD +#if defined(CONFIG_SCHED_CPULOAD) || defined(CONFIG_SCHED_CRITMONITOR) # include #endif @@ -105,6 +109,9 @@ enum proc_node_e PROC_CMDLINE, /* Task command line */ #ifdef CONFIG_SCHED_CPULOAD PROC_LOADAVG, /* Average CPU utilization */ +#endif +#ifdef CONFIG_SCHED_CRITMONITOR + PROC_CRITMON, /* Critical section monitor */ #endif PROC_STACK, /* Task stack info */ PROC_GROUP, /* Group directory */ @@ -167,9 +174,24 @@ static FAR const char *g_policy[4] = "SCHED_FIFO", "SCHED_RR", "SCHED_SPORADIC", "SCHED_OTHER" }; +/**************************************************************************** + * External Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SCHED_CRITMONITOR +/* If CONFIG_SCHED_CRITMONITOR is selected, then platform-specific logic + * must provide the following interface. This interface simply converts an + * elapsed time into well known units for presentation by the ProcFS file + * system.. + */ + +void up_critmon_convert(uint32_t starttime, FAR struct timespec *ts); +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ + /* Helpers */ static FAR const struct proc_node_s * @@ -185,6 +207,11 @@ static ssize_t proc_loadavg(FAR struct proc_file_s *procfile, FAR struct tcb_s *tcb, FAR char *buffer, size_t buflen, off_t offset); #endif +#ifdef CONFIG_SCHED_CRITMONITOR +static ssize_t proc_critmon(FAR struct proc_file_s *procfile, + FAR struct tcb_s *tcb, FAR char *buffer, size_t buflen, + off_t offset); +#endif static ssize_t proc_stack(FAR struct proc_file_s *procfile, FAR struct tcb_s *tcb, FAR char *buffer, size_t buflen, off_t offset); @@ -273,6 +300,13 @@ static const struct proc_node_s g_loadavg = }; #endif +#ifdef CONFIG_SCHED_CRITMONITOR +static const struct proc_node_s g_critmon = +{ + "critmon", "critmon", (uint8_t)PROC_CRITMON, DTYPE_FILE /* Critical Section Monitor */ +}; +#endif + static const struct proc_node_s g_stack = { "stack", "stack", (uint8_t)PROC_STACK, DTYPE_FILE /* Task stack info */ @@ -309,6 +343,9 @@ static FAR const struct proc_node_s * const g_nodeinfo[] = &g_cmdline, /* Task command line */ #ifdef CONFIG_SCHED_CPULOAD &g_loadavg, /* Average CPU utilization */ +#endif +#ifdef CONFIG_SCHED_CRITMONITOR + &g_critmon, /* Critical section Monitor */ #endif &g_stack, /* Task stack info */ &g_group, /* Group directory */ @@ -329,6 +366,9 @@ static const struct proc_node_s * const g_level0info[] = &g_cmdline, /* Task command line */ #ifdef CONFIG_SCHED_CPULOAD &g_loadavg, /* Average CPU utilization */ +#endif +#ifdef CONFIG_SCHED_CRITMONITOR + &g_critmon, /* Critical section monitor */ #endif &g_stack, /* Task stack info */ &g_group, /* Group directory */ @@ -743,6 +783,84 @@ static ssize_t proc_loadavg(FAR struct proc_file_s *procfile, } #endif +/**************************************************************************** + * Name: proc_critmon + ****************************************************************************/ + +#ifdef CONFIG_SCHED_CRITMONITOR +static ssize_t proc_critmon(FAR struct proc_file_s *procfile, + FAR struct tcb_s *tcb, FAR char *buffer, + size_t buflen, off_t offset) +{ + struct timespec maxtime; + size_t remaining; + size_t linesize; + size_t copysize; + size_t totalsize; + + remaining = buflen; + totalsize = 0; + + /* Convert the for maximum time pre-emption disabled */ + + if (tcb->premp_max > 0) + { + up_critmon_convert(tcb->premp_max, &maxtime); + } + else + { + maxtime.tv_sec = 0; + maxtime.tv_nsec = 0; + } + + /* Reset the maximum */ + + tcb->premp_max = 0; + + /* Generate output for maximum time pre-emption disabled */ + + linesize = snprintf(procfile->line, STATUS_LINELEN, "%lu.%09lu,", + (unsigned long)maxtime.tv_sec, + (unsigned long)maxtime.tv_nsec); + copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, &offset); + + totalsize += copysize; + buffer += copysize; + remaining -= copysize; + + if (totalsize >= buflen) + { + return totalsize; + } + + /* Convert and generate output for maximum time in a critical section */ + + if (tcb->crit_max > 0) + { + up_critmon_convert(tcb->crit_max, &maxtime); + } + else + { + maxtime.tv_sec = 0; + maxtime.tv_nsec = 0; + } + + /* Reset the maximum */ + + tcb->crit_max = 0; + + /* Generate output for maximum time in a critical section */ + + linesize = snprintf(procfile->line, STATUS_LINELEN, "%lu.%09lu\n", + (unsigned long)maxtime.tv_sec, + (unsigned long)maxtime.tv_nsec); + copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, &offset); + + totalsize += copysize; + return totalsize; +} +#endif + /**************************************************************************** * Name: proc_stack ****************************************************************************/ @@ -1324,6 +1442,11 @@ static ssize_t proc_read(FAR struct file *filep, FAR char *buffer, case PROC_LOADAVG: /* Average CPU utilization */ ret = proc_loadavg(procfile, tcb, buffer, buflen, filep->f_pos); break; +#endif +#ifdef CONFIG_SCHED_CRITMONITOR + case PROC_CRITMON: /* Critical section monitor */ + ret = proc_critmon(procfile, tcb, buffer, buflen, filep->f_pos); + break; #endif case PROC_STACK: /* Task stack info */ ret = proc_stack(procfile, tcb, buffer, buflen, filep->f_pos); diff --git a/include/nuttx/irq.h b/include/nuttx/irq.h index 8cb3fd63d02..bc18dc2ba46 100644 --- a/include/nuttx/irq.h +++ b/include/nuttx/irq.h @@ -1,7 +1,8 @@ /**************************************************************************** * include/nuttx/irq.h * - * Copyright (C) 2007-2011, 2013, 2016-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2011, 2013, 2016-2017 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -196,7 +197,8 @@ int irqchain_detach(int irq, xcpt_t isr, FAR void *arg); * ****************************************************************************/ -#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) +#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \ + defined(CONFIG_SCHED_CRITMONITOR) irqstate_t enter_critical_section(void); #else # define enter_critical_section(f) up_irq_save(f) @@ -223,7 +225,8 @@ irqstate_t enter_critical_section(void); * ****************************************************************************/ -#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) +#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \ + defined(CONFIG_SCHED_CRITMONITOR) void leave_critical_section(irqstate_t flags); #else # define leave_critical_section(f) up_irq_restore(f) diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 17fb3706226..e564e21409d 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -696,6 +696,16 @@ struct tcb_s FAR void *pthread_data[CONFIG_NPTHREAD_KEYS]; #endif + /* Pre-emption monitor support ************************************************/ + +#ifdef CONFIG_SCHED_CRITMONITOR + uint32_t crit_flags; /* Flag values used by the monitor */ + uint32_t premp_start; /* Time when preemption disabled */ + uint32_t premp_max; /* Max time preemption disabled */ + uint32_t crit_start; /* Time critical section entered */ + uint32_t crit_max; /* Max time in critical section */ +#endif + /* Library related fields *****************************************************/ int pterrno; /* Current per-thread errno */ @@ -931,7 +941,8 @@ int group_exitinfo(pid_t pid, FAR struct binary_s *bininfo); ********************************************************************************/ #if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC) || \ - defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SMP) + defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SCHED_CRITMONITOR) || \ + defined(CONFIG_SMP) void sched_resume_scheduler(FAR struct tcb_s *tcb); #else # define sched_resume_scheduler(tcb) @@ -953,7 +964,8 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb); * ********************************************************************************/ -#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION) +#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION) || \ + defined(CONFIG_SCHED_CRITMONITOR) void sched_suspend_scheduler(FAR struct tcb_s *tcb); #else # define sched_suspend_scheduler(tcb) diff --git a/sched/Kconfig b/sched/Kconfig index 26037f1478e..1c4e86721f4 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -700,6 +700,39 @@ config SCHED_IRQMONITOR counts will be available in the mounted procfs file systems at the top-level file, "irqs". +config SCHED_CRITMONITOR + bool "Enable Critical Section monitoring" + default n + depends on FS_PROCFS + ---help--- + Enables logic that monitors the duration of time that a thread keeps + interrupts or pre-emption disabled. These global locks can have + negative consequences to real timer performance: Disabling interrupts + adds jitter in the time when a interrupt request is asserted until + the hardware can responds with the interrupt. Disabling pre-emption + adds jitter in the timer from when the event is posted in the + interrupt handler until the task that responds to the event can run. + + If this option is selected, then the following interfaces must be + provided by platform-specific logic: + + uint32_t up_critmon_gettime(void); + void up_critmon_convert(uint32_t starttime, 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 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. + + The second interface simple converts an elapsed time into well known + units for presentation by the ProcFS file system.. + config SCHED_CPULOAD bool "Enable CPU load monitoring" default n diff --git a/sched/irq/Make.defs b/sched/irq/Make.defs index c2c11b3dd9d..18c2ad11f55 100644 --- a/sched/irq/Make.defs +++ b/sched/irq/Make.defs @@ -44,6 +44,8 @@ endif endif else ifeq ($(CONFIG_SCHED_INSTRUMENTATION_CSECTION),y) CSRCS += irq_csection.c +else ifeq ($(CONFIG_SCHED_CRITMONITOR),y) +CSRCS += irq_csection.c endif ifeq ($(CONFIG_SCHED_IRQMONITOR),y) diff --git a/sched/irq/irq_csection.c b/sched/irq/irq_csection.c index 9d7943cbf67..4df37aeee5a 100644 --- a/sched/irq/irq_csection.c +++ b/sched/irq/irq_csection.c @@ -49,7 +49,8 @@ #include "sched/sched.h" #include "irq/irq.h" -#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) +#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \ + defined(CONFIG_SCHED_CRITMONITOR) /**************************************************************************** * Public Data @@ -375,9 +376,12 @@ try_again: &g_cpu_irqlock); rtcb->irqcount = 1; -#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION /* Note that we have entered the critical section */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_csection(rtcb, true); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION sched_note_csection(rtcb, true); #endif } @@ -388,7 +392,8 @@ try_again: return ret; } -#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) */ +#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \ + * defined(CONFIG_SCHED_CRITMONITOR) */ irqstate_t enter_critical_section(void) { irqstate_t ret; @@ -408,7 +413,12 @@ irqstate_t enter_critical_section(void) /* Yes.. Note that we have entered the critical section */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_csection(rtcb, true); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION sched_note_csection(rtcb, true); +#endif } /* Return interrupt status */ @@ -507,9 +517,12 @@ void leave_critical_section(irqstate_t flags) } else { -#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION /* No.. Note that we have left the critical section */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_csection(rtcb, false); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION sched_note_csection(rtcb, false); #endif /* Decrement our count on the lock. If all CPUs have @@ -563,7 +576,10 @@ void leave_critical_section(irqstate_t flags) up_irq_restore(flags); } -#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) */ + +#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || + * defined(CONFIG_SCHED_CRITMONITOR) */ + void leave_critical_section(irqstate_t flags) { /* Check if we were called from an interrupt handler and that the tasks @@ -577,7 +593,12 @@ void leave_critical_section(irqstate_t flags) /* Yes.. Note that we have left the critical section */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_csection(rtcb, false); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION sched_note_csection(rtcb, false); +#endif } /* Restore the previous interrupt state. */ @@ -669,4 +690,5 @@ bool irq_cpu_locked(int cpu) } #endif -#endif /* CONFIG_SMP || CONFIG_SCHED_INSTRUMENTATION_CSECTION */ +#endif /* CONFIG_SMP || CONFIG_SCHED_INSTRUMENTATION_CSECTION || + * CONFIG_SCHED_CRITMONITOR */ diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index fd0bc78b7df..7686cc5d774 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -73,6 +73,8 @@ ifeq ($(CONFIG_SCHED_SPORADIC),y) CSRCS += sched_sporadic.c sched_suspendscheduler.c else ifeq ($(CONFIG_SCHED_INSTRUMENTATION),y) CSRCS += sched_suspendscheduler.c +else ifeq ($(CONFIG_SCHED_CRITMONITOR),y) +CSRCS += sched_suspendscheduler.c endif ifneq ($(CONFIG_RR_INTERVAL),0) @@ -81,6 +83,8 @@ else ifeq ($(CONFIG_SCHED_SPORADIC),y) CSRCS += sched_resumescheduler.c else ifeq ($(CONFIG_SCHED_INSTRUMENTATION),y) CSRCS += sched_resumescheduler.c +else ifeq ($(CONFIG_SCHED_CRITMONITOR),y) +CSRCS += sched_resumescheduler.c else ifeq ($(CONFIG_SMP),y) CSRCS += sched_resumescheduler.c endif @@ -101,10 +105,6 @@ else CSRCS += sched_processtimer.c endif -ifeq ($(CONFIG_SCHED_INSTRUMENTATION_BUFFER),y) -CSRCS += sched_note.c -endif - ifeq ($(CONFIG_SMP),y) CSRCS += sched_tasklistlock.c ifeq ($(CONFIG_ARCH_GLOBAL_IRQDISABLE),y) @@ -114,6 +114,14 @@ CSRCS += sched_thistask.c endif endif +ifeq ($(CONFIG_SCHED_INSTRUMENTATION_BUFFER),y) +CSRCS += sched_note.c +endif + +ifeq ($(CONFIG_SCHED_CRITMONITOR),y) +CSRCS += sched_critmonitor.c +endif + # Include sched build support DEPPATH += --dep-path sched diff --git a/sched/sched/sched.h b/sched/sched/sched.h index f84adcf9922..581b492840e 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -496,6 +496,15 @@ void sched_tasklist_unlock(irqstate_t lock); void weak_function sched_process_cpuload(void); #endif +/* Critical section monitor */ + +#ifdef CONFIG_SCHED_CRITMONITOR +void sched_critmon_preemption(FAR struct tcb_s *tcb, bool state); +void sched_critmon_csection(FAR struct tcb_s *tcb, bool state); +void sched_critmon_resume(FAR struct tcb_s *tcb); +void sched_critmon_suspend(FAR struct tcb_s *tcb); +#endif + /* TCB operations */ bool sched_verifytcb(FAR struct tcb_s *tcb); diff --git a/sched/sched/sched_critmonitor.c b/sched/sched/sched_critmonitor.c new file mode 100644 index 00000000000..c6ffcb01911 --- /dev/null +++ b/sched/sched/sched_critmonitor.c @@ -0,0 +1,249 @@ +/**************************************************************************** + * sched/sched/sched_critmonitor.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "sched/sched.h" + +#ifdef CONFIG_SCHED_CRITMONITOR + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Flags used by the critical section monitor */ + +#define CRITMON_PREEMPT (1 << 0) /* Bit 0: Pre-emption is disabled */ +#define CRITMON_CSECTION (1 << 1) /* Bit 1: In a critical section */ + +#define DISABLE_PREEMPT(t) do { (t)->flags |= CRITMON_PREEMPT; } while (0) +#define ENTER_CSECTION(t) do { (t)->flags |= CRITMON_PREEMPT; } while (0) + +#define ENABLE_PREEMPT(t) do { (t)->flags &= ~CRITMON_PREEMPT; } while (0) +#define LEAVE_CSECTION(t) do { (t)->flags &= ~CRITMON_PREEMPT; } while (0) + +#define PREEMPT_DISABLED(t) (((t)->crit_flags & CRITMON_PREEMPT) != 0) +#define IN_CSECTION(t) (((t)->crit_flags & CRITMON_CSECTION) != 0) + +/**************************************************************************** + * External Function Prototypes + ****************************************************************************/ + +/* If CONFIG_SCHED_CRITMONITOR is selected, then platform-specific logic + * must provide the following interface. This 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 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. + */ + +uint32_t up_critmon_gettime(void); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sched_critmon_preemption + * + * Description: + * Called when there is any change in pre-emptible state of a thread. + * + * Assumptions: + * Called within a critical section. + * + ****************************************************************************/ + +void sched_critmon_preemption(FAR struct tcb_s *tcb, bool state) +{ + /* Are we enabling or disabling pre-emption */ + + if (state) + { + DEBUGASSERT(tcb->premp_start == 0 && !PREEMPT_DISABLED(tcb)); + + /* Disabling.. Save the start time */ + + tcb->premp_start = up_critmon_gettime(); + DISABLE_PREEMPT(tcb); + } + else if (tcb->premp_start != 0) + { + DEBUGASSERT(PREEMPT_DISABLED(tcb)); + + /* Re-enabling.. Check for the max elapsed time */ + + uint32_t elapsed = tcb->premp_start - up_critmon_gettime(); + + tcb->premp_start = 0; + if (elapsed > tcb->premp_max) + { + tcb->premp_max = elapsed; + } + + ENABLE_PREEMPT(tcb); + } +} + +/**************************************************************************** + * Name: sched_critmon_csection + * + * Description: + * Called when a thread enters or leaves a critical section. + * + * Assumptions: + * Called within a critical section. + * + ****************************************************************************/ + +void sched_critmon_csection(FAR struct tcb_s *tcb, bool state) +{ + /* Are we entering or leaving the critical section? */ + + if (state) + { + /* Entering... Save the start time. */ + + DEBUGASSERT(tcb->crit_start == 0 && !IN_CSECTION(tcb)); + tcb->crit_start = up_critmon_gettime(); + } + else if (tcb->crit_start != 0) + { + DEBUGASSERT(IN_CSECTION(tcb)); + + /* Leaving .. Check for the max elapsed time */ + + uint32_t elapsed = tcb->crit_start - up_critmon_gettime(); + + tcb->crit_start = 0; + if (elapsed > tcb->crit_max) + { + tcb->crit_max = elapsed; + } + + ENTER_CSECTION(tcb); + } +} + +/**************************************************************************** + * Name: sched_critmon_resume + * + * Description: + * Called when a thread resumes execution, perhaps re-establishing a + * critical section or a non-pre-emptible state. + * + * Assumptions: + * Called within a critical section. + * + ****************************************************************************/ + +void sched_critmon_resume(FAR struct tcb_s *tcb) +{ + DEBUGASSERT(tcb->premp_start == 0 && tcb->crit_start == 0); + + /* Did this task disable pre-emption? */ + + if (PREEMPT_DISABLED(tcb)) + { + /* Yes.. Save the start time */ + + tcb->premp_start = up_critmon_gettime(); + } + + /* Was this task in a critical section? */ + + if (IN_CSECTION(tcb)) + { + /* Yes.. Save the start time */ + + tcb->crit_start = up_critmon_gettime(); + } +} + +/**************************************************************************** + * Name: sched_critmon_suspend + * + * Description: + * Called when a thread suspends execution, perhaps terminating a + * critical section or a non-pre-emptible state. + * + * Assumptions: + * Called within a critical section. + * + ****************************************************************************/ + +void sched_critmon_suspend(FAR struct tcb_s *tcb) +{ + /* Did this task disable pre-emption? */ + + if (PREEMPT_DISABLED(tcb)) + { + /* Re-enabling.. Check for the max elapsed time */ + + uint32_t elapsed = tcb->premp_start - up_critmon_gettime(); + + tcb->premp_start = 0; + if (elapsed > tcb->premp_max) + { + tcb->premp_max = elapsed; + } + } + + /* Is this task in a critical section? */ + + if (IN_CSECTION(tcb)) + { + /* Leaving .. Check for the max elapsed time */ + + uint32_t elapsed = tcb->crit_start - up_critmon_gettime(); + + tcb->crit_start = 0; + if (elapsed > tcb->crit_max) + { + tcb->crit_max = elapsed; + } + } +} + +#endif \ No newline at end of file diff --git a/sched/sched/sched_lock.c b/sched/sched/sched_lock.c index dbe20c06349..4b5916bf083 100644 --- a/sched/sched/sched_lock.c +++ b/sched/sched/sched_lock.c @@ -250,14 +250,20 @@ int sched_lock(void) (void)up_fetchsub16(&g_global_lockcount, 1); #endif -#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION +#if defined(CONFIG_SCHED_INSTRUMENTATION_PREEMPTION) || \ + defined(CONFIG_SCHED_CRITMONITOR) /* Check if we just acquired the lock */ if (rtcb->lockcount == 1) { /* Note that we have pre-emption locked */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_premption(rtcb, true); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION sched_note_premption(rtcb, true); +#endif } #endif @@ -299,14 +305,20 @@ int sched_lock(void) rtcb->lockcount++; -#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION +#if defined(CONFIG_SCHED_INSTRUMENTATION_PREEMPTION) || \ + defined(CONFIG_SCHED_CRITMONITOR) /* Check if we just acquired the lock */ if (rtcb->lockcount == 1) { /* Note that we have pre-emption locked */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_premption(rtcb, true); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION sched_note_premption(rtcb, true); +#endif } #endif } diff --git a/sched/sched/sched_resumescheduler.c b/sched/sched/sched_resumescheduler.c index 08f104a5d83..fd06c08b1a9 100644 --- a/sched/sched/sched_resumescheduler.c +++ b/sched/sched/sched_resumescheduler.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/sched/sched_resumescheduler.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -49,7 +49,8 @@ #include "sched/sched.h" #if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC) || \ - defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SMP) + defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SCHED_CRITMONITOR) || \ + defined(CONFIG_SMP) /**************************************************************************** * Public Functions @@ -96,9 +97,12 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb) } #endif -#ifdef CONFIG_SCHED_INSTRUMENTATION - /* Inidicate the task has been resumed */ + /* Indicate the task has been resumed */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_resume(tcb); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION sched_note_resume(tcb); #endif @@ -142,4 +146,5 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb) } #endif /* CONFIG_RR_INTERVAL > 0 || CONFIG_SCHED_SPORADIC || \ - * CONFIG_SCHED_INSTRUMENTATION || CONFIG_SMP */ + * CONFIG_SCHED_INSTRUMENTATION || CONFIG_SCHED_CRITMONITOR || + * CONFIG_SMP */ diff --git a/sched/sched/sched_suspendscheduler.c b/sched/sched/sched_suspendscheduler.c index 857cb0be17f..a8be48386a5 100644 --- a/sched/sched/sched_suspendscheduler.c +++ b/sched/sched/sched_suspendscheduler.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/sched/sched_suspendscheduler.c * - * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2015-2016, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -50,7 +50,8 @@ #include "clock/clock.h" #include "sched/sched.h" -#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION) +#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION) || \ + defined(CONFIG_SCHED_CRITMONITOR) /**************************************************************************** * Public Functions @@ -83,11 +84,15 @@ void sched_suspend_scheduler(FAR struct tcb_s *tcb) } #endif -#ifdef CONFIG_SCHED_INSTRUMENTATION - /* Inidicate the task has been suspended */ + /* Indicate that the task has been suspended */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_suspend(tcb); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION sched_note_suspend(tcb); #endif } -#endif /* CONFIG_SCHED_SPORADIC || CONFIG_SCHED_INSTRUMENTATION */ +#endif /* CONFIG_SCHED_SPORADIC || CONFIG_SCHED_INSTRUMENTATION || + * CONFIG_SCHED_CRITMONITOR */ diff --git a/sched/sched/sched_unlock.c b/sched/sched/sched_unlock.c index 88140cb3757..2115990d2e8 100644 --- a/sched/sched/sched_unlock.c +++ b/sched/sched/sched_unlock.c @@ -103,11 +103,15 @@ int sched_unlock(void) if (rtcb->lockcount <= 0) { -#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION /* Note that we no longer have pre-emption disabled. */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_premption(rtcb, false); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION sched_note_premption(rtcb, false); #endif + /* Set the lock count to zero */ rtcb->lockcount = 0; @@ -254,11 +258,15 @@ int sched_unlock(void) if (rtcb->lockcount <= 0) { -#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION /* Note that we no longer have pre-emption disabled. */ +#ifdef CONFIG_SCHED_CRITMONITOR + sched_critmon_premption(rtcb, false); +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION sched_note_premption(rtcb, false); #endif + /* Set the lock count to zero */ rtcb->lockcount = 0;