nuttx/sched/sched/sched_critmonitor.c
yinshengkai ddb87d3b86 clock: replace all up_perf_xx with perf_xx
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2023-10-02 16:11:43 +02:00

343 lines
9.3 KiB
C

/****************************************************************************
* sched/sched/sched_critmonitor.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sched.h>
#include <assert.h>
#include <debug.h>
#include <time.h>
#include "sched/sched.h"
#ifdef CONFIG_SCHED_CRITMONITOR
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_SCHED_CRITMONITOR_MAXTIME_PREEMPTION
# define CONFIG_SCHED_CRITMONITOR_MAXTIME_PREEMPTION 0
#endif
#ifndef CONFIG_SCHED_CRITMONITOR_MAXTIME_CSECTION
# define CONFIG_SCHED_CRITMONITOR_MAXTIME_CSECTION 0
#endif
#ifndef CONFIG_SCHED_CRITMONITOR_MAXTIME_THREAD
# define CONFIG_SCHED_CRITMONITOR_MAXTIME_THREAD 0
#endif
#if CONFIG_SCHED_CRITMONITOR_MAXTIME_PREEMPTION > 0
# define CHECK_PREEMPTION(pid, elapsed) \
do \
{ \
if (pid > 0 && \
elapsed > CONFIG_SCHED_CRITMONITOR_MAXTIME_PREEMPTION) \
{ \
CRITMONITOR_PANIC("PID %d hold sched lock too long %"PRIu32"\n", \
pid, elapsed); \
} \
} \
while (0)
#else
# define CHECK_PREEMPTION(pid, elapsed)
#endif
#if CONFIG_SCHED_CRITMONITOR_MAXTIME_CSECTION > 0
# define CHECK_CSECTION(pid, elapsed) \
do \
{ \
if (pid > 0 && \
elapsed > CONFIG_SCHED_CRITMONITOR_MAXTIME_CSECTION) \
{ \
CRITMONITOR_PANIC("PID %d hold critical section too long %" \
PRIu32 "\n", pid, elapsed); \
} \
} \
while (0)
#else
# define CHECK_CSECTION(pid, elapsed)
#endif
#if CONFIG_SCHED_CRITMONITOR_MAXTIME_THREAD > 0
# define CHECK_THREAD(pid, elapsed) \
do \
{ \
if (pid > 0 && \
elapsed > CONFIG_SCHED_CRITMONITOR_MAXTIME_THREAD) \
{ \
CRITMONITOR_PANIC("PID %d execute too long %"PRIu32"\n", \
pid, elapsed); \
} \
} \
while (0)
#else
# define CHECK_THREAD(pid, elapsed)
#endif
/****************************************************************************
* Private Data
****************************************************************************/
/* Start time when pre-emption disabled or critical section entered. */
static clock_t g_premp_start[CONFIG_SMP_NCPUS];
static clock_t g_crit_start[CONFIG_SMP_NCPUS];
/****************************************************************************
* Public Data
****************************************************************************/
/* Maximum time with pre-emption disabled or within critical section. */
clock_t g_premp_max[CONFIG_SMP_NCPUS];
clock_t g_crit_max[CONFIG_SMP_NCPUS];
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nxsched_critmon_preemption
*
* Description:
* Called when there is any change in pre-emptible state of a thread.
*
* Assumptions:
* - Called within a critical section.
* - Never called from an interrupt handler
*
****************************************************************************/
void nxsched_critmon_preemption(FAR struct tcb_s *tcb, bool state)
{
int cpu = this_cpu();
/* Are we enabling or disabling pre-emption */
if (state)
{
/* Disabling.. Save the thread start time */
tcb->premp_start = perf_gettime();
g_premp_start[cpu] = tcb->premp_start;
}
else
{
/* Re-enabling.. Check for the max elapsed time */
clock_t now = perf_gettime();
clock_t elapsed = now - tcb->premp_start;
if (elapsed > tcb->premp_max)
{
tcb->premp_max = elapsed;
CHECK_PREEMPTION(tcb->pid, elapsed);
}
/* Check for the global max elapsed time */
elapsed = now - g_premp_start[cpu];
if (elapsed > g_premp_max[cpu])
{
g_premp_max[cpu] = elapsed;
}
}
}
/****************************************************************************
* Name: nxsched_critmon_csection
*
* Description:
* Called when a thread enters or leaves a critical section.
*
* Assumptions:
* - Called within a critical section.
* - Never called from an interrupt handler
*
****************************************************************************/
void nxsched_critmon_csection(FAR struct tcb_s *tcb, bool state)
{
int cpu = this_cpu();
/* Are we entering or leaving the critical section? */
if (state)
{
/* Entering... Save the start time. */
tcb->crit_start = perf_gettime();
g_crit_start[cpu] = tcb->crit_start;
}
else
{
/* Leaving .. Check for the max elapsed time */
clock_t now = perf_gettime();
clock_t elapsed = now - tcb->crit_start;
if (elapsed > tcb->crit_max)
{
tcb->crit_max = elapsed;
CHECK_CSECTION(tcb->pid, elapsed);
}
/* Check for the global max elapsed time */
elapsed = now - g_crit_start[cpu];
if (elapsed > g_crit_max[cpu])
{
g_crit_max[cpu] = elapsed;
}
}
}
/****************************************************************************
* Name: nxsched_resume_critmon
*
* Description:
* Called when a thread resumes execution, perhaps re-establishing a
* critical section or a non-pre-emptible state.
*
* Assumptions:
* - Called within a critical section.
* - Might be called from an interrupt handler
*
****************************************************************************/
void nxsched_resume_critmon(FAR struct tcb_s *tcb)
{
clock_t current = perf_gettime();
int cpu = this_cpu();
clock_t elapsed;
tcb->run_start = current;
/* Did this task disable pre-emption? */
if (tcb->lockcount > 0)
{
/* Yes.. Save the start time */
tcb->premp_start = current;
g_premp_start[cpu] = current;
}
else
{
/* Check for the global max elapsed time */
elapsed = current - g_premp_start[cpu];
if (elapsed > g_premp_max[cpu])
{
g_premp_max[cpu] = elapsed;
CHECK_PREEMPTION(tcb->pid, elapsed);
}
}
/* Was this task in a critical section? */
if (tcb->irqcount > 0)
{
/* Yes.. Save the start time */
tcb->crit_start = current;
g_crit_start[cpu] = current;
}
else
{
/* Check for the global max elapsed time */
elapsed = current - g_crit_start[cpu];
if (elapsed > g_crit_max[cpu])
{
g_crit_max[cpu] = elapsed;
CHECK_CSECTION(tcb->pid, elapsed);
}
}
}
/****************************************************************************
* Name: nxsched_suspend_critmon
*
* Description:
* Called when a thread suspends execution, perhaps terminating a
* critical section or a non-preemptible state.
*
* Assumptions:
* - Called within a critical section.
* - Might be called from an interrupt handler
*
****************************************************************************/
void nxsched_suspend_critmon(FAR struct tcb_s *tcb)
{
clock_t current = perf_gettime();
clock_t elapsed = current - tcb->run_start;
#ifdef CONFIG_SCHED_CPULOAD_CRITMONITOR
clock_t tick = elapsed * CLOCKS_PER_SEC / perf_getfreq();
nxsched_process_taskload_ticks(tcb, tick);
#endif
tcb->run_time += elapsed;
if (elapsed > tcb->run_max)
{
tcb->run_max = elapsed;
CHECK_THREAD(tcb->pid, elapsed);
}
/* Did this task disable preemption? */
if (tcb->lockcount > 0)
{
/* Possibly re-enabling.. Check for the max elapsed time */
elapsed = current - tcb->premp_start;
if (elapsed > tcb->premp_max)
{
tcb->premp_max = elapsed;
CHECK_PREEMPTION(tcb->pid, elapsed);
}
}
/* Is this task in a critical section? */
if (tcb->irqcount > 0)
{
/* Possibly leaving .. Check for the max elapsed time */
elapsed = current - tcb->crit_start;
if (elapsed > tcb->crit_max)
{
tcb->crit_max = elapsed;
CHECK_CSECTION(tcb->pid, elapsed);
}
}
}
#endif