Hi Petri,
Any more comments?
I suggest we should push this patchset firstly. If we have any new
requirements, we can create a new ticket to trace it.
What's your thought?

2017-02-20 10:37 GMT+08:00 Kevin Wang <[email protected]>:

> We don't know how many threads/locks the application will use. The final
> timer resolution is determined by applications. So what we are trying to do
> here is to find out a MAX resolution in a single thread on this system. So
> no matter in the multi-thread environment or other more workloads system,
> the resolution should be obvious less than this MAX value.
>
> I think overrun means the application is not able to keep up with dealing
> each timer interrupt. It will miss some interrupts.
>
> 2017-02-17 17:46 GMT+08:00 Maxim Uvarov <[email protected]>:
>
>>
>>
>> On 17 February 2017 at 11:51, Francois Ozog <[email protected]>
>> wrote:
>>
>>> I think this is quite useful for cloud applications that do not know
>>> the underlying hardware specs and need to check what is effectively
>>> possible. "hardware" resolution is nothing without all surrounding
>>> software layers, and virtualization in particular...
>>>
>>> On 17 February 2017 at 09:43, Kevin Wang <[email protected]> wrote:
>>> > 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.
>>> >
>>>
>>
>>
>> Timer run in some thread. With different load you will have different
>> latency on timer action.
>> Plus you can be in some atomic operation preempted by the kernel. Number
>> of 'in fight' timers
>> also make sense. I'm not sure that we can do right calculation of that
>> value.
>>
>> btw, what is bad in overrun? And what is overrun in current context? Is
>> it hardware time counter overrun
>> or variable presented as time in odp overrun?
>>
>> Maxim.
>>
>>
>>> > 2017-02-17 3:00 GMT+08:00 Maxim Uvarov <[email protected]>:
>>> >
>>> >> 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;
>>> >> >
>>> >>
>>> >>
>>> >
>>> >
>>> > --
>>> > Thanks,
>>> > Kevin
>>>
>>>
>>>
>>> --
>>> François-Frédéric Ozog | Director Linaro Networking Group
>>> T: +33.67221.6485
>>> [email protected] | Skype: ffozog
>>>
>>
>>
>
>
> --
> Thanks,
> Kevin
>



-- 
Thanks,
Kevin

Reply via email to