Are you saying we should be good to merge this now?

On 19 June 2017 at 17:42, Bill Fischofer <bill.fischo...@linaro.org> wrote:
> On Mon, Jun 19, 2017 at 4:19 PM, Honnappa Nagarahalli
> <honnappa.nagaraha...@linaro.org> wrote:
>> Hi Bill/Maxim,
>>     I do not see any further comments, can we merge this to api-next?
>>
>> Thanks,
>> Honnappa
>
> Now that v1.15 is tagged we can unblock some of this pending work.
> Next step is to merge the v1.15 changes back into api-next so that we
> can continue with the merge of new APIs and features in preparation
> for v1.16.
>
>>
>> On 16 June 2017 at 10:59, Honnappa Nagarahalli
>> <honnappa.nagaraha...@linaro.org> wrote:
>>> Reviewed-by: Honnappa Nagarahalli <honnappa.nagaraha...@arm.com>
>>>
>>> On 14 June 2017 at 14:34, Brian Brooks <brian.bro...@arm.com> wrote:
>>>> Run timer pool processing on worker cores if the application hints
>>>> that the scheduler will be used. This reduces the latency and jitter
>>>> of the point at which timer pool processing begins. See [1] for details.
>>>>
>>>> [1] 
>>>> https://docs.google.com/document/d/1sY7rOxqCNu-bMqjBiT5_keAIohrX1ZW-eL0oGLAQ4OM/edit?usp=sharing
>>>>
>>>> Signed-off-by: Brian Brooks <brian.bro...@arm.com>
>>>> Reviewed-by: Ola Liljedahl <ola.liljed...@arm.com>
>>>> Reviewed-by: Honnappa Nagarahalli <honnappa.nagaraha...@arm.com>
>>>> ---
>>>>
>>>> ** There is a false positive checkpatch.pl warning **
>>>>
>>>> v4:
>>>>  - Rebase against Bill's feature init patch
>>>>
>>>> v3:
>>>>  - Add rate limiting by scheduling rounds
>>>>
>>>> v2:
>>>>  - Reword 'worker_timers' to 'use_scheduler'
>>>>  - Use time instead of ticks
>>>>
>>>>  platform/linux-generic/include/odp_internal.h      |   2 +-
>>>>  .../linux-generic/include/odp_timer_internal.h     |  24 +++++
>>>>  platform/linux-generic/odp_init.c                  |   2 +-
>>>>  platform/linux-generic/odp_schedule.c              |   3 +
>>>>  platform/linux-generic/odp_schedule_iquery.c       |   3 +
>>>>  platform/linux-generic/odp_schedule_sp.c           |   3 +
>>>>  platform/linux-generic/odp_timer.c                 | 112 
>>>> +++++++++++++++++++--
>>>>  7 files changed, 138 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/platform/linux-generic/include/odp_internal.h 
>>>> b/platform/linux-generic/include/odp_internal.h
>>>> index 90e2a629..404792cf 100644
>>>> --- a/platform/linux-generic/include/odp_internal.h
>>>> +++ b/platform/linux-generic/include/odp_internal.h
>>>> @@ -108,7 +108,7 @@ int odp_queue_term_global(void);
>>>>  int odp_crypto_init_global(void);
>>>>  int odp_crypto_term_global(void);
>>>>
>>>> -int odp_timer_init_global(void);
>>>> +int odp_timer_init_global(const odp_init_t *params);
>>>>  int odp_timer_term_global(void);
>>>>  int odp_timer_disarm_all(void);
>>>>
>>>> diff --git a/platform/linux-generic/include/odp_timer_internal.h 
>>>> b/platform/linux-generic/include/odp_timer_internal.h
>>>> index 91b12c54..67ee9fef 100644
>>>> --- a/platform/linux-generic/include/odp_timer_internal.h
>>>> +++ b/platform/linux-generic/include/odp_timer_internal.h
>>>> @@ -20,6 +20,12 @@
>>>>  #include <odp_pool_internal.h>
>>>>  #include <odp/api/timer.h>
>>>>
>>>> +/* Minimum number of nanoseconds between checking timer pools. */
>>>> +#define CONFIG_TIMER_RUN_RATELIMIT_NS 100
>>>> +
>>>> +/* Minimum number of scheduling rounds between checking timer pools. */
>>>> +#define CONFIG_TIMER_RUN_RATELIMIT_ROUNDS 1
>>>> +
>>>>  /**
>>>>   * Internal Timeout header
>>>>   */
>>>> @@ -35,4 +41,22 @@ typedef struct {
>>>>         odp_timer_t timer;
>>>>  } odp_timeout_hdr_t;
>>>>
>>>> +/*
>>>> + * Whether to run timer pool processing 'inline' (on worker cores) or in
>>>> + * background threads (thread-per-timerpool).
>>>> + *
>>>> + * If the application will use both scheduler and timer this flag is set
>>>> + * to true, otherwise false. This application conveys this information via
>>>> + * the 'not_used' bits in odp_init_t which are passed to 
>>>> odp_global_init().
>>>> + */
>>>> +extern odp_bool_t inline_timers;
>>>> +
>>>> +unsigned _timer_run(void);
>>>> +
>>>> +/* Static inline wrapper to minimize modification of schedulers. */
>>>> +static inline unsigned timer_run(void)
>>>> +{
>>>> +       return inline_timers ? _timer_run() : 0;
>>>> +}
>>>> +
>>>>  #endif
>>>> diff --git a/platform/linux-generic/odp_init.c 
>>>> b/platform/linux-generic/odp_init.c
>>>> index 62a1fbc2..8c17cbb0 100644
>>>> --- a/platform/linux-generic/odp_init.c
>>>> +++ b/platform/linux-generic/odp_init.c
>>>> @@ -241,7 +241,7 @@ int odp_init_global(odp_instance_t *instance,
>>>>         }
>>>>         stage = PKTIO_INIT;
>>>>
>>>> -       if (odp_timer_init_global()) {
>>>> +       if (odp_timer_init_global(params)) {
>>>>                 ODP_ERR("ODP timer init failed.\n");
>>>>                 goto init_failed;
>>>>         }
>>>> diff --git a/platform/linux-generic/odp_schedule.c 
>>>> b/platform/linux-generic/odp_schedule.c
>>>> index 011d4dc4..04d09981 100644
>>>> --- a/platform/linux-generic/odp_schedule.c
>>>> +++ b/platform/linux-generic/odp_schedule.c
>>>> @@ -23,6 +23,7 @@
>>>>  #include <odp/api/packet_io.h>
>>>>  #include <odp_ring_internal.h>
>>>>  #include <odp_queue_internal.h>
>>>> +#include <odp_timer_internal.h>
>>>>
>>>>  /* Number of priority levels  */
>>>>  #define NUM_PRIO 8
>>>> @@ -998,6 +999,8 @@ static int schedule_loop(odp_queue_t *out_queue, 
>>>> uint64_t wait,
>>>>         int ret;
>>>>
>>>>         while (1) {
>>>> +               timer_run();
>>>> +
>>>>                 ret = do_schedule(out_queue, out_ev, max_num);
>>>>
>>>>                 if (ret)
>>>> diff --git a/platform/linux-generic/odp_schedule_iquery.c 
>>>> b/platform/linux-generic/odp_schedule_iquery.c
>>>> index bdf1a460..f7c411f6 100644
>>>> --- a/platform/linux-generic/odp_schedule_iquery.c
>>>> +++ b/platform/linux-generic/odp_schedule_iquery.c
>>>> @@ -23,6 +23,7 @@
>>>>  #include <odp/api/thrmask.h>
>>>>  #include <odp/api/packet_io.h>
>>>>  #include <odp_config_internal.h>
>>>> +#include <odp_timer_internal.h>
>>>>
>>>>  /* Number of priority levels */
>>>>  #define NUM_SCHED_PRIO 8
>>>> @@ -719,6 +720,8 @@ static int schedule_loop(odp_queue_t *out_queue, 
>>>> uint64_t wait,
>>>>         odp_time_t next, wtime;
>>>>
>>>>         while (1) {
>>>> +               timer_run();
>>>> +
>>>>                 count = do_schedule(out_queue, out_ev, max_num);
>>>>
>>>>                 if (count)
>>>> diff --git a/platform/linux-generic/odp_schedule_sp.c 
>>>> b/platform/linux-generic/odp_schedule_sp.c
>>>> index 91d70e3a..252d128d 100644
>>>> --- a/platform/linux-generic/odp_schedule_sp.c
>>>> +++ b/platform/linux-generic/odp_schedule_sp.c
>>>> @@ -15,6 +15,7 @@
>>>>  #include <odp_align_internal.h>
>>>>  #include <odp_config_internal.h>
>>>>  #include <odp_ring_internal.h>
>>>> +#include <odp_timer_internal.h>
>>>>
>>>>  #define NUM_THREAD        ODP_THREAD_COUNT_MAX
>>>>  #define NUM_QUEUE         ODP_CONFIG_QUEUES
>>>> @@ -517,6 +518,8 @@ static int schedule_multi(odp_queue_t *from, uint64_t 
>>>> wait,
>>>>                 uint32_t qi;
>>>>                 int num;
>>>>
>>>> +               timer_run();
>>>> +
>>>>                 cmd = sched_cmd();
>>>>
>>>>                 if (cmd && cmd->s.type == CMD_PKTIO) {
>>>> diff --git a/platform/linux-generic/odp_timer.c 
>>>> b/platform/linux-generic/odp_timer.c
>>>> index cf610bfa..bf7f1acd 100644
>>>> --- a/platform/linux-generic/odp_timer.c
>>>> +++ b/platform/linux-generic/odp_timer.c
>>>> @@ -52,6 +52,7 @@
>>>>  #include <odp/api/sync.h>
>>>>  #include <odp/api/time.h>
>>>>  #include <odp/api/timer.h>
>>>> +#include <odp_time_internal.h>
>>>>  #include <odp_timer_internal.h>
>>>>
>>>>  #define TMO_UNUSED   ((uint64_t)0xFFFFFFFFFFFFFFFF)
>>>> @@ -60,6 +61,8 @@
>>>>   * for checking the freshness of received timeouts */
>>>>  #define TMO_INACTIVE ((uint64_t)0x8000000000000000)
>>>>
>>>> +odp_bool_t inline_timers = false;
>>>> +
>>>>  
>>>> /******************************************************************************
>>>>   * Mutual exclusion in the absence of CAS16
>>>>   
>>>> *****************************************************************************/
>>>> @@ -165,7 +168,8 @@ static inline void set_next_free(odp_timer *tim, 
>>>> uint32_t nf)
>>>>   
>>>> *****************************************************************************/
>>>>
>>>>  typedef struct odp_timer_pool_s {
>>>> -/* Put frequently accessed fields in the first cache line */
>>>> +       odp_time_t prev_scan; /* Time when previous scan started */
>>>> +       odp_time_t time_per_tick; /* Time per timer pool tick */
>>>>         odp_atomic_u64_t cur_tick;/* Current tick value */
>>>>         uint64_t min_rel_tck;
>>>>         uint64_t max_rel_tck;
>>>> @@ -242,6 +246,8 @@ static odp_timer_pool_t odp_timer_pool_new(const char 
>>>> *name,
>>>>                 ODP_ABORT("%s: timer pool shm-alloc(%zuKB) failed\n",
>>>>                           name, (sz0 + sz1 + sz2) / 1024);
>>>>         odp_timer_pool *tp = (odp_timer_pool *)odp_shm_addr(shm);
>>>> +       tp->prev_scan = odp_time_global();
>>>> +       tp->time_per_tick = odp_time_global_from_ns(param->res_ns);
>>>>         odp_atomic_init_u64(&tp->cur_tick, 0);
>>>>
>>>>         if (name == NULL) {
>>>> @@ -276,8 +282,10 @@ static odp_timer_pool_t odp_timer_pool_new(const char 
>>>> *name,
>>>>         tp->tp_idx = tp_idx;
>>>>         odp_spinlock_init(&tp->lock);
>>>>         timer_pool[tp_idx] = tp;
>>>> -       if (tp->param.clk_src == ODP_CLOCK_CPU)
>>>> -               itimer_init(tp);
>>>> +       if (!inline_timers) {
>>>> +               if (tp->param.clk_src == ODP_CLOCK_CPU)
>>>> +                       itimer_init(tp);
>>>> +       }
>>>>         return tp;
>>>>  }
>>>>
>>>> @@ -306,11 +314,13 @@ static void odp_timer_pool_del(odp_timer_pool *tp)
>>>>         odp_spinlock_lock(&tp->lock);
>>>>         timer_pool[tp->tp_idx] = NULL;
>>>>
>>>> -       /* Stop timer triggering */
>>>> -       if (tp->param.clk_src == ODP_CLOCK_CPU)
>>>> -               itimer_fini(tp);
>>>> +       if (!inline_timers) {
>>>> +               /* Stop POSIX itimer signals */
>>>> +               if (tp->param.clk_src == ODP_CLOCK_CPU)
>>>> +                       itimer_fini(tp);
>>>>
>>>> -       stop_timer_thread(tp);
>>>> +               stop_timer_thread(tp);
>>>> +       }
>>>>
>>>>         if (tp->num_alloc != 0) {
>>>>                 /* It's a programming error to attempt to destroy a */
>>>> @@ -671,6 +681,81 @@ static unsigned 
>>>> odp_timer_pool_expire(odp_timer_pool_t tpid, uint64_t tick)
>>>>  }
>>>>
>>>>  
>>>> /******************************************************************************
>>>> + * Inline timer processing
>>>> + 
>>>> *****************************************************************************/
>>>> +
>>>> +static unsigned process_timer_pools(void)
>>>> +{
>>>> +       odp_timer_pool *tp;
>>>> +       odp_time_t prev_scan, now;
>>>> +       uint64_t nticks;
>>>> +       unsigned nexp = 0;
>>>> +
>>>> +       for (size_t i = 0; i < MAX_TIMER_POOLS; i++) {
>>>> +               tp = timer_pool[i];
>>>> +
>>>> +               if (tp == NULL)
>>>> +                       continue;
>>>> +
>>>> +               /*
>>>> +                * Check the last time this timer pool was expired. If one
>>>> +                * or more periods have passed, attempt to expire it.
>>>> +                */
>>>> +               prev_scan = tp->prev_scan;
>>>> +               now = odp_time_global();
>>>> +
>>>> +               nticks = (now.u64 - prev_scan.u64) / tp->time_per_tick.u64;
>>>> +
>>>> +               if (nticks < 1)
>>>> +                       continue;
>>>> +
>>>> +               if (__atomic_compare_exchange_n(
>>>> +                           &tp->prev_scan.u64, &prev_scan.u64,
>>>> +                           prev_scan.u64 + (tp->time_per_tick.u64 * 
>>>> nticks),
>>>> +                           false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
>>>> +                       uint64_t tp_tick = _odp_atomic_u64_fetch_add_mm(
>>>> +                               &tp->cur_tick, nticks, _ODP_MEMMODEL_RLX);
>>>> +
>>>> +                       if (tp->notify_overrun && nticks > 1) {
>>>> +                               ODP_ERR("\n\t%d ticks overrun on timer 
>>>> pool "
>>>> +                                       "\"%s\", timer resolution too 
>>>> high\n",
>>>> +                                       nticks - 1, tp->name);
>>>> +                               tp->notify_overrun = 0;
>>>> +                       }
>>>> +                       nexp += odp_timer_pool_expire(tp, tp_tick + 
>>>> nticks);
>>>> +               }
>>>> +       }
>>>> +       return nexp;
>>>> +}
>>>> +
>>>> +static odp_time_t time_per_ratelimit_period;
>>>> +
>>>> +unsigned _timer_run(void)
>>>> +{
>>>> +       static __thread odp_time_t last_timer_run;
>>>> +       static __thread unsigned timer_run_cnt =
>>>> +               CONFIG_TIMER_RUN_RATELIMIT_ROUNDS;
>>>> +       odp_time_t now;
>>>> +
>>>> +       /* Rate limit how often this thread checks the timer pools. */
>>>> +
>>>> +       if (CONFIG_TIMER_RUN_RATELIMIT_ROUNDS > 1) {
>>>> +               if (--timer_run_cnt)
>>>> +                       return 0;
>>>> +               timer_run_cnt = CONFIG_TIMER_RUN_RATELIMIT_ROUNDS;
>>>> +       }
>>>> +
>>>> +       now = odp_time_global();
>>>> +       if (odp_time_cmp(odp_time_diff(now, last_timer_run),
>>>> +                        time_per_ratelimit_period) == -1)
>>>> +               return 0;
>>>> +       last_timer_run = now;
>>>> +
>>>> +       /* Check the timer pools. */
>>>> +       return process_timer_pools();
>>>> +}
>>>> +
>>>> +/******************************************************************************
>>>>   * POSIX timer support
>>>>   * Functions that use Linux/POSIX per-process timers and related 
>>>> facilities
>>>>   
>>>> *****************************************************************************/
>>>> @@ -989,7 +1074,7 @@ void odp_timeout_free(odp_timeout_t tmo)
>>>>         odp_buffer_free(odp_buffer_from_event(ev));
>>>>  }
>>>>
>>>> -int odp_timer_init_global(void)
>>>> +int odp_timer_init_global(const odp_init_t *params)
>>>>  {
>>>>  #ifndef ODP_ATOMIC_U128
>>>>         uint32_t i;
>>>> @@ -1000,7 +1085,16 @@ int odp_timer_init_global(void)
>>>>  #endif
>>>>         odp_atomic_init_u32(&num_timer_pools, 0);
>>>>
>>>> -       block_sigalarm();
>>>> +       if (params)
>>>> +               inline_timers =
>>>> +                       !params->not_used.feat.schedule &&
>>>> +                       !params->not_used.feat.timer;
>>>> +
>>>> +       time_per_ratelimit_period =
>>>> +               odp_time_global_from_ns(CONFIG_TIMER_RUN_RATELIMIT_NS);
>>>> +
>>>> +       if (!inline_timers)
>>>> +               block_sigalarm();
>>>>
>>>>         return 0;
>>>>  }
>>>> --
>>>> 2.13.1
>>>>

Reply via email to