diff options
| author | zhkag <[email protected]> | 2023-02-15 20:46:22 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-02-15 20:46:22 +0800 |
| commit | 0f85648cfbe5aa0c0158620917a98845811fefc3 (patch) | |
| tree | 3ff4413c01a1fff2ae8269368753214f5d57fb8f /components/libc | |
| parent | ad79e294742e2486e42c44e11619ef3b756dabf4 (diff) | |
Improve timer accuracy and realize (#6926)
* add cputimer frame
* add cputime sleep
* ctime use cputime
* Processing cputime has no timeout function
* Migration cputime Code
* formatting file
* 整理代码
* add document copyright information
* 改 cputime_timer 为 cputimer
* 简化 _cputimer_list 初始化
* rt_cputimer_create -> rt_cputimer_init
* Remove RT_USING_CPUTIME and code cleanup.
* Remove RT_USING_CPUTIME in cputimer.c
* Set set_next_timeout as static function.
---------
Co-authored-by: Bernard Xiong <[email protected]>
Diffstat (limited to 'components/libc')
| -rw-r--r-- | components/libc/compilers/common/ctime.c | 237 |
1 files changed, 159 insertions, 78 deletions
diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c index 8a6767e194..7e182b5ba9 100644 --- a/components/libc/compilers/common/ctime.c +++ b/components/libc/compilers/common/ctime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2022, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -32,7 +32,7 @@ #ifdef RT_USING_POSIX_DELAY #include <delay.h> #endif -#ifdef RT_USING_RTC +#if defined( RT_USING_RTC ) || defined( RT_USING_CPUTIME) #include <rtdevice.h> #endif @@ -535,28 +535,22 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) return -1; } #ifdef RT_USING_CPUTIME - uint64_t cpu_tick, cpu_tick_old; - cpu_tick_old = clock_cpu_gettime(); - rt_tick_t tick; double unit = clock_cpu_getres(); - - cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + ((uint64_t)rqtp->tv_nsec * NANOSECOND_PER_SECOND) / NANOSECOND_PER_SECOND) / unit; - tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND); - rt_thread_delay(tick); + rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; + rt_uint64_t tick = ns / unit; + rt_cputime_sleep(tick); if (rt_get_errno() == -RT_EINTR) { if (rmtp) { - uint64_t rmtp_cpu_tick = cpu_tick_old + cpu_tick - clock_cpu_gettime(); + uint64_t rmtp_cpu_tick = tick - clock_cpu_gettime(); rmtp->tv_sec = ((time_t)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND; rmtp->tv_nsec = ((long)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND; } rt_set_errno(EINTR); return -1; } - else - while (clock_cpu_gettime() - cpu_tick_old < cpu_tick); #else rt_tick_t tick, tick_old = rt_tick_get(); tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; @@ -761,30 +755,25 @@ int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, s case CLOCK_MONOTONIC: case CLOCK_CPUTIME_ID: { - uint64_t cpu_tick, cpu_tick_old; - cpu_tick_old = clock_cpu_gettime(); - rt_tick_t tick; + rt_uint64_t cpu_tick_old = clock_cpu_gettime(); double unit = clock_cpu_getres(); - - cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec * (NANOSECOND_PER_SECOND / NANOSECOND_PER_SECOND)) / unit; + rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; + rt_uint64_t tick = ns / unit; if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) - cpu_tick = cpu_tick < cpu_tick_old ? 0 : cpu_tick - cpu_tick_old; - tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND); - rt_thread_delay(tick); + tick -= cpu_tick_old; + rt_cputime_sleep(tick); if (rt_get_errno() == -RT_EINTR) { if (rmtp) { - uint64_t rmtp_cpu_tick = cpu_tick_old + cpu_tick - clock_cpu_gettime(); + uint64_t rmtp_cpu_tick = tick - clock_cpu_gettime(); rmtp->tv_sec = ((time_t)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND; rmtp->tv_nsec = ((long)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND; } rt_set_errno(EINTR); return -1; } - else - while (clock_cpu_gettime() - cpu_tick_old < cpu_tick); } break; #endif @@ -882,14 +871,21 @@ RTM_EXPORT(rt_timespec_to_tick); struct timer_obj { - struct rt_timer timer; + union + { + struct rt_timer timer; +#ifdef RT_USING_CPUTIME + struct rt_cputimer cputimer; +#endif + }; void (*sigev_notify_function)(union sigval val); union sigval val; struct timespec interval; /* Reload value */ struct timespec value; /* Reload value */ - rt_uint32_t reload; /* Reload value in ms */ + rt_uint64_t reload; /* Reload value in ms */ rt_uint32_t status; int sigev_signo; + clockid_t clockid; #ifdef RT_USING_SMART pid_t pid; #endif @@ -906,9 +902,20 @@ static void rtthread_timer_wrapper(void *timerobj) timer->status = NOT_ACTIVE; } - timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; - if (timer->reload) - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + { + timer->reload = (timer->interval.tv_sec * NANOSECOND_PER_SECOND + timer->interval.tv_nsec) / clock_cpu_getres(); + if (timer->reload) + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + } + else +#endif /* RT_USING_CPUTIME */ + { + timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; + if (timer->reload) + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + } #ifdef RT_USING_SMART sys_kill(timer->pid, timer->sigev_signo); @@ -1024,14 +1031,20 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) timer->interval.tv_nsec = 0; timer->reload = 0U; timer->status = NOT_ACTIVE; + timer->clockid = clockid; - if (evp->sigev_notify == SIGEV_NONE) +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) { - rt_timer_init(&timer->timer, timername, RT_NULL, RT_NULL, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + rt_cputimer_init(&timer->cputimer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); } else +#endif /* RT_USING_CPUTIME */ { - rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + if (evp->sigev_notify == SIGEV_NONE) + rt_timer_init(&timer->timer, timername, RT_NULL, RT_NULL, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + else + rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); } timer_id_lock(); @@ -1069,19 +1082,32 @@ int timer_delete(timer_t timerid) timer = _g_timerid[(rt_ubase_t)timerid]; timer_id_put((rt_ubase_t)timerid); timer_id_unlock(); - - if (timer == RT_NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer) + if (timer == RT_NULL) { rt_set_errno(EINVAL); return -1; } - if (timer->status == ACTIVE) +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) { - timer->status = NOT_ACTIVE; - rt_timer_stop(&timer->timer); + if (timer->status == ACTIVE) + { + timer->status = NOT_ACTIVE; + rt_cputimer_stop(&timer->cputimer); + } + rt_cputimer_detach(&timer->cputimer); + } + else +#endif /* RT_USING_CPUTIME */ + { + if (timer->status == ACTIVE) + { + timer->status = NOT_ACTIVE; + rt_timer_stop(&timer->timer); + } + rt_timer_detach(&timer->timer); } - rt_timer_detach(&timer->timer); rt_free(timer); return 0; @@ -1107,10 +1133,9 @@ int timer_getoverrun(timer_t timerid) int timer_gettime(timer_t timerid, struct itimerspec *its) { struct timer_obj *timer = timer_id_get((rt_ubase_t)timerid); - rt_tick_t remaining; rt_uint32_t seconds, nanoseconds; - if (timer == NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer) + if (timer == NULL) { rt_set_errno(EINVAL); return -1; @@ -1124,31 +1149,45 @@ int timer_gettime(timer_t timerid, struct itimerspec *its) if (timer->status == ACTIVE) { - rt_tick_t remain_tick; - - rt_timer_control(&timer->timer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + { + rt_uint64_t remain_tick; + rt_uint64_t remaining; + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); + remaining = (remain_tick - clock_cpu_gettime()) / clock_cpu_getres(); + seconds = remaining / NANOSECOND_PER_SECOND; + nanoseconds = remaining % NANOSECOND_PER_SECOND; + } + else +#endif /* RT_USING_CPUTIME */ + { + rt_tick_t remain_tick; + rt_tick_t remaining; - /* 'remain_tick' is minimum-unit in the RT-Thread' timer, - * so the seconds, nanoseconds will be calculated by 'remain_tick'. - */ - remaining = remain_tick - rt_tick_get(); + rt_timer_control(&timer->timer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); - /* calculate 'second' */ - seconds = remaining / RT_TICK_PER_SECOND; + /* 'remain_tick' is minimum-unit in the RT-Thread' timer, + * so the seconds, nanoseconds will be calculated by 'remain_tick'. + */ + remaining = remain_tick - rt_tick_get(); - /* calculate 'nanosecond'; To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on. - * - * remain_tick millisecond remain_tick * MILLISECOND_PER_SECOND - * ------------------------- = -------------------------- ---> millisecond = ------------------------------------------- - * RT_TICK_PER_SECOND MILLISECOND_PER_SECOND RT_TICK_PER_SECOND - * - * remain_tick * MILLISECOND_PER_SECOND remain_tick * MILLISECOND_PER_SECOND * MICROSECOND_PER_SECOND - * millisecond = ---------------------------------------- ---> nanosecond = ------------------------------------------------------------------- - * RT_TICK_PER_SECOND RT_TICK_PER_SECOND - * - */ - nanoseconds = (((remaining % RT_TICK_PER_SECOND) * MILLISECOND_PER_SECOND) * MICROSECOND_PER_SECOND) / RT_TICK_PER_SECOND ; + /* calculate 'second' */ + seconds = remaining / RT_TICK_PER_SECOND; + /* calculate 'nanosecond'; To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on. + * + * remain_tick millisecond remain_tick * MILLISECOND_PER_SECOND + * ------------------------- = -------------------------- ---> millisecond = ------------------------------------------- + * RT_TICK_PER_SECOND MILLISECOND_PER_SECOND RT_TICK_PER_SECOND + * + * remain_tick * MILLISECOND_PER_SECOND remain_tick * MILLISECOND_PER_SECOND * MICROSECOND_PER_SECOND + * millisecond = ---------------------------------------- ---> nanosecond = ------------------------------------------------------------------- + * RT_TICK_PER_SECOND RT_TICK_PER_SECOND + * + */ + nanoseconds = (((remaining % RT_TICK_PER_SECOND) * MILLISECOND_PER_SECOND) * MICROSECOND_PER_SECOND) / RT_TICK_PER_SECOND; + } its->it_value.tv_sec = (rt_int32_t)seconds; its->it_value.tv_nsec = (rt_int32_t)nanoseconds; } @@ -1175,7 +1214,6 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, { struct timer_obj *timer = timer_id_get((rt_ubase_t)timerid); if (timer == NULL || - rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer || value->it_interval.tv_nsec < 0 || value->it_interval.tv_nsec >= NANOSECOND_PER_SECOND || value->it_interval.tv_sec < 0 || @@ -1198,7 +1236,12 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, { if (timer->status == ACTIVE) { - rt_timer_stop(&timer->timer); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + rt_cputimer_stop(&timer->cputimer); + else +#endif /* RT_USING_CPUTIME */ + rt_timer_stop(&timer->timer); } timer->status = NOT_ACTIVE; @@ -1212,21 +1255,39 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, * RT_TICK_PER_SECOND NANOSECOND_PER_SECOND NANOSECOND_PER_SECOND * */ - if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + { + rt_uint64_t tick; + double unit = clock_cpu_getres(); + + tick = (value->it_value.tv_sec * NANOSECOND_PER_SECOND + value->it_value.tv_nsec) / unit; + if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) + { + tick -= clock_cpu_gettime(); + } + timer->reload = tick; + } + else +#endif /* RT_USING_CPUTIME */ { + if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) + { #ifndef RT_USING_RTC - LOG_W(_WARNING_NO_RTC); - return -1; + LOG_W(_WARNING_NO_RTC); + return -1; #else - rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND); - rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec * 1000) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); - rt_int64_t reload = ts + tns; - rt_tick_t rt_tick = rt_tick_get(); - timer->reload = reload < rt_tick ? 0 : reload - rt_tick; + rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND); + rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec * 1000) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); + rt_int64_t reload = ts + tns; + rt_tick_t rt_tick = rt_tick_get(); + + timer->reload = reload < rt_tick ? 0 : reload - rt_tick; #endif + } + else + timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); } - else - timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); timer->interval.tv_sec = value->it_interval.tv_sec; timer->interval.tv_nsec = value->it_interval.tv_nsec; timer->value.tv_sec = value->it_value.tv_sec; @@ -1234,18 +1295,38 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, if (timer->status == ACTIVE) { - rt_timer_stop(&timer->timer); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + rt_cputimer_stop(&timer->cputimer); + else +#endif /* RT_USING_CPUTIME */ + rt_timer_stop(&timer->timer); } timer->status = ACTIVE; - if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + { + if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); + else + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); + + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + rt_cputimer_start(&timer->cputimer); + } else - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); +#endif /* RT_USING_CPUTIME */ + { + if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); + else + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); - rt_timer_start(&timer->timer); + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + rt_timer_start(&timer->timer); + } return 0; } |
