diff --git a/ChangeLog b/ChangeLog index 86444d10c24..3f3c141f51c 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11562,4 +11562,7 @@ * sched/tls and include/nuttx/tls.h: Basic definitions needed to support thread local storage (TLS). Not used anywhere yet (and may not be used in the near future either) (2016-03-10). + * sched/sched_note.c and include/nuttx/sched_note.c: Add a configuration + option to buffer RTOS instrumentation data in an in-memory buffer + (2016-03-17). diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index ac5f9b799a2..b4f3d055fa4 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -843,48 +843,6 @@ void sched_suspend_scheduler(FAR struct tcb_s *tcb); # define sched_suspend_scheduler(tcb) #endif -/******************************************************************************** - * Name: sched_note_* - * - * Description: - * If instrumentation of the scheduler is enabled, then some outboard logic - * must provide the following interfaces. These interfaces are not availalble - * to application code. - * - * Input Parameters: - * tcb - The TCB of the thread. - * - * Returned Value: - * None - * - ********************************************************************************/ - -#ifdef CONFIG_SCHED_INSTRUMENTATION - -void sched_note_start(FAR struct tcb_s *tcb); -void sched_note_stop(FAR struct tcb_s *tcb); -void sched_note_switch(FAR struct tcb_s *fromtcb, FAR struct tcb_s *totcb); - -#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION -void sched_note_premption(FAR struct tcb_s *tcb, bool locked); -#else -# define sched_note_premption(t,l) -#endif - -#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION -void sched_note_csection(FAR struct tcb_s *tcb, bool enter); -#else -# define sched_note_csection(t,e) -#endif - -#else -# define sched_note_start(t) -# define sched_note_stop(t) -# define sched_note_switch(t1, t2) -# define sched_note_premption(t,l) -# define sched_note_csection(t,e) -#endif /* CONFIG_SCHED_INSTRUMENTATION */ - #undef EXTERN #if defined(__cplusplus) } diff --git a/include/nuttx/sched_note.h b/include/nuttx/sched_note.h new file mode 100644 index 00000000000..dd7ca875a05 --- /dev/null +++ b/include/nuttx/sched_note.h @@ -0,0 +1,219 @@ +/**************************************************************************** + * include/nuttx/sched_note.h + * + * Copyright (C) 2016 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SCHED_NOTE_H +#define __INCLUDE_NUTTX_SCHED_NOTE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#ifdef CONFIG_SCHED_INSTRUMENTATION + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef CONFIG_SCHED_INSTRUMENTATION_BUFFER + +/* This type identifies a note structure */ + +enum note_type_e +{ + NOTE_START = 0, + NOTE_STOP, + NOTE_SWITCH +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION + , + NOTE_PREEMPT_LOCK, + NOTE_PREEMPT_UNLOCK +#endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION + , + NOTE_CSECTION_ENTER, + NOTE_CSECTION_LEAVE +#endif +}; + +/* This structure provides the common header of each note */ + +struct note_common_s +{ + uint8_t nc_length; /* Length of the note */ + uint8_t nc_type; /* See enum note_type_e */ + uint8_t nc_systime[4]; /* Time when note buffered */ +}; + +/* This is the specific form of the NOTE_START note */ + +struct note_start_s +{ + uint8_t nst_length; /* Length of the note */ + uint8_t nst_type; /* Must be NOTE_START */ + uint8_t nst_systime[4]; /* Time when note buffered */ + uint8_t nst_pid[2]; /* ID of the new thread/task */ +#if CONFIG_TASK_NAME_SIZE > 0 + char nst_name[1]; /* Start of the name of the thread/task */ +#endif +}; + +/* This is the specific form of the NOTE_STOP note */ + +struct note_stop_s +{ + uint8_t nsp_length; /* Length of the note */ + uint8_t nsp_type; /* Must be NOTE_STOP */ + uint8_t nsp_systime[4]; /* Time when note buffered */ + uint8_t nsp_pid[2]; /* ID of the thread/task that stopped */ +}; + +/* This is the specific form of the NOTE_SWITCH note */ + +struct note_switch_s +{ + uint8_t nsw_length; /* Length of the note */ + uint8_t nsw_type; /* Must be NOTE_SWITCH */ + uint8_t nsw_systime[4]; /* Time when note buffered */ + uint8_t nsw_pidout[2]; /* ID of the thread/task that was blocked */ + uint8_t nsw_pidin[2]; /* ID of the thread/task that was started */ +}; + +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION +/* This is the specific form of the NOTE_PREEMPT_LOCK/UNLOCK note */ + +struct note_preempt_s +{ + uint8_t npr_length; /* Length of the note */ + uint8_t npr_type; /* Must be NOTE_PREEMPT_LOCK or _UNLOCK */ + uint8_t npr_systime[4]; /* Time when note buffered */ + uint8_t npr_pid[2]; /* ID of the thread/task that change pre-emption */ + uint8_t npr_count[2]; /* Count of nested locks */ +}; +#endif /* CONFIG_SCHED_INSTRUMENTATION_PREEMPTION */ + +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION +/* This is the specific form of the NOTE_CSECTION_ENTER/LEAVE note */ + +struct note_csection_s +{ + uint8_t ncs_length; /* Length of the note */ + uint8_t ncs_type; /* Must be NOTE_CSECTION_ENTER or _LEAVE */ + uint8_t ncs_systime[4]; /* Time when note buffered */ + uint8_t ncs_pid[2]; /* ID of the thread/task that changed critical section */ +#ifdef CONFIG_SMP + uint8_t ncs_count[2]; /* Count of nested csections */ +#endif +}; +#endif /* CONFIG_SCHED_INSTRUMENTATION_CSECTION */ +#endif /* CONFIG_SCHED_INSTRUMENTATION_BUFFER */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/******************************************************************************** + * Name: sched_note_* + * + * Description: + * If instrumentation of the scheduler is enabled, then some outboard logic + * must provide the following interfaces. These interfaces are not availalble + * to application code. + * + * NOTE: if CONFIG_SCHED_INSTRUMENTATION_BUFFER, then these interfaces are + * *not* available to the platform-specific logic. Rather, they provided by + * the note buffering logic. See sched_note_get() below. + * + * Input Parameters: + * tcb - The TCB of the thread. + * + * Returned Value: + * None + * + ********************************************************************************/ + +void sched_note_start(FAR struct tcb_s *tcb); +void sched_note_stop(FAR struct tcb_s *tcb); +void sched_note_switch(FAR struct tcb_s *fromtcb, FAR struct tcb_s *totcb); + +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION +void sched_note_premption(FAR struct tcb_s *tcb, bool locked); +#endif + +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION +void sched_note_csection(FAR struct tcb_s *tcb, bool enter); +#endif + +/**************************************************************************** + * Name: sched_note_get + * + * Description: + * Remove the next note from the tail of the circular buffer. The note + * is also removed from the circular buffer to make room for futher notes. + * + * Input Parameters: + * buffer - Location to return the next note + * buflen - The length of the user provided buffer. + * + * Returned Value: + * None + * + * Assumptions: + * On success, the length of the return note is provided. A negated + * errno value is returned on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_INSTRUMENTATION_BUFFER +ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen); +#endif + +#else /* CONFIG_SCHED_INSTRUMENTATION */ + +# define sched_note_start(t) +# define sched_note_stop(t) +# define sched_note_switch(t1, t2) +# define sched_note_premption(t,l) +# define sched_note_csection(t,e) + +#endif /* CONFIG_SCHED_INSTRUMENTATION */ +#endif /* __INCLUDE_NUTTX_SCHED_NOTE_H */ diff --git a/sched/Kconfig b/sched/Kconfig index 66c9f024592..dc9d7d13d93 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -370,10 +370,10 @@ config SPORADIC_INSTRUMENTATION scheduler behavior. If enabled, then the board-specific logic must provide the following functions: - void arch_sporadic_start(FAR struct tcb_s *tcb); - void arch_sporadic_lowpriority(FAR struct tcb_s *tcb); - void arch_sporadic_suspend(FAR struct tcb_s *tcb); - void arch_sporadic_resume(FAR struct tcb_s *tcb); + void arch_sporadic_start(FAR struct tcb_s *tcb); + void arch_sporadic_lowpriority(FAR struct tcb_s *tcb); + void arch_sporadic_suspend(FAR struct tcb_s *tcb); + void arch_sporadic_resume(FAR struct tcb_s *tcb); endif # SCHED_SPORADIC @@ -605,7 +605,15 @@ config SCHED_INSTRUMENTATION void sched_note_stop(FAR struct tcb_s *tcb); void sched_note_switch(FAR struct tcb_s *pFromTcb, FAR struct tcb_s *pToTcb); + NOTE: These are internal OS interfaces and are called at at very + critical locations in the OS. There is very little that can be + done in these interfaces. For example, normal devices may not be + used; syslog output cannot be performed. + + An option is to use SCHED_INSTRUMENTATION_BUFFER below. + if SCHED_INSTRUMENTATION + config SCHED_INSTRUMENTATION_PREEMPTION bool "Preemption monitor hooks" default n @@ -626,6 +634,38 @@ config SCHED_INSTRUMENTATION_CSECTION void sched_note_csection(FAR struct tcb_s *tcb, bool state); +config SCHED_INSTRUMENTATION_BUFFER + bool "Buffer instrumentation data in memory" + default n + ---help--- + If this option is selected, then in-memory buffering logic is + enabled to capature scheduler instrumentation data. This has + the advantage that (1) the platform logic does not have to provide + the sched_note_* interaces described for the previous settings. + Instead, the buffering logic catches all of these. It encodes + timestamps the scheduler note and adds the note to an in-memory, + circular buffer. And (2) buffering the scheduler instrumentation + data (versus performing some output operation) minimizes the impact + of the instrumentation on the behavior of the system. + + If the in-memory buffer becomes full, then older notes are + overwritten by newer notes. The following interface is provided: + + ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen); + + Platform specific information must call this function and dispose + of it quickly so that overwriting of the tail of the circular buffer + does not occur. See include/nuttx/sched_note.h for additional + information. + +config SCHED_NOTE_BUFSIZE + int "Instrumentation buffer size" + default 2048 + depends on SCHED_INSTRUMENTATION_BUFFER + ---help--- + The size of the in-memory, circular instrumentation buffer (in + bytes). + endif # SCHED_INSTRUMENTATION endmenu # Performance Monitoring diff --git a/sched/init/os_smpstart.c b/sched/init/os_smpstart.c index 5c43b9befff..f613344b5f1 100644 --- a/sched/init/os_smpstart.c +++ b/sched/init/os_smpstart.c @@ -96,10 +96,20 @@ static const char g_idlename[] = "CPUn Idle" void os_idle_trampoline(void) { +#ifdef CONFIG_SCHED_INSTRUMENTATION + FAR struct tcb_s *tcb = this_task(); +#endif + /* Perform architecture-specific initialization for this CPU */ up_cpu_initialize(); +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Announce that the IDLE task has started */ + + sched_note_start(tcb); +#endif + /* Then transfer control to the IDLE task */ (void)os_idle_task(0, NULL); diff --git a/sched/init/os_start.c b/sched/init/os_start.c index 1e0a90b916f..a8456c008a1 100644 --- a/sched/init/os_start.c +++ b/sched/init/os_start.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include "sched/sched.h" @@ -708,8 +709,13 @@ void os_start(void) lib_initialize(); /* IDLE Group Initialization **********************************************/ + /* Announce that the CPU0 IDLE task has started */ + + sched_note_start(&g_idletcb[0].cmn); #ifdef CONFIG_SMP + /* Initialize the IDLE group for the IDLE task of each CPU */ + for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++) #endif { diff --git a/sched/irq/irq_csection.c b/sched/irq/irq_csection.c index e2bb1d995fc..414238045e2 100644 --- a/sched/irq/irq_csection.c +++ b/sched/irq/irq_csection.c @@ -42,6 +42,7 @@ #include #include +#include #include #include "sched/sched.h" diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index aa806b95aa4..74ffabe1f35 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -82,6 +82,10 @@ else CSRCS += sched_processtimer.c endif +ifeq ($(CONFIG_SCHED_INSTRUMENTATION_BUFFER),y) +CSRCS += sched_note.c +endif + # Include sched build support DEPPATH += --dep-path sched diff --git a/sched/sched/sched_addreadytorun.c b/sched/sched/sched_addreadytorun.c index a105e4f5455..987c91d4865 100644 --- a/sched/sched/sched_addreadytorun.c +++ b/sched/sched/sched_addreadytorun.c @@ -43,6 +43,8 @@ #include #include +#include + #include "irq/irq.h" #include "sched/sched.h" diff --git a/sched/sched/sched_lock.c b/sched/sched/sched_lock.c index 83ba4b8635d..529ba4a07f0 100644 --- a/sched/sched/sched_lock.c +++ b/sched/sched/sched_lock.c @@ -44,6 +44,8 @@ #include #include +#include + #include "sched/sched.h" /**************************************************************************** diff --git a/sched/sched/sched_mergepending.c b/sched/sched/sched_mergepending.c index 48f6d58310f..e314e31d69c 100644 --- a/sched/sched/sched_mergepending.c +++ b/sched/sched/sched_mergepending.c @@ -44,6 +44,8 @@ #include #include +#include + #include "sched/sched.h" /**************************************************************************** diff --git a/sched/sched/sched_note.c b/sched/sched/sched_note.c new file mode 100644 index 00000000000..3838bef8cda --- /dev/null +++ b/sched/sched/sched_note.c @@ -0,0 +1,491 @@ +/**************************************************************************** + * sched/sched/sched_note.c + * + * Copyright (C) 2016 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 +#include +#include + +#include +#include +#include + +#ifdef CONFIG_SCHED_INSTRUMENTATION_BUFFER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct note_info_s +{ + unsigned int ni_head; + unsigned int ni_tail; + uint8_t ni_buffer[CONFIG_SCHED_NOTE_BUFSIZE]; +}; + +struct note_startalloc_s +{ + uint8_t nsa_length; + uint8_t nsa_type; + uint8_t nsa_systime[4]; + uint8_t nsa_pid[2]; +#if CONFIG_TASK_NAME_SIZE > 0 + char nsa_name[CONFIG_TASK_NAME_SIZE + 1]; +#endif +}; + +#if CONFIG_TASK_NAME_SIZE > 0 +# define SIZEOF_NOTE_START(n) (sizeof(struct note_start_s) + (n) - 1) +#else +# define SIZEOF_NOTE_START(n) (sizeof(struct note_start_s)) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct note_info_s g_note_info; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: note_next + * + * Description: + * Return the circular buffer index at offset from the specified index + * value, handling wraparound + * + * Input Parameters: + * ndx - Old circular buffer index + * + * Returned Value: + * New circular buffer index + * + ****************************************************************************/ + +static inline unsigned int note_next(unsigned int ndx, unsigned int offset) +{ + ndx += offset; + if (ndx >= CONFIG_SCHED_NOTE_BUFSIZE) + { + ndx -= CONFIG_SCHED_NOTE_BUFSIZE; + } + + return ndx; +} + +/**************************************************************************** + * Name: note_systime + * + * Description: + * Save the current system time in the note structure as a 32-bit value. + * + * Input Parameters: + * note - The note structure to use + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void note_systime(FAR struct note_common_s *note) +{ + uint32_t systime = (uint32_t)clock_systimer(); + + /* Save the LS 32-bits of the system timer in little endian order */ + + note->nc_systime[0] = (uint8_t)( systime & 0xff); + note->nc_systime[1] = (uint8_t)((systime >> 8) & 0xff); + note->nc_systime[2] = (uint8_t)((systime >> 16) & 0xff); + note->nc_systime[3] = (uint8_t)((systime >> 24) & 0xff); +} + +/**************************************************************************** + * Name: note_length + * + * Description: + * Length of data currently in circular buffer. + * + * Input Parameters: + * None + * + * Returned Value: + * Length of data currently in circular buffer. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG +static unsigned int note_length(void) +{ + unsigned int head = g_note_info.ni_head; + unsigned int tail = g_note_info.ni_tail; + + if (tail > head) + { + head += CONFIG_SCHED_NOTE_BUFSIZE; + } + + return head - tail; +} +#endif + +/**************************************************************************** + * Name: note_remove + * + * Description: + * Remove the variable length note from the tail of the circular buffer + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * We are within a critical section. + * + ****************************************************************************/ + +static void note_remove(void) +{ + FAR struct note_common_s *note; + unsigned int tail; + unsigned int length; + + /* Get the tail index of the circular buffer */ + + tail = g_note_info.ni_tail; + DEBUGASSERT(tail < CONFIG_SCHED_NOTE_BUFSIZE); + + /* Get the length of the note at the tail index */ + + note = (FAR struct note_common_s *)&g_note_info.ni_buffer[tail]; + length = note->nc_length; + DEBUGASSERT(length <= note_length()); + + /* Increment the tail index to remove the entire note from the circular + * buffer. + */ + + g_note_info.ni_tail = note_next(tail, length); +} + +/**************************************************************************** + * Name: note_add + * + * Description: + * Add the variable length note to the head of the circular buffer + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * We are within a critical section. + * + ****************************************************************************/ + +static void note_add(FAR const uint8_t *note, uint8_t notelen) +{ + unsigned int head; + unsigned int next; + + /* Get the index to the head of the circular buffer */ + + DEBUGASSERT(note != NULL && notelen < CONFIG_SCHED_NOTE_BUFSIZE); + head = g_note_info.ni_head; + + /* Loop until all bytes have been transferred to the circular buffer */ + + while (notelen > 0) + { + /* Get the next head index. Would it collide with the current tail + * index? + */ + + next = note_next(head, 1); + if (next == g_note_info.ni_tail) + { + /* Yes, then remove the note at the tail index */ + + note_remove(); + } + + /* Save the next byte at the head index */ + + g_note_info.ni_buffer[head] = *note++; + + head = next; + notelen--; + } + + g_note_info.ni_head = head; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sched_note_* + * + * Description: + * These are the hooks into the scheduling instrumentation logic. Each + * simply formats the note associated with the schedule event and adds + * that note to the circular buffer. + * + * Input Parameters: + * tcb - The TCB of the thread. + * + * Returned Value: + * None + * + * Assumptions: + * We are within a critical section. + * + ****************************************************************************/ + +void sched_note_start(FAR struct tcb_s *tcb) +{ + struct note_startalloc_s note; + unsigned int length; +#if CONFIG_TASK_NAME_SIZE > 0 + int namelen; +#endif + + /* Copy the task name (if possible) and get the length of the note */ + +#if CONFIG_TASK_NAME_SIZE > 0 + namelen = strlen(tcb->name); + + DEBUGASSERT(namelen <= CONFIG_TASK_NAME_SIZE); + strncpy(note.nsa_name, tcb->name, CONFIG_TASK_NAME_SIZE + 1); + + length = SIZEOF_NOTE_START(namelen + 1); +#else + length = SIZEOF_NOTE_START(0) +#endif + + /* Finish formatting the note */ + + note.nsa_length = length; + note.nsa_type = NOTE_START; + note.nsa_pid[0] = (uint8_t)(tcb->pid & 0xff); + note.nsa_pid[1] = (uint8_t)((tcb->pid >> 8) & 0xff); + + note_systime((FAR struct note_common_s *)¬e); + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, length); +} + +void sched_note_stop(FAR struct tcb_s *tcb) +{ + struct note_stop_s note; + + /* Format the note */ + + note.nsp_length = sizeof(struct note_stop_s); + note.nsp_type = NOTE_STOP; + note.nsp_pid[0] = (uint8_t)(tcb->pid & 0xff); + note.nsp_pid[1] = (uint8_t)((tcb->pid >> 8) & 0xff); + + note_systime((FAR struct note_common_s *)¬e); + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_stop_s)); +} + +void sched_note_switch(FAR struct tcb_s *fromtcb, FAR struct tcb_s *totcb) +{ + struct note_switch_s note; + + /* Format the note */ + + note.nsw_length = sizeof(struct note_switch_s); + note.nsw_type = NOTE_SWITCH; + note.nsw_pidout[0] = (uint8_t)(fromtcb->pid & 0xff); + note.nsw_pidout[1] = (uint8_t)((fromtcb->pid >> 8) & 0xff); + note.nsw_pidin[0] = (uint8_t)(totcb->pid & 0xff); + note.nsw_pidin[1] = (uint8_t)((totcb->pid >> 8) & 0xff); + + note_systime((FAR struct note_common_s *)¬e); + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_switch_s)); +} + +#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION +void sched_note_premption(FAR struct tcb_s *tcb, bool locked) +{ + struct note_preempt_s note; + + /* Format the note */ + + note.npr_length = sizeof(struct note_preempt_s); + note.npr_type = locked ? NOTE_PREEMPT_LOCK : NOTE_PREEMPT_UNLOCK; + note.npr_pid[0] = (uint8_t)(tcb->pid & 0xff); + note.npr_pid[1] = (uint8_t)((tcb->pid >> 8) & 0xff); + note.npr_count[0] = (uint8_t)(tcb->lockcount & 0xff); + note.npr_count[1] = (uint8_t)((tcb->lockcount >> 8) & 0xff); + + note_systime((FAR struct note_common_s *)¬e); + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_preempt_s)); +} +#endif + +#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION +void sched_note_csection(FAR struct tcb_s *tcb, bool enter) +{ + struct note_preempt_s note; + + /* Format the note */ + + note.ncs_length = sizeof(struct note_preempt_s); + note.ncs_type = enter ? NOTE_CSECTION_ENTER : NOTE_CSECTION_LEAVE; + note.ncs_pid[0] = (uint8_t)(tcb->pid & 0xff); + note.ncs_pid[1] = (uint8_t)((tcb->pid >> 8) & 0xff); +#ifdef CONFIG_SMP + note.ncs_count[0] = (uint8_t)(tcb->irqcount & 0xff); + note.ncs_count[1] = (uint8_t)((tcb->irqcount >> 8) & 0xff); +#endif + + note_systime((FAR struct note_common_s *)¬e); + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_preempt_s)); +} +#endif + +/**************************************************************************** + * Name: sched_note_get + * + * Description: + * Remove the next note from the tail of the circular buffer. The note + * is also removed from the circular buffer to make room for futher notes. + * + * Input Parameters: + * buffer - Location to return the next note + * buflen - The length of the user provided buffer. + * + * Returned Value: + * None + * + * Assumptions: + * On success, the length of the return note is provided. A negated + * errno value is returned on failure. + * + ****************************************************************************/ + +ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen) +{ + FAR struct note_common_s *note; + irqstate_t flags; + unsigned int remaining; + unsigned int tail; + ssize_t notelen; + + DEBUGASSERT(buffer != NULL); + flags = enter_critical_section(); + + /* Get the index to the tail of the circular buffer */ + + tail = g_note_info.ni_tail; + DEBUGASSERT(tail < CONFIG_SCHED_NOTE_BUFSIZE); + + /* Get the length of the note at the tail index */ + + note = (FAR struct note_common_s *)&g_note_info.ni_buffer[tail]; + notelen = note->nc_length; + DEBUGASSERT(notelen <= note_length()); + + /* Is the user buffer large enough to hold the note? */ + + if (buflen < notelen) + { + /* Remove the large note so that we do not get constipated. */ + + note_remove(); + + /* and return and error */ + + notelen = -EFBIG; + goto errout_with_csection; + } + + /* Loop until the note has been transferred to the user buffer */ + + remaining = (unsigned int)notelen; + while (remaining > 0) + { + /* Copy the next byte at the tail index */ + + *buffer++ = g_note_info.ni_buffer[tail]; + + /* Adjust indices and counts */ + + tail = note_next(tail, 1); + remaining--; + } + + g_note_info.ni_tail = tail; + +errout_with_csection: + leave_critical_section(flags); + return notelen; +} + +#endif /* CONFIG_SCHED_INSTRUMENTATION_BUFFER */ diff --git a/sched/sched/sched_removereadytorun.c b/sched/sched/sched_removereadytorun.c index 19e6cbed1f6..84d3b25c111 100644 --- a/sched/sched/sched_removereadytorun.c +++ b/sched/sched/sched_removereadytorun.c @@ -43,6 +43,8 @@ #include #include +#include + #include "irq/irq.h" #include "sched/sched.h" diff --git a/sched/sched/sched_unlock.c b/sched/sched/sched_unlock.c index e08fb4482af..9a6ff5a9248 100644 --- a/sched/sched/sched_unlock.c +++ b/sched/sched/sched_unlock.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "sched/sched.h" diff --git a/sched/task/task_activate.c b/sched/task/task_activate.c index dfe7f5192a7..47791c7a259 100644 --- a/sched/task/task_activate.c +++ b/sched/task/task_activate.c @@ -44,6 +44,7 @@ #include #include +#include /**************************************************************************** * Public Functions diff --git a/sched/task/task_terminate.c b/sched/task/task_terminate.c index 52e4e4c8c0e..f9b115f8e40 100644 --- a/sched/task/task_terminate.c +++ b/sched/task/task_terminate.c @@ -46,6 +46,7 @@ #include #include +#include #include "sched/sched.h" #ifndef CONFIG_DISABLE_SIGNALS