clock_getres() is to find the hardware resolution of specific clock source.
It shows 1ns in most of modern system.
What this API trys to do is to find out the resolution without overrun of
this timer. Applications are able to deal with each timer event with that
timer resolution.

2017-02-17 3:00 GMT+08:00 Maxim Uvarov <maxim.uva...@linaro.org>:

> why not clock_getres() ?
>
> Maxim.
>
> On 02/08/17 05:37, Kevin Wang wrote:
> > Implement a new internal function timer_res_init() to detect the max
> > timer resolution without overrun at the ODP init stage. It will check
> > timer resolution from 1ms to 100us, 10us...1ns until the timer is
> > overrun.
> >
> > Signed-off-by: Kevin Wang <kevin.w...@linaro.org>
> > ---
> >  platform/linux-generic/odp_timer.c | 95 ++++++++++++++++++++++++++++++
> ++++++++
> >  1 file changed, 95 insertions(+)
> >
> > diff --git a/platform/linux-generic/odp_timer.c
> b/platform/linux-generic/odp_timer.c
> > index 53fec08..9b884ea 100644
> > --- a/platform/linux-generic/odp_timer.c
> > +++ b/platform/linux-generic/odp_timer.c
> > @@ -70,6 +70,9 @@ static _odp_atomic_flag_t locks[NUM_LOCKS]; /*
> Multiple locks per cache line! */
> >  #define IDX2LOCK(idx) (&locks[(idx) % NUM_LOCKS])
> >  #endif
> >
> > +/* Timer resolution in nanoseconds */
> > +static uint64_t timer_res;
> > +
> >  /***********************************************************
> *******************
> >   * Translation between timeout buffer and timeout header
> >   ************************************************************
> *****************/
> > @@ -188,6 +191,7 @@ typedef struct odp_timer_pool_s {
> >
> >  #define MAX_TIMER_POOLS 255 /* Leave one for ODP_TIMER_INVALID */
> >  #define INDEX_BITS 24
> > +#define TIMER_RES_TEST_LOOP_COUNT 10
> >  static odp_atomic_u32_t num_timer_pools;
> >  static odp_timer_pool *timer_pool[MAX_TIMER_POOLS];
> >
> > @@ -738,6 +742,81 @@ static void *timer_thread(void *arg)
> >       return NULL;
> >  }
> >
> > +/* Get the max timer resolution without overrun and fill in timer_res
> variable.
> > + *
> > + * Set timer's interval with candidate resolutions to get the max
> resolution
> > + * that the timer would not be overrun.
> > + * The candidate resolution value is from 1ms to 100us, 10us...1ns etc.
> > + */
> > +static int timer_res_init(void)
> > +{
> > +     struct sigevent sigev;
> > +     timer_t timerid;
> > +     uint64_t res, sec, nsec;
> > +     struct itimerspec ispec;
> > +     sigset_t sigset;
> > +     siginfo_t si;
> > +     int loop_cnt;
> > +     struct timespec tmo;
> > +
> > +     sigev.sigev_notify = SIGEV_THREAD_ID;
> > +     sigev._sigev_un._tid = (pid_t)syscall(SYS_gettid);
> > +     sigev.sigev_signo = SIGUSR1;
> > +
> > +     /* Create timer */
> > +     if (timer_create(CLOCK_MONOTONIC, &sigev, &timerid))
> > +             ODP_ABORT("timer_create() returned error %s\n",
> > +                       strerror(errno));
> > +
> > +     /* Timer resolution start from 1ms */
> > +     res = ODP_TIME_MSEC_IN_NS;
> > +     /* Set initial value of timer_res */
> > +     timer_res = res;
> > +     sigemptyset(&sigset);
> > +     /* Add SIGUSR1 to sigset */
> > +     sigaddset(&sigset, SIGUSR1);
> > +     sigprocmask(SIG_BLOCK, &sigset, NULL);
> > +
> > +     while (res > 0) {
> > +             /* Loop for 10 times to test the result */
> > +             loop_cnt = TIMER_RES_TEST_LOOP_COUNT;
> > +             sec  = res / ODP_TIME_SEC_IN_NS;
> > +             nsec = res - sec * ODP_TIME_SEC_IN_NS;
> > +
> > +             memset(&ispec, 0, sizeof(ispec));
> > +             ispec.it_interval.tv_sec  = (time_t)sec;
> > +             ispec.it_interval.tv_nsec = (long)nsec;
> > +             ispec.it_value.tv_sec     = (time_t)sec;
> > +             ispec.it_value.tv_nsec    = (long)nsec;
> > +
> > +             if (timer_settime(timerid, 0, &ispec, NULL))
> > +                     ODP_ABORT("timer_settime() returned error %s\n",
> > +                               strerror(errno));
> > +             /* Set signal wait timeout to 10*res */
> > +             tmo.tv_sec = 0;
> > +             tmo.tv_nsec = res * 10;
> > +             while (loop_cnt--) {
> > +                     if (sigtimedwait(&sigset, &si, &tmo) > 0) {
> > +                             if (timer_getoverrun(timerid))
> > +                                     /* overrun at this resolution */
> > +                                     /* goto the end */
> > +                                     goto timer_res_init_done;
> > +                     }
> > +             }
> > +             /* Set timer_res */
> > +             timer_res = res;
> > +             /* Test the next timer resolution candidate */
> > +             res /= 10;
> > +     }
> > +timer_res_init_done:
> > +     if (timer_delete(timerid) != 0)
> > +             ODP_ABORT("timer_delete() returned error %s\n",
> > +                       strerror(errno));
> > +     sigemptyset(&sigset);
> > +     sigprocmask(SIG_BLOCK, &sigset, NULL);
> > +     return 0;
> > +}
> > +
> >  static void itimer_init(odp_timer_pool *tp)
> >  {
> >       struct sigevent   sigev;
> > @@ -795,6 +874,20 @@ static void itimer_fini(odp_timer_pool *tp)
> >   * Some parameter checks and error messages
> >   * No modificatios of internal state
> >   ************************************************************
> *****************/
> > +int odp_timer_capability(odp_timer_clk_src_t clk_src,
> > +                      odp_timer_capability_t *capa)
> > +{
> > +     int ret = 0;
> > +
> > +     if (clk_src == ODP_CLOCK_CPU) {
> > +             capa->res_ns = timer_res;
> > +     } else {
> > +             ODP_ERR("ODP timer system doesn't support external clock
> source currently\n");
> > +             ret = -1;
> > +     }
> > +     return ret;
> > +}
> > +
> >  odp_timer_pool_t
> >  odp_timer_pool_create(const char *name,
> >                     const odp_timer_pool_param_t *param)
> > @@ -1003,6 +1096,8 @@ int odp_timer_init_global(void)
> >  #endif
> >       odp_atomic_init_u32(&num_timer_pools, 0);
> >
> > +     timer_res_init();
> > +
> >       block_sigalarm();
> >
> >       return 0;
> >
>
>


-- 
Thanks,
Kevin

Reply via email to