Scheduler instrumentation: Fix some associated with monitoring critical sections

This commit is contained in:
Gregory Nutt 2016-03-21 17:08:07 -06:00
parent adf3c73219
commit d20db82fcb
5 changed files with 65 additions and 13 deletions

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* include/nuttx/irq.h * include/nuttx/irq.h
* *
* Copyright (C) 2007-2011, 2013 Gregory Nutt. All rights reserved. * Copyright (C) 2007-2011, 2013, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -113,7 +113,7 @@ int irq_attach(int irq, xcpt_t isr);
* *
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_SMP #if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION)
irqstate_t enter_critical_section(void); irqstate_t enter_critical_section(void);
#else #else
# define enter_critical_section(f) up_irq_save(f) # define enter_critical_section(f) up_irq_save(f)
@ -131,7 +131,7 @@ irqstate_t enter_critical_section(void);
* *
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_SMP #if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION)
void leave_critical_section(irqstate_t flags); void leave_critical_section(irqstate_t flags);
#else #else
# define leave_critical_section(f) up_irq_restore(f) # define leave_critical_section(f) up_irq_restore(f)
@ -144,4 +144,3 @@ void leave_critical_section(irqstate_t flags);
#endif #endif
#endif /* __INCLUDE_NUTTX_IRQ_H */ #endif /* __INCLUDE_NUTTX_IRQ_H */

View File

@ -627,7 +627,7 @@ config SCHED_INSTRUMENTATION_PREEMPTION
config SCHED_INSTRUMENTATION_CSECTION config SCHED_INSTRUMENTATION_CSECTION
bool "Critical section monitor hooks" bool "Critical section monitor hooks"
default n default n
depends on SMP depends on EXPERIMENTAL
---help--- ---help---
Enables additional hooks for entry and exit from critical sections. Enables additional hooks for entry and exit from critical sections.
Interrupts are disabled while within a critical section. Board- Interrupts are disabled while within a critical section. Board-
@ -635,6 +635,13 @@ config SCHED_INSTRUMENTATION_CSECTION
void sched_note_csection(FAR struct tcb_s *tcb, bool state); void sched_note_csection(FAR struct tcb_s *tcb, bool state);
NOTE: This option is marked EXPERIMENTAL because there is a logical
error in the design. That error is that sched_note_get() calls
enter/leave_critical_section. When the buffer note buffer has been
filled, each of these calls causes an entry to be removed from the
note buffer to make more space. The end result is that every other
note is lost when dumping the note buffer. Not very useful!
config SCHED_INSTRUMENTATION_BUFFER config SCHED_INSTRUMENTATION_BUFFER
bool "Buffer instrumentation data in memory" bool "Buffer instrumentation data in memory"
default n default n

View File

@ -37,6 +37,8 @@ CSRCS += irq_initialize.c irq_attach.c irq_dispatch.c irq_unexpectedisr.c
ifeq ($(CONFIG_SMP),y) ifeq ($(CONFIG_SMP),y)
CSRCS += irq_csection.c CSRCS += irq_csection.c
else ifeq ($(CONFIG_SCHED_INSTRUMENTATION_CSECTION),y)
CSRCS += irq_csection.c
endif endif
# Include irq build support # Include irq build support

View File

@ -48,11 +48,13 @@
#include "sched/sched.h" #include "sched/sched.h"
#include "irq/irq.h" #include "irq/irq.h"
#ifdef CONFIG_SMP #if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION)
/**************************************************************************** /****************************************************************************
* Public Data * Public Data
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_SMP
/* This is the spinlock that enforces critical sections when interrupts are /* This is the spinlock that enforces critical sections when interrupts are
* disabled. * disabled.
*/ */
@ -63,6 +65,7 @@ volatile spinlock_t g_cpu_irqlock = SP_UNLOCKED;
volatile spinlock_t g_cpu_irqsetlock; volatile spinlock_t g_cpu_irqsetlock;
volatile cpu_set_t g_cpu_irqset; volatile cpu_set_t g_cpu_irqset;
#endif
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
@ -78,6 +81,7 @@ volatile cpu_set_t g_cpu_irqset;
* *
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_SMP
irqstate_t enter_critical_section(void) irqstate_t enter_critical_section(void)
{ {
FAR struct tcb_s *rtcb; FAR struct tcb_s *rtcb;
@ -96,6 +100,8 @@ irqstate_t enter_critical_section(void)
/* Do we already have interrupts disabled? */ /* Do we already have interrupts disabled? */
rtcb = this_task(); rtcb = this_task();
DEBUGASSERT(rtcb != NULL);
if (rtcb->irqcount > 0) if (rtcb->irqcount > 0)
{ {
/* Yes... make sure that the spinlock is set and increment the IRQ /* Yes... make sure that the spinlock is set and increment the IRQ
@ -136,6 +142,26 @@ irqstate_t enter_critical_section(void)
return up_irq_save(); return up_irq_save();
} }
#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) */
irqstate_t enter_critical_section(void)
{
/* Check if we were called from an interrupt handler */
if (!up_interrupt_context())
{
FAR struct tcb_s *rtcb = this_task();
DEBUGASSERT(rtcb != NULL);
/* No.. note that we have entered the critical section */
sched_note_csection(rtcb, true);
}
/* And disable interrupts */
return up_irq_save();
}
#endif
/**************************************************************************** /****************************************************************************
* Name: leave_critical_section * Name: leave_critical_section
@ -146,6 +172,7 @@ irqstate_t enter_critical_section(void)
* *
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_SMP
void leave_critical_section(irqstate_t flags) void leave_critical_section(irqstate_t flags)
{ {
/* Do nothing if called from an interrupt handler */ /* Do nothing if called from an interrupt handler */
@ -153,8 +180,7 @@ void leave_critical_section(irqstate_t flags)
if (!up_interrupt_context()) if (!up_interrupt_context())
{ {
FAR struct tcb_s *rtcb = this_task(); FAR struct tcb_s *rtcb = this_task();
DEBUGASSERT(rtcb != 0 && rtcb->irqcount > 0);
DEBUGASSERT(rtcb->irqcount > 0);
/* Will we still have interrupts disabled after decrementing the /* Will we still have interrupts disabled after decrementing the
* count? * count?
@ -211,5 +237,25 @@ void leave_critical_section(irqstate_t flags)
up_irq_restore(flags); up_irq_restore(flags);
} }
} }
#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) */
void leave_critical_section(irqstate_t flags)
{
/* Check if we were called from an interrupt handler */
#endif /* CONFIG_SMP */ if (!up_interrupt_context())
{
FAR struct tcb_s *rtcb = this_task();
DEBUGASSERT(rtcb != NULL);
/* Note that we have left the critical section */
sched_note_csection(rtcb, false);
}
/* Restore the previous interrupt state. */
up_irq_restore(flags);
}
#endif
#endif /* CONFIG_SMP || CONFIG_SCHED_INSTRUMENTATION_CSECTION*/

View File

@ -401,8 +401,6 @@ void sched_note_csection(FAR struct tcb_s *tcb, bool enter)
note.ncs_count[1] = (uint8_t)((tcb->irqcount >> 8) & 0xff); note.ncs_count[1] = (uint8_t)((tcb->irqcount >> 8) & 0xff);
#endif #endif
note_systime((FAR struct note_common_s *)&note);
/* Add the note to circular buffer */ /* Add the note to circular buffer */
note_add((FAR const uint8_t *)&note, sizeof(struct note_csection_s)); note_add((FAR const uint8_t *)&note, sizeof(struct note_csection_s));
@ -450,7 +448,7 @@ ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen)
/* Get the index to the tail of the circular buffer */ /* Get the index to the tail of the circular buffer */
tail = g_note_info.ni_tail; tail = g_note_info.ni_tail;
DEBUGASSERT(tail < CONFIG_SCHED_NOTE_BUFSIZE); DEBUGASSERT(tail < CONFIG_SCHED_NOTE_BUFSIZE);
/* Get the length of the note at the tail index */ /* Get the length of the note at the tail index */
@ -467,7 +465,7 @@ ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen)
note_remove(); note_remove();
/* and return and error */ /* and return an error */
notelen = -EFBIG; notelen = -EFBIG;
goto errout_with_csection; goto errout_with_csection;