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 <[email protected]>
> ---
>  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;
> 

Reply via email to