diff --git a/boards/arm/cxd56xx/spresense/configs/smp/defconfig b/boards/arm/cxd56xx/spresense/configs/smp/defconfig index 5c64e24e76..051902d0a2 100644 --- a/boards/arm/cxd56xx/spresense/configs/smp/defconfig +++ b/boards/arm/cxd56xx/spresense/configs/smp/defconfig @@ -26,6 +26,7 @@ CONFIG_CXD56_SPI5=y CONFIG_CXD56_SPI=y CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVER_NOTE=y CONFIG_EXAMPLES_HELLO=y CONFIG_FS_PROCFS=y CONFIG_FS_PROCFS_REGISTER=y @@ -45,7 +46,6 @@ CONFIG_RR_INTERVAL=200 CONFIG_RTC=y CONFIG_RTC_DRIVER=y CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SDCLONE_DISABLE=y CONFIG_SMP=y CONFIG_SMP_NCPUS=2 diff --git a/boards/arm/imx6/sabre-6quad/configs/smp/defconfig b/boards/arm/imx6/sabre-6quad/configs/smp/defconfig index 402f4df459..4f60ebf88a 100644 --- a/boards/arm/imx6/sabre-6quad/configs/smp/defconfig +++ b/boards/arm/imx6/sabre-6quad/configs/smp/defconfig @@ -23,6 +23,7 @@ CONFIG_BUILTIN=y CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y +CONFIG_DRIVER_NOTE=y CONFIG_EXAMPLES_HELLO=y CONFIG_FS_PROCFS=y CONFIG_HAVE_CXX=y @@ -49,7 +50,6 @@ CONFIG_RR_INTERVAL=200 CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SMP=y CONFIG_SPINLOCK_IRQ=y CONFIG_START_MONTH=3 diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/bt/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/bt/defconfig index 7aa6eda5cf..b33a866d3f 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/bt/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/bt/defconfig @@ -36,6 +36,7 @@ CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y CONFIG_DRIVERS_AUDIO=y +CONFIG_DRIVER_NOTE=y CONFIG_DVFS=y CONFIG_EXAMPLES_HELLO=y CONFIG_EXAMPLES_I2SLOOP=y @@ -146,7 +147,6 @@ CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_INSTRUMENTATION_PREEMPTION=y CONFIG_SCHED_LPWORK=y CONFIG_SCHED_LPWORKPRIORITY=60 diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/elf/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/elf/defconfig index 128a5802c4..3e61fd7fbf 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/elf/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/elf/defconfig @@ -22,6 +22,7 @@ CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DRIVER_NOTE=y CONFIG_ELF=y CONFIG_EXAMPLES_ELF=y CONFIG_FS_PROCFS=y @@ -54,7 +55,6 @@ CONFIG_SCHED_ATEXIT=y CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_ONEXIT=y CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_STARTHOOK=y diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/ipl2/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/ipl2/defconfig index b48c9f03a3..5b6604db30 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/ipl2/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/ipl2/defconfig @@ -21,6 +21,7 @@ CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_MQUEUE=y CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DRIVER_NOTE=y CONFIG_FAT_LCNAMES=y CONFIG_FAT_LFN=y CONFIG_FS_FAT=y @@ -54,7 +55,6 @@ CONFIG_SCHED_ATEXIT=y CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_ONEXIT=y CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_STARTHOOK=y diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/knsh/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/knsh/defconfig index bfeb8c8325..767ea4ef74 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/knsh/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/knsh/defconfig @@ -29,6 +29,7 @@ CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DRIVER_NOTE=y CONFIG_FS_PROCFS=y CONFIG_HRT_TIMER=y CONFIG_I2C=y @@ -99,7 +100,6 @@ CONFIG_SCHED_ATEXIT=y CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_ONEXIT=y CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_STARTHOOK=y diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig index 9a09a07126..84a0087625 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig @@ -37,6 +37,7 @@ CONFIG_DEV_URANDOM=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y CONFIG_DRIVERS_AUDIO=y +CONFIG_DRIVER_NOTE=y CONFIG_DVFS=y CONFIG_ELF=y CONFIG_EXAMPLES_HELLO=m @@ -154,7 +155,6 @@ CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_INSTRUMENTATION_PREEMPTION=y CONFIG_SCHED_LPWORK=y CONFIG_SCHED_LPWORKPRIORITY=60 diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/nsh/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/nsh/defconfig index 92e108e134..80e15aed3e 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/nsh/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/nsh/defconfig @@ -28,6 +28,7 @@ CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DRIVER_NOTE=y CONFIG_EXAMPLES_ADC=y CONFIG_EXAMPLES_ADC_GROUPSIZE=6 CONFIG_EXAMPLES_ADC_SWTRIG=y @@ -104,7 +105,6 @@ CONFIG_SCHED_ATEXIT=y CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_ONEXIT=y CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_STARTHOOK=y diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/posix_spawn/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/posix_spawn/defconfig index 4825e612f1..69a464ec24 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/posix_spawn/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/posix_spawn/defconfig @@ -21,6 +21,7 @@ CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DRIVER_NOTE=y CONFIG_ELF=y CONFIG_EXAMPLES_POSIXSPAWN=y CONFIG_FS_PROCFS=y @@ -53,7 +54,6 @@ CONFIG_SCHED_ATEXIT=y CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_ONEXIT=y CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_STARTHOOK=y diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig index 4887b02b43..8a0cc440e3 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig @@ -35,6 +35,7 @@ CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y CONFIG_DRIVERS_AUDIO=y +CONFIG_DRIVER_NOTE=y CONFIG_DVFS=y CONFIG_ELF=y CONFIG_EXAMPLES_HELLO=m @@ -154,7 +155,6 @@ CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_INSTRUMENTATION_PREEMPTION=y CONFIG_SCHED_LPWORK=y CONFIG_SCHED_LPWORKPRIORITY=60 diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/usb/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/usb/defconfig index c1a8e78aea..2d636e78dd 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/usb/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/usb/defconfig @@ -27,6 +27,7 @@ CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DRIVER_NOTE=y CONFIG_ELF=y CONFIG_ELF_BUFFERSIZE=512 CONFIG_EXAMPLES_ADC=y @@ -107,7 +108,6 @@ CONFIG_SCHED_ATEXIT=y CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_ONEXIT=y CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_STARTHOOK=y diff --git a/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig b/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig index df3b8c9455..024d65f733 100644 --- a/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig +++ b/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig @@ -31,6 +31,7 @@ CONFIG_C99_BOOL8=y CONFIG_CDCACM=y CONFIG_CDCACM_EPINTIN_HSSIZE=512 CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVER_NOTE=y CONFIG_FAT_DMAMEMORY=y CONFIG_FAT_LCNAMES=y CONFIG_FAT_LFN=y @@ -69,7 +70,6 @@ CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_HPWORKSTACKSIZE=1800 CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SCHED_LPWORK=y CONFIG_SCHED_LPWORKSTACKSIZE=1800 CONFIG_SCHED_NOTE_BUFSIZE=512 diff --git a/boards/risc-v/k210/maix-bit/configs/smp/defconfig b/boards/risc-v/k210/maix-bit/configs/smp/defconfig index 3eeba6b995..249ccb6abe 100644 --- a/boards/risc-v/k210/maix-bit/configs/smp/defconfig +++ b/boards/risc-v/k210/maix-bit/configs/smp/defconfig @@ -21,6 +21,7 @@ CONFIG_BUILTIN=y CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_ZERO=y +CONFIG_DRIVER_NOTE=y CONFIG_EXAMPLES_HELLO=y CONFIG_FS_PROCFS=y CONFIG_FS_PROCFS_REGISTER=y @@ -48,7 +49,6 @@ CONFIG_RAW_BINARY=y CONFIG_READLINE_CMD_HISTORY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SMP=y CONFIG_SMP_NCPUS=2 CONFIG_SPINLOCK_IRQ=y diff --git a/boards/xtensa/esp32/esp32-core/configs/smp/defconfig b/boards/xtensa/esp32/esp32-core/configs/smp/defconfig index 5182655b55..ffcb2d398f 100644 --- a/boards/xtensa/esp32/esp32-core/configs/smp/defconfig +++ b/boards/xtensa/esp32/esp32-core/configs/smp/defconfig @@ -20,6 +20,7 @@ CONFIG_BUILTIN=y CONFIG_DEBUG_FEATURES=y CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVER_NOTE=y CONFIG_ESP32_UART0=y CONFIG_EXAMPLES_HELLO=y CONFIG_EXPERIMENTAL=y @@ -44,7 +45,6 @@ CONFIG_RAW_BINARY=y CONFIG_READLINE_CMD_HISTORY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_INSTRUMENTATION=y -CONFIG_SCHED_INSTRUMENTATION_BUFFER=y CONFIG_SDCLONE_DISABLE=y CONFIG_SMP=y CONFIG_SMP_IDLETHREAD_STACKSIZE=3072 diff --git a/drivers/note/Kconfig b/drivers/note/Kconfig index 6865682faf..32060812f1 100644 --- a/drivers/note/Kconfig +++ b/drivers/note/Kconfig @@ -8,10 +8,37 @@ menu "Note Driver Support" config DRIVER_NOTE bool "Scheduler instrumentation driver" default n - depends on SCHED_INSTRUMENTATION_BUFFER && SCHED_NOTE_GET + depends on !SCHED_INSTRUMENTATION_CSECTION && (!SCHED_INSTRUMENTATION_SPINLOCK || !SMP) ---help--- - Enable building a serial driver that can be used by an application + If this option is selected, then in-memory buffering logic is + enabled to capture scheduler instrumentation data. This has + the advantage that (1) the platform logic does not have to provide + the sched_note_* interfaces 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. + + A character driver is provided which can be used by an application to read data from the in-memory, scheduler instrumentation "note" buffer. + NOTE: This option is not available if critical sections are being + monitor (nor if spinlocks are being monitored in SMP configuration) + because there would be a logical error in the design in those cases. + That error is that these interfaces call enter_ and leave_critical_section + (and which us spinlocks in SMP mode). That means that each call to + sched_note_get() causes several additional entries to be added from + the note buffer in order to remove one entry. + +config SCHED_NOTE_BUFSIZE + int "Instrumentation buffer size" + depends on DRIVER_NOTE + default 2048 + ---help--- + The size of the in-memory, circular instrumentation buffer (in + bytes). + endmenu diff --git a/drivers/note/note_driver.c b/drivers/note/note_driver.c index afd37c2881..9207609262 100644 --- a/drivers/note/note_driver.c +++ b/drivers/note/note_driver.c @@ -44,11 +44,20 @@ #include #include +#include #include #include -#if defined(CONFIG_SCHED_INSTRUMENTATION_BUFFER) && \ - defined(CONFIG_DRIVER_NOTE) +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct note_info_s +{ + volatile unsigned int ni_head; + volatile unsigned int ni_tail; + uint8_t ni_buffer[CONFIG_SCHED_NOTE_BUFSIZE]; +}; /**************************************************************************** * Private Function Prototypes @@ -75,10 +84,246 @@ static const struct file_operations note_fops = #endif }; +static struct note_info_s g_note_info; + +#ifdef CONFIG_SMP +static volatile spinlock_t g_note_lock; +#endif + /**************************************************************************** * 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_length + * + * Description: + * Length of data currently in circular buffer. + * + * Input Parameters: + * None + * + * Returned Value: + * Length of data currently in circular buffer. + * + ****************************************************************************/ + +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; +} + +/**************************************************************************** + * 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: 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 further notes. + * + * Input Parameters: + * buffer - Location to return the next note + * buflen - The length of the user provided buffer. + * + * Returned Value: + * On success, the positive, non-zero length of the return note is + * provided. Zero is returned only if the circular buffer is empty. A + * negated errno value is returned in the event of any failure. + * + ****************************************************************************/ + +static 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; + size_t circlen; + + DEBUGASSERT(buffer != NULL); + flags = enter_critical_section(); + + /* Verify that the circular buffer is not empty */ + + circlen = note_length(); + if (circlen <= 0) + { + notelen = 0; + goto errout_with_csection; + } + + /* 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 <= circlen); + + /* 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 an 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; +} + +/**************************************************************************** + * Name: sched_note_size + * + * Description: + * Return the size of the next note at the tail of the circular buffer. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero is returned if the circular buffer is empty. Otherwise, the size + * of the next note is returned. + * + ****************************************************************************/ + +static ssize_t sched_note_size(void) +{ + FAR struct note_common_s *note; + irqstate_t flags; + unsigned int tail; + ssize_t notelen; + size_t circlen; + + flags = enter_critical_section(); + + /* Verify that the circular buffer is not empty */ + + circlen = note_length(); + if (circlen <= 0) + { + notelen = 0; + goto errout_with_csection; + } + + /* 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 <= circlen); + +errout_with_csection: + leave_critical_section(flags); + return notelen; +} + /**************************************************************************** * Name: note_read ****************************************************************************/ @@ -143,6 +388,71 @@ static ssize_t note_read(FAR struct file *filep, FAR char *buffer, * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: note_add + * + * Description: + * Add the variable length note to the transport layer + * + * Input Parameters: + * note - The note buffer + * notelen - The buffer length + * + * Returned Value: + * None + * + * Assumptions: + * We are within a critical section. + * + ****************************************************************************/ + +void note_add(FAR const uint8_t *note, uint8_t notelen) +{ + unsigned int head; + unsigned int next; + +#ifdef CONFIG_SMP + irqstate_t flags = up_irq_save(); + spin_lock_wo_note(&g_note_lock); +#endif + + /* 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; + +#ifdef CONFIG_SMP + spin_unlock_wo_note(&g_note_lock); + up_irq_restore(flags); +#endif +} + /**************************************************************************** * Name: note_register * @@ -163,5 +473,3 @@ int note_register(void) { return register_driver("/dev/note", ¬e_fops, 0666, NULL); } - -#endif /* CONFIG_SCHED_INSTRUMENTATION_BUFFER && CONFIG_DRIVER_NOTE */ diff --git a/include/nuttx/sched_note.h b/include/nuttx/sched_note.h index 1052a08aca..68c994682c 100644 --- a/include/nuttx/sched_note.h +++ b/include/nuttx/sched_note.h @@ -48,16 +48,10 @@ # define CONFIG_SCHED_INSTRUMENTATION_CPUSET 0xffff #endif -#ifndef CONFIG_SCHED_NOTE_BUFSIZE -# define CONFIG_SCHED_NOTE_BUFSIZE 2048 -#endif - /**************************************************************************** * Public Types ****************************************************************************/ -#ifdef CONFIG_SCHED_INSTRUMENTATION_BUFFER - /* This type identifies a note structure */ enum note_type_e @@ -259,7 +253,6 @@ struct note_irqhandler_s uint8_t nih_irq; /* IRQ number */ }; #endif /* CONFIG_SCHED_INSTRUMENTATION_IRQHANDLER */ -#endif /* CONFIG_SCHED_INSTRUMENTATION_BUFFER */ /**************************************************************************** * Public Function Prototypes @@ -273,10 +266,6 @@ struct note_irqhandler_s * logic must provide the following interfaces. These interfaces are not * available 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. * @@ -349,47 +338,24 @@ void sched_note_irqhandler(int irq, FAR void *handler, bool enter); #endif /**************************************************************************** - * Name: sched_note_get + * Name: note_add * * 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 further notes. + * Add the variable length note to the transport layer * * Input Parameters: - * buffer - Location to return the next note - * buflen - The length of the user provided buffer. + * note - The note buffer + * notelen - The buffer length * * Returned Value: - * On success, the positive, non-zero length of the return note is - * provided. Zero is returned only if the circular buffer is empty. A - * negated errno value is returned in the event of any failure. + * None + * + * Assumptions: + * We are within a critical section. * ****************************************************************************/ -#if defined(CONFIG_SCHED_INSTRUMENTATION_BUFFER) && \ - defined(CONFIG_SCHED_NOTE_GET) -ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen); -#endif - -/**************************************************************************** - * Name: sched_note_size - * - * Description: - * Return the size of the next note at the tail of the circular buffer. - * - * Input Parameters: - * None. - * - * Returned Value: - * Zero is returned if the circular buffer is empty. Otherwise, the size - * of the next note is returned. - * - ****************************************************************************/ - -#if defined(CONFIG_SCHED_INSTRUMENTATION_BUFFER) && \ - defined(CONFIG_SCHED_NOTE_GET) -ssize_t sched_note_size(void); -#endif +void note_add(FAR const uint8_t *note, uint8_t notelen); #else /* CONFIG_SCHED_INSTRUMENTATION */ diff --git a/sched/Kconfig b/sched/Kconfig index c5fcc3c8bd..3e01b93a5c 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -914,8 +914,6 @@ config SCHED_INSTRUMENTATION 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_CPUSET @@ -977,59 +975,6 @@ config SCHED_INSTRUMENTATION_IRQHANDLER void sched_note_irqhandler(int irq, FAR void *handler, bool enter); -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 capture scheduler instrumentation data. This has - the advantage that (1) the platform logic does not have to provide - the sched_note_* interfaces 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. - -if SCHED_INSTRUMENTATION_BUFFER - -config SCHED_NOTE_BUFSIZE - int "Instrumentation buffer size" - default 2048 - ---help--- - The size of the in-memory, circular instrumentation buffer (in - bytes). - -config SCHED_NOTE_GET - bool "Callable interface to get instrumentation data" - default n - depends on !SCHED_INSTRUMENTATION_CSECTION && (!SCHED_INSTRUMENTATION_SPINLOCK || !SMP) - ---help--- - Add support for interfaces to get the size of the next note and also - to extract the next note from the instrumentation buffer: - - ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen); - ssize_t sched_note_size(void); - - NOTE: This option is not available if critical sections are being - monitor (nor if spinlocks are being monitored in SMP configuration) - because there would be a logical error in the design in those cases. - That error is that these interfaces call enter_ and leave_critical_section - (and which us spinlocks in SMP mode). That means that each call to - sched_note_get() causes several additional entries to be added from - the note buffer in order to remove one entry. - -endif # SCHED_INSTRUMENTATION_BUFFER endif # SCHED_INSTRUMENTATION endmenu # Performance Monitoring diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index 9825ac39d0..57546acdd0 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -89,7 +89,7 @@ CSRCS += sched_tasklistlock.c CSRCS += sched_thistask.c endif -ifeq ($(CONFIG_SCHED_INSTRUMENTATION_BUFFER),y) +ifeq ($(CONFIG_SCHED_INSTRUMENTATION),y) CSRCS += sched_note.c endif diff --git a/sched/sched/sched_note.c b/sched/sched/sched_note.c index e13a85b2e8..8b20d5b0eb 100644 --- a/sched/sched/sched_note.c +++ b/sched/sched/sched_note.c @@ -36,19 +36,10 @@ #include "sched/sched.h" -#ifdef CONFIG_SCHED_INSTRUMENTATION_BUFFER - /**************************************************************************** * Private Types ****************************************************************************/ -struct note_info_s -{ - volatile unsigned int ni_head; - volatile unsigned int ni_tail; - uint8_t ni_buffer[CONFIG_SCHED_NOTE_BUFSIZE]; -}; - struct note_startalloc_s { struct note_common_s nsa_cmn; /* Common note parameters */ @@ -63,52 +54,10 @@ struct note_startalloc_s # define SIZEOF_NOTE_START(n) (sizeof(struct note_start_s)) #endif -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void note_add(FAR const uint8_t *note, uint8_t notelen); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct note_info_s g_note_info; - -#ifdef CONFIG_SMP -static volatile spinlock_t g_note_lock; -#endif - /**************************************************************************** * 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_common * @@ -167,116 +116,12 @@ static void note_common(FAR struct tcb_s *tcb, ****************************************************************************/ #ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS -void note_spincommon(FAR struct tcb_s *tcb, - FAR volatile spinlock_t *spinlock, - int type) +static void note_spincommon(FAR struct tcb_s *tcb, + FAR volatile spinlock_t *spinlock, + int type) { struct note_spinlock_s note; - /* Format the note */ - - note_common(tcb, ¬e.nsp_cmn, sizeof(struct note_spinlock_s), type); - note.nsp_spinlock = (FAR void *)spinlock; - note.nsp_value = (uint8_t)*spinlock; - - /* Add the note to circular buffer */ - - note_add((FAR const uint8_t *)¬e, sizeof(struct note_spinlock_s)); -} -#endif - -/**************************************************************************** - * Name: note_length - * - * Description: - * Length of data currently in circular buffer. - * - * Input Parameters: - * None - * - * Returned Value: - * Length of data currently in circular buffer. - * - ****************************************************************************/ - -#if defined(CONFIG_SCHED_NOTE_GET) || defined(CONFIG_DEBUG_ASSERTIONS) -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; - #ifdef CONFIG_SMP /* Ignore notes that are not in the set of monitored CPUs */ @@ -288,47 +133,17 @@ static void note_add(FAR const uint8_t *note, uint8_t notelen) } #endif -#ifdef CONFIG_SMP - irqstate_t flags = up_irq_save(); - spin_lock_wo_note(&g_note_lock); -#endif + /* Format the note */ - /* Get the index to the head of the circular buffer */ + note_common(tcb, ¬e.nsp_cmn, sizeof(struct note_spinlock_s), type); + note.nsp_spinlock = (FAR void *)spinlock; + note.nsp_value = (uint8_t)*spinlock; - DEBUGASSERT(note != NULL && notelen < CONFIG_SCHED_NOTE_BUFSIZE); - head = g_note_info.ni_head; + /* Add the note to circular buffer */ - /* 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; - -#ifdef CONFIG_SMP - spin_unlock_wo_note(&g_note_lock); - up_irq_restore(flags); -#endif + note_add((FAR const uint8_t *)¬e, sizeof(struct note_spinlock_s)); } +#endif /**************************************************************************** * Public Functions @@ -361,6 +176,17 @@ void sched_note_start(FAR struct tcb_s *tcb) int namelen; #endif +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Copy the task name (if possible) and get the length of the note */ #if CONFIG_TASK_NAME_SIZE > 0 @@ -387,6 +213,17 @@ void sched_note_stop(FAR struct tcb_s *tcb) { struct note_stop_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.nsp_cmn, sizeof(struct note_stop_s), NOTE_STOP); @@ -400,6 +237,17 @@ void sched_note_suspend(FAR struct tcb_s *tcb) { struct note_suspend_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.nsu_cmn, sizeof(struct note_suspend_s), @@ -415,6 +263,17 @@ void sched_note_resume(FAR struct tcb_s *tcb) { struct note_resume_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.nre_cmn, sizeof(struct note_resume_s), NOTE_RESUME); @@ -429,6 +288,17 @@ void sched_note_cpu_start(FAR struct tcb_s *tcb, int cpu) { struct note_cpu_start_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.ncs_cmn, sizeof(struct note_cpu_start_s), @@ -444,6 +314,17 @@ void sched_note_cpu_started(FAR struct tcb_s *tcb) { struct note_cpu_started_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.ncs_cmn, sizeof(struct note_cpu_started_s), @@ -458,6 +339,17 @@ void sched_note_cpu_pause(FAR struct tcb_s *tcb, int cpu) { struct note_cpu_pause_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.ncp_cmn, sizeof(struct note_cpu_pause_s), @@ -473,6 +365,17 @@ void sched_note_cpu_paused(FAR struct tcb_s *tcb) { struct note_cpu_paused_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.ncp_cmn, sizeof(struct note_cpu_paused_s), @@ -487,6 +390,17 @@ void sched_note_cpu_resume(FAR struct tcb_s *tcb, int cpu) { struct note_cpu_resume_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.ncr_cmn, sizeof(struct note_cpu_resume_s), @@ -502,6 +416,17 @@ void sched_note_cpu_resumed(FAR struct tcb_s *tcb) { struct note_cpu_resumed_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.ncr_cmn, sizeof(struct note_cpu_resumed_s), @@ -518,6 +443,17 @@ void sched_note_premption(FAR struct tcb_s *tcb, bool locked) { struct note_preempt_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.npr_cmn, sizeof(struct note_preempt_s), @@ -536,6 +472,17 @@ void sched_note_csection(FAR struct tcb_s *tcb, bool enter) { struct note_csection_s note; +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.ncs_cmn, sizeof(struct note_csection_s), @@ -581,6 +528,17 @@ void sched_note_syscall_enter(int nr, int argc, ...) struct note_syscall_enter_s note; FAR struct tcb_s *tcb = this_task(); +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.nsc_cmn, sizeof(struct note_syscall_enter_s), @@ -598,6 +556,17 @@ void sched_note_syscall_leave(int nr, uintptr_t result) struct note_syscall_leave_s note; FAR struct tcb_s *tcb = this_task(); +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.nsc_cmn, sizeof(struct note_syscall_leave_s), @@ -618,6 +587,17 @@ void sched_note_irqhandler(int irq, FAR void *handler, bool enter) struct note_irqhandler_s note; FAR struct tcb_s *tcb = this_task(); +#ifdef CONFIG_SMP + /* Ignore notes that are not in the set of monitored CPUs */ + + if ((CONFIG_SCHED_INSTRUMENTATION_CPUSET & (1 << this_cpu())) == 0) + { + /* Not in the set of monitored CPUs. Do not log the note. */ + + return; + } +#endif + /* Format the note */ note_common(tcb, ¬e.nih_cmn, sizeof(struct note_irqhandler_s), @@ -630,145 +610,3 @@ void sched_note_irqhandler(int irq, FAR void *handler, bool enter) note_add((FAR const uint8_t *)¬e, sizeof(struct note_irqhandler_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 further notes. - * - * Input Parameters: - * buffer - Location to return the next note - * buflen - The length of the user provided buffer. - * - * Returned Value: - * On success, the positive, non-zero length of the return note is - * provided. Zero is returned only if the circular buffer is empty. A - * negated errno value is returned in the event of any failure. - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_NOTE_GET -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; - size_t circlen; - - DEBUGASSERT(buffer != NULL); - flags = enter_critical_section(); - - /* Verify that the circular buffer is not empty */ - - circlen = note_length(); - if (circlen <= 0) - { - notelen = 0; - goto errout_with_csection; - } - - /* 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 <= circlen); - - /* 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 an 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 - -/**************************************************************************** - * Name: sched_note_size - * - * Description: - * Return the size of the next note at the tail of the circular buffer. - * - * Input Parameters: - * None. - * - * Returned Value: - * Zero is returned if the circular buffer is empty. Otherwise, the size - * of the next note is returned. - * - ****************************************************************************/ - -#ifdef CONFIG_SCHED_NOTE_GET -ssize_t sched_note_size(void) -{ - FAR struct note_common_s *note; - irqstate_t flags; - unsigned int tail; - ssize_t notelen; - size_t circlen; - - flags = enter_critical_section(); - - /* Verify that the circular buffer is not empty */ - - circlen = note_length(); - if (circlen <= 0) - { - notelen = 0; - goto errout_with_csection; - } - - /* 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 <= circlen); - -errout_with_csection: - leave_critical_section(flags); - return notelen; -} -#endif - -#endif /* CONFIG_SCHED_INSTRUMENTATION_BUFFER */