From d65be718c2d365f2d8cb54af666d6fa7965e43fb Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 27 Nov 2016 17:14:57 -0600 Subject: [PATCH] sched_note: Extend OS instrumentation to include some SMP events. --- arch/arm/src/armv7-a/arm_cpupause.c | 25 ++++++++++ arch/arm/src/armv7-a/arm_cpustart.c | 3 +- arch/xtensa/src/common/xtensa_cpupause.c | 25 ++++++++++ drivers/syslog/Kconfig | 2 +- include/nuttx/sched_note.h | 59 ++++++++++++++++++++++++ sched/Kconfig | 8 ++++ sched/sched/sched_cpupause.c | 1 + sched/sched/sched_note.c | 56 ++++++++++++++++++++++ 8 files changed, 176 insertions(+), 3 deletions(-) diff --git a/arch/arm/src/armv7-a/arm_cpupause.c b/arch/arm/src/armv7-a/arm_cpupause.c index 8b8df44a73..c0751f8ee4 100644 --- a/arch/arm/src/armv7-a/arm_cpupause.c +++ b/arch/arm/src/armv7-a/arm_cpupause.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "up_internal.h" #include "gic.h" @@ -131,6 +132,12 @@ int up_cpu_paused(int cpu) sched_suspend_scheduler(tcb); +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify that we are paused */ + + sched_note_cpu_paused(tcb); +#endif + /* Save the current context at CURRENT_REGS into the TCB at the head * of the assigned task list for this CPU. */ @@ -148,6 +155,12 @@ int up_cpu_paused(int cpu) tcb = this_task(); +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify that we have resumed */ + + sched_note_cpu_resumed(tcb); +#endif + /* Reset scheduler parameters */ sched_resume_scheduler(tcb); @@ -224,6 +237,12 @@ int up_cpu_pause(int cpu) { int ret; +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify of the pause event */ + + sched_note_cpu_pause(this_task(), cpu); +#endif + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); /* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2 @@ -287,6 +306,12 @@ int up_cpu_pause(int cpu) int up_cpu_resume(int cpu) { +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify of the resume event */ + + sched_note_cpu_resume(this_task(), cpu); +#endif + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); /* Release the spinlock. Releasing the spinlock will cause the SGI2 diff --git a/arch/arm/src/armv7-a/arm_cpustart.c b/arch/arm/src/armv7-a/arm_cpustart.c index c3eab68d4a..012d2e438e 100644 --- a/arch/arm/src/armv7-a/arm_cpustart.c +++ b/arch/arm/src/armv7-a/arm_cpustart.c @@ -105,9 +105,8 @@ static inline void arm_registerdump(FAR struct tcb_s *tcb) int arm_start_handler(int irq, FAR void *context) { FAR struct tcb_s *tcb; - int cpu = up_cpu_index(); - sinfo("CPU%d Started\n", cpu); + sinfo("CPU%d Started\n", this_cpu()); /* Reset scheduler parameters */ diff --git a/arch/xtensa/src/common/xtensa_cpupause.c b/arch/xtensa/src/common/xtensa_cpupause.c index e310ad44da..8d1fcd0371 100644 --- a/arch/xtensa/src/common/xtensa_cpupause.c +++ b/arch/xtensa/src/common/xtensa_cpupause.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "xtensa.h" #include "sched/sched.h" @@ -117,6 +118,12 @@ int up_cpu_paused(int cpu) sched_suspend_scheduler(otcb); +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify that we are paused */ + + sched_note_cpu_paused(otcb); +#endif + /* Copy the CURRENT_REGS into the OLD TCB (otcb). The co-processor state * will be saved as part of the return from xtensa_irq_dispatch(). */ @@ -134,6 +141,12 @@ int up_cpu_paused(int cpu) ntcb = this_task(); +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify that we have resumed */ + + sched_note_cpu_resumed(ntcb); +#endif + /* Reset scheduler parameters */ sched_resume_scheduler(ntcb); @@ -203,6 +216,12 @@ int up_cpu_pause(int cpu) { int ret; +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify of the pause event */ + + sched_note_cpu_pause(this_task(), cpu); +#endif + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); /* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2 @@ -266,6 +285,12 @@ int up_cpu_pause(int cpu) int up_cpu_resume(int cpu) { +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify of the resume event */ + + sched_note_cpu_resume(this_task(), cpu); +#endif + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); /* Release the spinlock. Releasing the spinlock will cause the SGI2 diff --git a/drivers/syslog/Kconfig b/drivers/syslog/Kconfig index 3ac22d8b68..dd64edb1e8 100644 --- a/drivers/syslog/Kconfig +++ b/drivers/syslog/Kconfig @@ -73,7 +73,7 @@ config DRIVER_NOTE depends on SCHED_INSTRUMENTATION_BUFFER ---help--- Enable building a serial driver that can be used by an application - to read data from the in-memory, scheduler instrumentatin "note" + to read data from the in-memory, scheduler instrumentation "note" buffer. config SYSLOG_INTBUFFER diff --git a/include/nuttx/sched_note.h b/include/nuttx/sched_note.h index c21f040066..86afa0ea2c 100644 --- a/include/nuttx/sched_note.h +++ b/include/nuttx/sched_note.h @@ -64,6 +64,13 @@ enum note_type_e NOTE_STOP, NOTE_SUSPEND, NOTE_RESUME +#ifdef CONFIG_SMP + , + NOTE_CPU_PAUSE, + NOTE_CPU_PAUSED, + NOTE_CPU_RESUME, + NOTE_CPU_RESUMED +#endif #ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION , NOTE_PREEMPT_LOCK, @@ -122,6 +129,38 @@ struct note_resume_s struct note_common_s nre_cmn; /* Common note parameters */ }; +#ifdef CONFIG_SMP +/* This is the specific form of the NOTE_CPU_PAUSE note */ + +struct note_cpu_pause_s +{ + struct note_common_s ncp_cmn; /* Common note parameters */ + uint8_t ncp_target; /* CPU being paused */ +}; + +/* This is the specific form of the NOTE_CPU_PAUSED note */ + +struct note_cpu_paused_s +{ + struct note_common_s ncp_cmn; /* Common note parameters */ +}; + +/* This is the specific form of the NOTE_CPU_RESUME note */ + +struct note_cpu_resume_s +{ + struct note_common_s ncr_cmn; /* Common note parameters */ + uint8_t ncr_target; /* CPU being resumed */ +}; + +/* This is the specific form of the NOTE_CPU_RESUMED note */ + +struct note_cpu_resumed_s +{ + struct note_common_s ncr_cmn; /* Common note parameters */ +}; +#endif + #ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION /* This is the specific form of the NOTE_PREEMPT_LOCK/UNLOCK note */ @@ -174,12 +213,28 @@ void sched_note_stop(FAR struct tcb_s *tcb); void sched_note_suspend(FAR struct tcb_s *tcb); void sched_note_resume(FAR struct tcb_s *tcb); +#ifdef CONFIG_SMP +void sched_note_cpu_pause(FAR struct tcb_s *tcb, int cpu); +void sched_note_cpu_paused(FAR struct tcb_s *tcb); +void sched_note_cpu_resume(FAR struct tcb_s *tcb, int cpu); +void sched_note_cpu_resumed(FAR struct tcb_s *tcb); +#else +# define sched_note_cpu_pause(t,c) +# define sched_note_cpu_paused(t) +# define sched_note_cpu_resume(t,c) +# define sched_note_cpu_resumed(t) +#endif + #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 /**************************************************************************** @@ -250,6 +305,10 @@ int note_register(void); # define sched_note_stop(t) # define sched_note_suspend(t) # define sched_note_resume(t) +# define sched_note_cpu_pause(t,c) +# define sched_note_cpu_paused(t) +# define sched_note_cpu_resume(t,c) +# define sched_note_cpu_resumed(t) # define sched_note_premption(t,l) # define sched_note_csection(t,e) diff --git a/sched/Kconfig b/sched/Kconfig index 60156e0368..9065261acb 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -661,6 +661,14 @@ config SCHED_INSTRUMENTATION void sched_note_suspend(FAR struct tcb_s *tcb); void sched_note_resume(FAR struct tcb_s *tcb); + If CONFIG_SMP is enabled, then these additional interfaces are + expected: + + void sched_note_cpu_pause(FAR struct tcb_s *tcb, int cpu); + void sched_note_cpu_paused(FAR struct tcb_s *tcb); + void sched_note_cpu_resume(FAR struct tcb_s *tcb, int cpu); + void sched_note_cpu_resumed(FAR struct tcb_s *tcb); + 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 diff --git a/sched/sched/sched_cpupause.c b/sched/sched/sched_cpupause.c index 513e8deb48..d2b14d187d 100644 --- a/sched/sched/sched_cpupause.c +++ b/sched/sched/sched_cpupause.c @@ -44,6 +44,7 @@ #include #include +#include #include "sched/sched.h" diff --git a/sched/sched/sched_note.c b/sched/sched/sched_note.c index 4dc1bd262e..6594efaf22 100644 --- a/sched/sched/sched_note.c +++ b/sched/sched/sched_note.c @@ -369,6 +369,62 @@ void sched_note_resume(FAR struct tcb_s *tcb) note_add((FAR const uint8_t *)¬e, sizeof(struct note_resume_s)); } +#ifdef CONFIG_SMP +void sched_note_cpu_pause(FAR struct tcb_s *tcb, int cpu) +{ + struct note_cpu_pause_s note; + + /* Format the note */ + + note_common(tcb, ¬e.ncp_cmn, sizeof(struct note_cpu_pause_s), NOTE_CPU_PAUSE); + note.ncp_target = (uint8_t)cpu; + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_cpu_pause_s)); +} + +void sched_note_cpu_paused(FAR struct tcb_s *tcb) +{ + struct note_cpu_paused_s note; + + /* Format the note */ + + note_common(tcb, ¬e.ncp_cmn, sizeof(struct note_cpu_paused_s), NOTE_CPU_PAUSED); + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_cpu_paused_s)); +} + +void sched_note_cpu_resume(FAR struct tcb_s *tcb, int cpu) +{ + struct note_cpu_resume_s note; + + /* Format the note */ + + note_common(tcb, ¬e.ncr_cmn, sizeof(struct note_cpu_resume_s), NOTE_CPU_RESUME); + note.ncr_target = (uint8_t)cpu; + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_cpu_resume_s)); +} + +void sched_note_cpu_resumed(FAR struct tcb_s *tcb) +{ + struct note_cpu_resumed_s note; + + /* Format the note */ + + note_common(tcb, ¬e.ncr_cmn, sizeof(struct note_cpu_resumed_s), NOTE_CPU_RESUMED); + + /* Add the note to circular buffer */ + + note_add((FAR const uint8_t *)¬e, sizeof(struct note_cpu_resumed_s)); +} +#endif + #ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION void sched_note_premption(FAR struct tcb_s *tcb, bool locked) {