timer: handle perf count overflow
clock_getcycle always returns an incremented cycle value If the hardware does not support perf event it will use arch_alarm's up_perf_gettime Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
This commit is contained in:
parent
244293ce5f
commit
b99820744c
@ -663,6 +663,24 @@ struct timer_lowerhalf_s;
|
||||
void nxsched_period_extclk(FAR struct timer_lowerhalf_s *lower);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* perf_gettime
|
||||
****************************************************************************/
|
||||
|
||||
clock_t perf_gettime(void);
|
||||
|
||||
/****************************************************************************
|
||||
* perf_convert
|
||||
****************************************************************************/
|
||||
|
||||
void perf_convert(clock_t elapsed, FAR struct timespec *ts);
|
||||
|
||||
/****************************************************************************
|
||||
* perf_gettfreq
|
||||
****************************************************************************/
|
||||
|
||||
unsigned long perf_getfreq(void);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -283,6 +283,16 @@ config PREALLOC_TIMERS
|
||||
pool of preallocated timer structures to minimize dynamic allocations. Set to
|
||||
zero for all dynamic allocations.
|
||||
|
||||
config PERF_OVERFLOW_CORRECTION
|
||||
bool "Compensate perf count overflow"
|
||||
depends on SYSTEM_TIME64 && (ALARM_ARCH || TIMER_ARCH || ARCH_PERF_EVENTS)
|
||||
default n
|
||||
---help---
|
||||
If this option is enabled, then the perf event will be enabled
|
||||
by default.
|
||||
When enabled, it will always return an increasing count value to
|
||||
avoid overflow on 32-bit platforms.
|
||||
|
||||
endmenu # Clocks and Timers
|
||||
|
||||
menu "Tasks and Scheduling"
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
set(SRCS
|
||||
clock.c
|
||||
clock_perf.c
|
||||
clock_initialize.c
|
||||
clock_settime.c
|
||||
clock_gettime.c
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
CSRCS += clock.c clock_initialize.c clock_settime.c clock_gettime.c
|
||||
CSRCS += clock_abstime2ticks.c clock_systime_ticks.c clock_systime_timespec.c
|
||||
CSRCS += clock_perf.c
|
||||
|
||||
ifeq ($(CONFIG_CLOCK_TIMEKEEPING),y)
|
||||
CSRCS += clock_timekeeping.c
|
||||
|
@ -94,4 +94,10 @@ int clock_abstime2ticks(clockid_t clockid,
|
||||
FAR const struct timespec *abstime,
|
||||
FAR sclock_t *ticks);
|
||||
|
||||
/****************************************************************************
|
||||
* perf_init
|
||||
****************************************************************************/
|
||||
|
||||
void perf_init(void);
|
||||
|
||||
#endif /* __SCHED_CLOCK_CLOCK_H */
|
||||
|
@ -237,6 +237,8 @@ void clock_initialize(void)
|
||||
|
||||
#endif
|
||||
|
||||
perf_init();
|
||||
|
||||
sched_trace_end();
|
||||
}
|
||||
|
||||
|
203
sched/clock/clock_perf.c
Normal file
203
sched/clock/clock_perf.c
Normal file
@ -0,0 +1,203 @@
|
||||
/****************************************************************************
|
||||
* sched/clock/clock_perf.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 <stdint.h>
|
||||
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/wdog.h>
|
||||
|
||||
#if defined(CONFIG_PERF_OVERFLOW_CORRECTION) && ULONG_MAX != UINT64_MAX
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct perf_s
|
||||
{
|
||||
struct wdog_s wdog;
|
||||
unsigned long last;
|
||||
unsigned long overflow;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct perf_s g_perf;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* perf_update
|
||||
****************************************************************************/
|
||||
|
||||
static void perf_update(wdparm_t arg)
|
||||
{
|
||||
clock_t tick = (clock_t)LONG_MAX * TICK_PER_SEC / up_perf_getfreq();
|
||||
|
||||
perf_gettime();
|
||||
wd_start((FAR struct wdog_s *)arg, tick, perf_update, arg);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* perf_init
|
||||
****************************************************************************/
|
||||
|
||||
void perf_init(void)
|
||||
{
|
||||
FAR struct perf_s *perf = &g_perf;
|
||||
clock_t tick = (clock_t)LONG_MAX * TICK_PER_SEC / up_perf_getfreq();
|
||||
|
||||
perf->last = up_perf_gettime();
|
||||
|
||||
/* Periodic check for overflow */
|
||||
|
||||
wd_start(&perf->wdog, tick, perf_update, (wdparm_t)perf);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_gettime
|
||||
****************************************************************************/
|
||||
|
||||
clock_t perf_gettime(void)
|
||||
{
|
||||
FAR struct perf_s *perf = &g_perf;
|
||||
unsigned long now = up_perf_gettime();
|
||||
|
||||
/* Check if overflow */
|
||||
|
||||
if (now < perf->last)
|
||||
{
|
||||
perf->overflow++;
|
||||
}
|
||||
|
||||
perf->last = now;
|
||||
return (clock_t)now | (clock_t)perf->overflow << 32;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_convert
|
||||
****************************************************************************/
|
||||
|
||||
void perf_convert(clock_t elapsed, FAR struct timespec *ts)
|
||||
{
|
||||
unsigned long freq = up_perf_getfreq();
|
||||
|
||||
ts->tv_sec = elapsed / freq;
|
||||
elapsed -= ts->tv_sec * freq;
|
||||
ts->tv_nsec = NSEC_PER_SEC * elapsed / freq;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_getfreq
|
||||
****************************************************************************/
|
||||
|
||||
unsigned long perf_getfreq(void)
|
||||
{
|
||||
return up_perf_getfreq();
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_ALARM_ARCH) || defined (CONFIG_TIMER_ARCH) || \
|
||||
defined(CONFIG_ARCH_PERF_EVENTS)
|
||||
|
||||
/****************************************************************************
|
||||
* perf_init
|
||||
****************************************************************************/
|
||||
|
||||
void perf_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_gettime
|
||||
****************************************************************************/
|
||||
|
||||
clock_t perf_gettime(void)
|
||||
{
|
||||
return up_perf_gettime();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_convert
|
||||
****************************************************************************/
|
||||
|
||||
void perf_convert(clock_t elapsed, FAR struct timespec *ts)
|
||||
{
|
||||
up_perf_convert(elapsed, ts);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_getfreq
|
||||
****************************************************************************/
|
||||
|
||||
unsigned long perf_getfreq(void)
|
||||
{
|
||||
return up_perf_getfreq();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
* perf_init
|
||||
****************************************************************************/
|
||||
|
||||
void perf_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_gettime
|
||||
****************************************************************************/
|
||||
|
||||
clock_t perf_gettime(void)
|
||||
{
|
||||
return clock_systime_ticks();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_convert
|
||||
****************************************************************************/
|
||||
|
||||
void perf_convert(clock_t elapsed, FAR struct timespec *ts)
|
||||
{
|
||||
clock_ticks2time(elapsed, ts);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* perf_getfreq
|
||||
****************************************************************************/
|
||||
|
||||
unsigned long perf_getfreq(void)
|
||||
{
|
||||
return TICK_PER_SEC;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user