This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "".
The branch, master has been updated via f95ac4d08f59722e10524e3bbe7385044aa2b565 (commit) via 79a8bfe88fc65864bd30a9d856c39a657334a843 (commit) via 216e7ca52f92bf5ea4a0c82e38cc60e24885fa95 (commit) via a13aba1c4c0e97a08b05873de9dcf7f8a5637f69 (commit) via 6590f544ee2aa749643eeb8cbc8c479e789a385b (commit) via 3951dca226dbfc216dc7b986f5219216ca386eb8 (commit) via 9537c3802e291e725f0e19005f50dfb254c67dde (commit) via 68f3af205916dd2e8d0dd82f6ab8cb7f548a353a (commit) via 5c5d9390db4cf3a4cf909effeeb404c557e5c9a2 (commit) via 473b993971ad348bf61fea0c3409336945867361 (commit) via 777a745851a665f31733814a07b2538b94bb65dd (commit) from 1fe4c8442faf80f13582eb7ad37254ba8ade2cc6 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit f95ac4d08f59722e10524e3bbe7385044aa2b565 Author: Petri Savolainen petri.savolainen@nokia.com Date: Fri Sep 27 12:53:01 2019 +0300
linux-gen: timer: add poll interval time conf option
Improve timer accuracy by increasing timer pool scan rate to twice per resolution.
Add configure file option to limit inline timer polling rate in nanoseconds. With the default value, each thread checks if timer pool scan is needed in maximum once per 500us. Polling rate is increased if a timer pool is created with a higher resolution requirement.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/config/odp-linux-generic.conf b/config/odp-linux-generic.conf index 9a5dbea69..4fec05047 100644 --- a/config/odp-linux-generic.conf +++ b/config/odp-linux-generic.conf @@ -16,7 +16,7 @@
# Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.7" +config_file_version = "0.1.8"
# Shared memory options shm: { @@ -158,4 +158,13 @@ timer: { # Increasing the value reduces timer processing overhead while # decreasing accuracy. Ignored when inline timer is not enabled. inline_poll_interval = 10 + + # Inline timer poll interval in nanoseconds + # + # When inline_poll_interval is larger than 1, use this option to limit + # inline timer polling rate in nanoseconds. By default, this defines the + # maximum rate a thread may poll timers. If a timer pool is created with + # a higher resolution than this, the polling rate is increased + # accordingly. + inline_poll_interval_nsec = 500000 } diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index d9e35dd5d..bd35e5b42 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -212,7 +212,7 @@ typedef struct timer_global_t { odp_shm_t shm; /* Max timer resolution in nanoseconds */ uint64_t highest_res_ns; - uint64_t min_res_ns; + uint64_t poll_interval_nsec; int num_timer_pools; uint8_t timer_pool_used[MAX_TIMER_POOLS]; timer_pool_t *timer_pool[MAX_TIMER_POOLS]; @@ -221,9 +221,9 @@ typedef struct timer_global_t { _odp_atomic_flag_t ODP_ALIGNED_CACHE locks[NUM_LOCKS]; #endif /* These are read frequently from inline timer */ - odp_time_t time_per_ratelimit_period; + odp_time_t poll_interval_time; odp_bool_t use_inline_timers; - int inline_poll_interval; + int poll_interval; int highest_tp_idx;
} timer_global_t; @@ -280,6 +280,7 @@ static odp_timer_pool_t timer_pool_new(const char *name, int tp_idx; size_t sz0, sz1, sz2; uint64_t tp_size; + uint64_t res_ns, nsec_per_scan; uint32_t flags = ODP_SHM_SW_ONLY;
if (odp_global_ro.shm_single_va) @@ -323,7 +324,16 @@ static odp_timer_pool_t timer_pool_new(const char *name,
memset(tp, 0, tp_size);
- tp->nsec_per_scan = param->res_ns; + res_ns = param->res_ns; + + /* Scan timer pool twice during resolution interval */ + if (res_ns > ODP_TIME_USEC_IN_NS) + nsec_per_scan = res_ns / 2; + else + nsec_per_scan = res_ns; + + tp->nsec_per_scan = nsec_per_scan; + odp_atomic_init_u64(&tp->cur_tick, 0);
if (name == NULL) { @@ -365,6 +375,13 @@ static odp_timer_pool_t timer_pool_new(const char *name, if (timer_global->num_timer_pools == 1) odp_global_rw->inline_timers = timer_global->use_inline_timers;
+ /* Increase poll rate to match the highest resolution */ + if (timer_global->poll_interval_nsec > nsec_per_scan) { + timer_global->poll_interval_nsec = nsec_per_scan; + timer_global->poll_interval_time = + odp_time_global_from_ns(nsec_per_scan); + } + odp_ticketlock_unlock(&timer_global->lock); if (!odp_global_rw->inline_timers) { if (tp->param.clk_src == ODP_CLOCK_CPU) @@ -915,10 +932,10 @@ static inline void timer_pool_scan_inline(int num, odp_time_t now) if (odp_atomic_cas_u64(&tp->cur_tick, &old_tick, new_tick)) { if (tp->notify_overrun && diff > 1) { if (old_tick == 0) { - ODP_ERR("Timer pool (%s) %" PRIi64 " ticks overrun in start up\n", + ODP_ERR("Timer pool (%s) missed %" PRIi64 " scans in start up\n", tp->name, diff - 1); } else { - ODP_ERR("Timer pool (%s) resolution too high: %" PRIi64 " ticks overrun\n", + ODP_ERR("Timer pool (%s) resolution too high: missed %" PRIi64 " scans\n", tp->name, diff - 1); tp->notify_overrun = 0; } @@ -934,24 +951,30 @@ void _timer_run_inline(int dec) static __thread int timer_run_cnt = 1; odp_time_t now; int num = timer_global->highest_tp_idx + 1; + int poll_interval = timer_global->poll_interval;
if (num == 0) return;
/* Rate limit how often this thread checks the timer pools. */
- if (timer_global->inline_poll_interval > 1) { + if (poll_interval > 1) { timer_run_cnt -= dec; if (timer_run_cnt > 0) return; - timer_run_cnt = timer_global->inline_poll_interval; + timer_run_cnt = poll_interval; }
now = odp_time_global(); - if (odp_time_cmp(odp_time_diff(now, last_timer_run), - timer_global->time_per_ratelimit_period) == -1) - return; - last_timer_run = now; + + if (poll_interval > 1) { + odp_time_t period = odp_time_diff(now, last_timer_run); + + if (odp_time_cmp(period, + timer_global->poll_interval_time) < 0) + return; + last_timer_run = now; + }
/* Check the timer pools. */ timer_pool_scan_inline(num, now); @@ -1240,12 +1263,6 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, return ODP_TIMER_POOL_INVALID; }
- if (timer_global->min_res_ns > param->res_ns) { - timer_global->min_res_ns = param->res_ns; - timer_global->time_per_ratelimit_period = - odp_time_global_from_ns(timer_global->min_res_ns / 2); - } - return timer_pool_new(name, param); }
@@ -1473,7 +1490,6 @@ int odp_timer_init_global(const odp_init_t *params) odp_ticketlock_init(&timer_global->lock); timer_global->shm = shm; timer_global->highest_res_ns = MAX_INLINE_RES_NS; - timer_global->min_res_ns = INT64_MAX; timer_global->highest_tp_idx = -1;
#ifndef ODP_ATOMIC_U128 @@ -1497,10 +1513,17 @@ int odp_timer_init_global(const odp_init_t *params) odp_shm_free(shm); return -1; } - timer_global->inline_poll_interval = val; + timer_global->poll_interval = val;
- timer_global->time_per_ratelimit_period = - odp_time_global_from_ns(timer_global->min_res_ns / 2); + conf_str = "timer.inline_poll_interval_nsec"; + if (!_odp_libconfig_lookup_int(conf_str, &val)) { + ODP_ERR("Config option '%s' not found.\n", conf_str); + odp_shm_free(shm); + return -1; + } + timer_global->poll_interval_nsec = val; + timer_global->poll_interval_time = + odp_time_global_from_ns(timer_global->poll_interval_nsec);
if (!timer_global->use_inline_timers) { timer_res_init(); diff --git a/platform/linux-generic/test/inline-timer.conf b/platform/linux-generic/test/inline-timer.conf index 36bc7f323..03998f5f5 100644 --- a/platform/linux-generic/test/inline-timer.conf +++ b/platform/linux-generic/test/inline-timer.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.7" +config_file_version = "0.1.8"
timer: { # Enable inline timer implementation diff --git a/platform/linux-generic/test/process-mode.conf b/platform/linux-generic/test/process-mode.conf index 12c79617f..dbf2acb81 100644 --- a/platform/linux-generic/test/process-mode.conf +++ b/platform/linux-generic/test/process-mode.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.7" +config_file_version = "0.1.8"
# Shared memory options shm: {
commit 79a8bfe88fc65864bd30a9d856c39a657334a843 Author: Petri Savolainen petri.savolainen@nokia.com Date: Thu Sep 26 14:39:48 2019 +0300
linux-gen: timer: read time once per scan
Read time register once and use the same time value for all timer pools and rate limit comparison.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index cffe077b3..d9e35dd5d 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -875,17 +875,23 @@ static inline void timer_pool_scan(timer_pool_t *tp, uint64_t tick) * Inline timer processing *****************************************************************************/
+static inline uint64_t time_nsec(timer_pool_t *tp, odp_time_t now) +{ + odp_time_t start = tp->start_time; + + return odp_time_diff_ns(now, start); +} + static inline uint64_t current_nsec(timer_pool_t *tp) { - odp_time_t now, start; + odp_time_t now;
now = odp_time_global(); - start = tp->start_time;
- return odp_time_diff_ns(now, start); + return time_nsec(tp, now); }
-static inline void timer_pool_scan_inline(int num) +static inline void timer_pool_scan_inline(int num, odp_time_t now) { timer_pool_t *tp; uint64_t new_tick, old_tick, nsec; @@ -898,7 +904,7 @@ static inline void timer_pool_scan_inline(int num) if (tp == NULL) continue;
- nsec = current_nsec(tp); + nsec = time_nsec(tp, now); new_tick = nsec / tp->nsec_per_scan; old_tick = odp_atomic_load_u64(&tp->cur_tick); diff = new_tick - old_tick; @@ -948,7 +954,7 @@ void _timer_run_inline(int dec) last_timer_run = now;
/* Check the timer pools. */ - timer_pool_scan_inline(num); + timer_pool_scan_inline(num, now); }
/******************************************************************************
commit 216e7ca52f92bf5ea4a0c82e38cc60e24885fa95 Author: Petri Savolainen petri.savolainen@nokia.com Date: Wed Sep 25 14:18:31 2019 +0300
linux-gen: timer: use nsec as timer tick
Division operations which convert time to timer ticks caused low accuracy when timer resolution was high (division with a small number). Timers expired constantly too early and accuracy got worse when resolution was increased.
Use nsec as timer tick in API instead of resolution based tick. Timer scan runs once per resolution (cur_tick), but timer expiration times are compared in nanoseconds.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 9df12e186..cffe077b3 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -176,7 +176,7 @@ static inline void set_next_free(_odp_timer_t *tim, uint32_t nf)
typedef struct timer_pool_s { /* Put frequently accessed fields in the first cache line */ - odp_time_t time_per_tick; /* Time per timer pool tick */ + uint64_t nsec_per_scan; odp_time_t start_time; odp_atomic_u64_t cur_tick;/* Current tick value */ uint64_t min_rel_tck; @@ -323,7 +323,7 @@ static odp_timer_pool_t timer_pool_new(const char *name,
memset(tp, 0, tp_size);
- tp->time_per_tick = odp_time_global_from_ns(param->res_ns); + tp->nsec_per_scan = param->res_ns; odp_atomic_init_u64(&tp->cur_tick, 0);
if (name == NULL) { @@ -875,11 +875,20 @@ static inline void timer_pool_scan(timer_pool_t *tp, uint64_t tick) * Inline timer processing *****************************************************************************/
+static inline uint64_t current_nsec(timer_pool_t *tp) +{ + odp_time_t now, start; + + now = odp_time_global(); + start = tp->start_time; + + return odp_time_diff_ns(now, start); +} + static inline void timer_pool_scan_inline(int num) { timer_pool_t *tp; - odp_time_t now, start; - uint64_t new_tick, old_tick; + uint64_t new_tick, old_tick, nsec; int64_t diff; int i;
@@ -889,9 +898,8 @@ static inline void timer_pool_scan_inline(int num) if (tp == NULL) continue;
- now = odp_time_global(); - start = tp->start_time; - new_tick = (now.u64 - start.u64) / tp->time_per_tick.u64; + nsec = current_nsec(tp); + new_tick = nsec / tp->nsec_per_scan; old_tick = odp_atomic_load_u64(&tp->cur_tick); diff = new_tick - old_tick;
@@ -909,7 +917,7 @@ static inline void timer_pool_scan_inline(int num) tp->notify_overrun = 0; } } - timer_pool_scan(tp, new_tick); + timer_pool_scan(tp, nsec); } } } @@ -950,8 +958,8 @@ void _timer_run_inline(int dec)
static inline void timer_run_posix(timer_pool_t *tp) { + uint64_t nsec; int overrun; - int64_t prev_tick;
if (tp->notify_overrun) { overrun = timer_getoverrun(tp->timerid); @@ -967,10 +975,9 @@ static inline void timer_run_posix(timer_pool_t *tp) /* Prefetch initial cache lines (match 32 above) */ for (i = 0; i < 32; i += ODP_CACHE_LINE_SIZE / sizeof(array[0])) __builtin_prefetch(&array[i], 0, 0); - prev_tick = odp_atomic_fetch_inc_u64(&tp->cur_tick);
- /* Scan timer array, looking for timers to expire */ - timer_pool_scan(tp, prev_tick + 1); + nsec = current_nsec(tp); + timer_pool_scan(tp, nsec); }
static void *timer_thread(void *arg) @@ -1248,24 +1255,25 @@ void odp_timer_pool_destroy(odp_timer_pool_t tpid)
uint64_t odp_timer_tick_to_ns(odp_timer_pool_t tpid, uint64_t ticks) { - timer_pool_t *tp = timer_pool_from_hdl(tpid); + (void)tpid;
- return ticks * tp->param.res_ns; + /* Timer ticks in API are nsec */ + return ticks; }
uint64_t odp_timer_ns_to_tick(odp_timer_pool_t tpid, uint64_t ns) { - timer_pool_t *tp = timer_pool_from_hdl(tpid); + (void)tpid;
- return (uint64_t)(ns / tp->param.res_ns); + /* Timer ticks in API are nsec */ + return ns; }
uint64_t odp_timer_current_tick(odp_timer_pool_t tpid) { timer_pool_t *tp = timer_pool_from_hdl(tpid);
- /* Relaxed atomic read for lowest overhead */ - return odp_atomic_load_u64(&tp->cur_tick); + return current_nsec(tp); }
int odp_timer_pool_info(odp_timer_pool_t tpid, @@ -1318,8 +1326,8 @@ int odp_timer_set_abs(odp_timer_t hdl, odp_event_t *tmo_ev) { timer_pool_t *tp = handle_to_tp(hdl); + uint64_t cur_tick = current_nsec(tp); uint32_t idx = handle_to_idx(hdl, tp); - uint64_t cur_tick = odp_atomic_load_u64(&tp->cur_tick);
if (odp_unlikely(abs_tck < cur_tick + tp->min_rel_tck)) return ODP_TIMER_TOOEARLY; @@ -1336,8 +1344,10 @@ int odp_timer_set_rel(odp_timer_t hdl, odp_event_t *tmo_ev) { timer_pool_t *tp = handle_to_tp(hdl); + uint64_t cur_tick = current_nsec(tp); + uint64_t abs_tck = cur_tick + rel_tck; uint32_t idx = handle_to_idx(hdl, tp); - uint64_t abs_tck = odp_atomic_load_u64(&tp->cur_tick) + rel_tck; + if (odp_unlikely(rel_tck < tp->min_rel_tck)) return ODP_TIMER_TOOEARLY; if (odp_unlikely(rel_tck > tp->max_rel_tck))
commit a13aba1c4c0e97a08b05873de9dcf7f8a5637f69 Author: Petri Savolainen petri.savolainen@nokia.com Date: Thu Sep 19 15:07:51 2019 +0300
linux-gen: timer: remove pad from tick_buf_t
Use union to ensure tick_buf_t is 128 bits also with 32 bit pointers (buffer handle). Init potential extra bits only once.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 6cee6acd8..9df12e186 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -11,15 +11,6 @@ * ODP timer service * */ - -#if __SIZEOF_POINTER__ != 8 -/* TB_NEEDS_PAD defined if sizeof(odp_buffer_t) != 8 */ -#define TB_NEEDS_PAD -#define TB_SET_PAD(x) ((x).pad = 0) -#else -#define TB_SET_PAD(x) (void)(x) -#endif - #include <odp_posix_extensions.h>
#include <errno.h> @@ -117,10 +108,15 @@ tick_buf_s { #else odp_atomic_u64_t exp_tck;/* Expiration tick or TMO_xxx */ #endif - odp_buffer_t tmo_buf;/* ODP_BUFFER_INVALID if timer not active */ -#ifdef TB_NEEDS_PAD - uint32_t pad;/* Need to be able to access padding for successful CAS */ -#endif + + union { + /* ODP_BUFFER_INVALID if timer not active */ + odp_buffer_t tmo_buf; + + /* Ensures that tick_buf_t is 128 bits */ + uint64_t tmo_u64; + }; + } tick_buf_t;
#if __GCC_ATOMIC_LLONG_LOCK_FREE >= 2 @@ -140,9 +136,9 @@ static void timer_init(_odp_timer_t *tim, { tim->queue = _q; tim->user_ptr = _up; + tb->tmo_u64 = 0; tb->tmo_buf = ODP_BUFFER_INVALID; - /* All pad fields need a defined and constant value */ - TB_SET_PAD(*tb); + /* Release the timer by setting timer state to inactive */ #if __GCC_ATOMIC_LLONG_LOCK_FREE < 2 tb->exp_tck.v = TMO_INACTIVE; @@ -530,11 +526,16 @@ static bool timer_reset(uint32_t idx, if (tmo_buf == NULL || *tmo_buf == ODP_BUFFER_INVALID) { #ifdef ODP_ATOMIC_U128 /* Target supports 128-bit atomic operations */ tick_buf_t new, old; + + /* Init all bits, also when tmo_buf is less than 64 bits */ + new.tmo_u64 = 0; + old.tmo_u64 = 0; + do { /* Relaxed and non-atomic read of current values */ old.exp_tck.v = tb->exp_tck.v; old.tmo_buf = tb->tmo_buf; - TB_SET_PAD(old); + /* Check if there actually is a timeout buffer * present */ if (old.tmo_buf == ODP_BUFFER_INVALID) { @@ -546,7 +547,7 @@ static bool timer_reset(uint32_t idx, /* Set up new values */ new.exp_tck.v = abs_tck; new.tmo_buf = old.tmo_buf; - TB_SET_PAD(new); + /* Atomic CAS will fail if we experienced torn reads, * retry update sequence until CAS succeeds */ } while (!_odp_atomic_u128_cmp_xchg_mm( @@ -620,9 +621,13 @@ static bool timer_reset(uint32_t idx, odp_buffer_t old_buf = ODP_BUFFER_INVALID; #ifdef ODP_ATOMIC_U128 tick_buf_t new, old; + + /* Init all bits, also when tmo_buf is less than 64 bits */ + new.tmo_u64 = 0; + new.exp_tck.v = abs_tck; new.tmo_buf = *tmo_buf; - TB_SET_PAD(new); + /* We are releasing the new timeout buffer to some other * thread */ _odp_atomic_u128_xchg_mm((_odp_atomic_u128_t *)tb, @@ -661,11 +666,15 @@ static odp_buffer_t timer_set_unused(timer_pool_t *tp,
#ifdef ODP_ATOMIC_U128 tick_buf_t new, old; + + /* Init all bits, also when tmo_buf is less than 64 bits */ + new.tmo_u64 = 0; + /* Update the timer state (e.g. cancel the current timeout) */ new.exp_tck.v = TMO_UNUSED; /* Swap out the old buffer */ new.tmo_buf = ODP_BUFFER_INVALID; - TB_SET_PAD(new); + _odp_atomic_u128_xchg_mm((_odp_atomic_u128_t *)tb, (_uint128_t *)&new, (_uint128_t *)&old, _ODP_MEMMODEL_RLX); @@ -700,11 +709,14 @@ static odp_buffer_t timer_cancel(timer_pool_t *tp, #ifdef ODP_ATOMIC_U128 tick_buf_t new, old;
+ /* Init all bits, also when tmo_buf is less than 64 bits */ + new.tmo_u64 = 0; + old.tmo_u64 = 0; + do { /* Relaxed and non-atomic read of current values */ old.exp_tck.v = tb->exp_tck.v; old.tmo_buf = tb->tmo_buf; - TB_SET_PAD(old);
/* Check if it is not expired already */ if (old.exp_tck.v & TMO_INACTIVE) { @@ -715,7 +727,7 @@ static odp_buffer_t timer_cancel(timer_pool_t *tp, /* Set up new values */ new.exp_tck.v = TMO_INACTIVE; new.tmo_buf = ODP_BUFFER_INVALID; - TB_SET_PAD(new); + /* Atomic CAS will fail if we experienced torn reads, * retry update sequence until CAS succeeds */ } while (!_odp_atomic_u128_cmp_xchg_mm( @@ -763,15 +775,20 @@ static inline void timer_expire(timer_pool_t *tp, uint32_t idx, uint64_t tick) /* Attempt to grab timeout buffer, replace with inactive timer * and invalid buffer */ tick_buf_t new, old; + + /* Init all bits, also when tmo_buf is less than 64 bits */ + new.tmo_u64 = 0; + old.tmo_u64 = 0; + old.exp_tck.v = exp_tck; old.tmo_buf = tb->tmo_buf; - TB_SET_PAD(old); + /* Set the inactive/expired bit keeping the expiration tick so * that we can check against the expiration tick of the timeout * when it is received */ new.exp_tck.v = exp_tck | TMO_INACTIVE; new.tmo_buf = ODP_BUFFER_INVALID; - TB_SET_PAD(new); + int succ = _odp_atomic_u128_cmp_xchg_mm( (_odp_atomic_u128_t *)tb, (_uint128_t *)&old, (_uint128_t *)&new,
commit 6590f544ee2aa749643eeb8cbc8c479e789a385b Author: Petri Savolainen petri.savolainen@nokia.com Date: Tue Sep 24 15:52:20 2019 +0300
linux-gen: timer: timer index increment
Code is more readable when timer index is incremented in the end of the loop (not in the middle).
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index a8ec96016..6cee6acd8 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -839,17 +839,17 @@ static inline void timer_pool_scan(timer_pool_t *tp, uint64_t tick) uint32_t i;
ODP_ASSERT(high_wm <= tp->param.num_timers); - for (i = 0; i < high_wm;) { + for (i = 0; i < high_wm; i++) { /* As a rare occurrence, we can outsmart the HW prefetcher * and the compiler (GCC -fprefetch-loop-arrays) with some * tuned manual prefetching (32x16=512B ahead), seems to * give 30% better performance on ARM C-A15 */ __builtin_prefetch(&array[i + 32], 0, 0); /* Non-atomic read for speed */ - uint64_t exp_tck = array[i++].exp_tck.v; + uint64_t exp_tck = array[i].exp_tck.v; if (odp_unlikely(exp_tck <= tick)) { /* Attempt to expire timer */ - timer_expire(tp, i - 1, tick); + timer_expire(tp, i, tick); } } }
commit 3951dca226dbfc216dc7b986f5219216ca386eb8 Author: Petri Savolainen petri.savolainen@nokia.com Date: Thu Sep 19 14:26:45 2019 +0300
linux-gen: timer: scan timer pools up to highest index
Scan up to the highest pool index, instead of scanning all pools allways.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 707402195..a8ec96016 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -217,7 +217,6 @@ typedef struct timer_global_t { /* Max timer resolution in nanoseconds */ uint64_t highest_res_ns; uint64_t min_res_ns; - odp_time_t time_per_ratelimit_period; int num_timer_pools; uint8_t timer_pool_used[MAX_TIMER_POOLS]; timer_pool_t *timer_pool[MAX_TIMER_POOLS]; @@ -225,8 +224,12 @@ typedef struct timer_global_t { /* Multiple locks per cache line! */ _odp_atomic_flag_t ODP_ALIGNED_CACHE locks[NUM_LOCKS]; #endif + /* These are read frequently from inline timer */ + odp_time_t time_per_ratelimit_period; odp_bool_t use_inline_timers; int inline_poll_interval; + int highest_tp_idx; + } timer_global_t;
static timer_global_t *timer_global; @@ -277,7 +280,8 @@ static void itimer_fini(timer_pool_t *tp); static odp_timer_pool_t timer_pool_new(const char *name, const odp_timer_pool_param_t *param) { - uint32_t i, tp_idx; + uint32_t i; + int tp_idx; size_t sz0, sz1, sz2; uint64_t tp_size; uint32_t flags = ODP_SHM_SW_ONLY; @@ -303,6 +307,9 @@ static odp_timer_pool_t timer_pool_new(const char *name, tp_idx = i; timer_global->num_timer_pools++;
+ if (tp_idx > timer_global->highest_tp_idx) + timer_global->highest_tp_idx = tp_idx; + odp_ticketlock_unlock(&timer_global->lock);
sz0 = ROUNDUP_CACHE_LINE(sizeof(timer_pool_t)); @@ -395,7 +402,7 @@ static void stop_timer_thread(timer_pool_t *tp)
static void odp_timer_pool_del(timer_pool_t *tp) { - int rc; + int rc, highest; odp_shm_t shm;
odp_spinlock_lock(&tp->lock); @@ -423,9 +430,20 @@ static void odp_timer_pool_del(timer_pool_t *tp) timer_global->timer_pool_used[tp->tp_idx] = 0; timer_global->num_timer_pools--;
+ highest = -1; + /* Disable inline timer polling */ - if (timer_global->num_timer_pools == 0) + if (timer_global->num_timer_pools == 0) { odp_global_rw->inline_timers = false; + } else { + int i; + + for (i = 0; i < MAX_TIMER_POOLS; i++) + if (timer_global->timer_pool_used[i]) + highest = i; + } + + timer_global->highest_tp_idx = highest;
odp_ticketlock_unlock(&timer_global->lock);
@@ -840,7 +858,7 @@ static inline void timer_pool_scan(timer_pool_t *tp, uint64_t tick) * Inline timer processing *****************************************************************************/
-static inline void timer_pool_scan_inline(void) +static inline void timer_pool_scan_inline(int num) { timer_pool_t *tp; odp_time_t now, start; @@ -848,7 +866,7 @@ static inline void timer_pool_scan_inline(void) int64_t diff; int i;
- for (i = 0; i < MAX_TIMER_POOLS; i++) { + for (i = 0; i < num; i++) { tp = timer_global->timer_pool[i];
if (tp == NULL) @@ -884,8 +902,9 @@ void _timer_run_inline(int dec) static __thread odp_time_t last_timer_run; static __thread int timer_run_cnt = 1; odp_time_t now; + int num = timer_global->highest_tp_idx + 1;
- if (timer_global->num_timer_pools == 0) + if (num == 0) return;
/* Rate limit how often this thread checks the timer pools. */ @@ -904,7 +923,7 @@ void _timer_run_inline(int dec) last_timer_run = now;
/* Check the timer pools. */ - timer_pool_scan_inline(); + timer_pool_scan_inline(num); }
/****************************************************************************** @@ -1422,6 +1441,7 @@ int odp_timer_init_global(const odp_init_t *params) timer_global->shm = shm; timer_global->highest_res_ns = MAX_INLINE_RES_NS; timer_global->min_res_ns = INT64_MAX; + timer_global->highest_tp_idx = -1;
#ifndef ODP_ATOMIC_U128 uint32_t i;
commit 9537c3802e291e725f0e19005f50dfb254c67dde Author: Petri Savolainen petri.savolainen@nokia.com Date: Thu Sep 19 13:08:09 2019 +0300
linux-gen: timer: remove unused return value
Removed return value of timer expire function as it was not used. Also renamed functions so that it's easier to see which belong to posix and inline timer implementations.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/platform/linux-generic/include/odp_timer_internal.h b/platform/linux-generic/include/odp_timer_internal.h index 59ea19323..17ebf2684 100644 --- a/platform/linux-generic/include/odp_timer_internal.h +++ b/platform/linux-generic/include/odp_timer_internal.h @@ -37,12 +37,13 @@ typedef struct {
/* A larger decrement value should be used after receiving events compared to * an 'empty' call. */ -unsigned int _timer_run(int dec); +void _timer_run_inline(int dec);
/* Static inline wrapper to minimize modification of schedulers. */ -static inline unsigned int timer_run(int dec) +static inline void timer_run(int dec) { - return odp_global_rw->inline_timers ? _timer_run(dec) : 0; + if (odp_global_rw->inline_timers) + _timer_run_inline(dec); }
#endif diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 30e63fef8..707402195 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -731,7 +731,7 @@ static odp_buffer_t timer_cancel(timer_pool_t *tp, return old_buf; }
-static unsigned timer_expire(timer_pool_t *tp, uint32_t idx, uint64_t tick) +static inline void timer_expire(timer_pool_t *tp, uint32_t idx, uint64_t tick) { _odp_timer_t *tim = &tp->timers[idx]; tick_buf_t *tb = &tp->tick_buf[idx]; @@ -810,20 +810,14 @@ static unsigned timer_expire(timer_pool_t *tp, uint32_t idx, uint64_t tick) ODP_ABORT("Failed to enqueue timeout buffer (%d)\n", rc); } - return 1; - } else { - /* Else false positive, ignore */ - return 0; } }
-static unsigned odp_timer_pool_expire(odp_timer_pool_t tpid, uint64_t tick) +static inline void timer_pool_scan(timer_pool_t *tp, uint64_t tick) { - timer_pool_t *tp = timer_pool_from_hdl(tpid); tick_buf_t *array = &tp->tick_buf[0]; uint32_t high_wm = _odp_atomic_u32_load_mm(&tp->high_wm, _ODP_MEMMODEL_ACQ); - unsigned nexp = 0; uint32_t i;
ODP_ASSERT(high_wm <= tp->param.num_timers); @@ -837,24 +831,22 @@ static unsigned odp_timer_pool_expire(odp_timer_pool_t tpid, uint64_t tick) uint64_t exp_tck = array[i++].exp_tck.v; if (odp_unlikely(exp_tck <= tick)) { /* Attempt to expire timer */ - nexp += timer_expire(tp, i - 1, tick); + timer_expire(tp, i - 1, tick); } } - return nexp; }
/****************************************************************************** * Inline timer processing *****************************************************************************/
-static inline int process_timer_pools(void) +static inline void timer_pool_scan_inline(void) { timer_pool_t *tp; odp_time_t now, start; uint64_t new_tick, old_tick; int64_t diff; int i; - int num_exp = 0;
for (i = 0; i < MAX_TIMER_POOLS; i++) { tp = timer_global->timer_pool[i]; @@ -882,40 +874,37 @@ static inline int process_timer_pools(void) tp->notify_overrun = 0; } } - num_exp += odp_timer_pool_expire(timer_pool_to_hdl(tp), - new_tick); + timer_pool_scan(tp, new_tick); } } - - return num_exp; }
-unsigned int _timer_run(int dec) +void _timer_run_inline(int dec) { static __thread odp_time_t last_timer_run; static __thread int timer_run_cnt = 1; odp_time_t now;
if (timer_global->num_timer_pools == 0) - return 0; + return;
/* Rate limit how often this thread checks the timer pools. */
if (timer_global->inline_poll_interval > 1) { timer_run_cnt -= dec; if (timer_run_cnt > 0) - return 0; + return; timer_run_cnt = timer_global->inline_poll_interval; }
now = odp_time_global(); if (odp_time_cmp(odp_time_diff(now, last_timer_run), timer_global->time_per_ratelimit_period) == -1) - return 0; + return; last_timer_run = now;
/* Check the timer pools. */ - return process_timer_pools(); + timer_pool_scan_inline(); }
/****************************************************************************** @@ -923,7 +912,7 @@ unsigned int _timer_run(int dec) * Functions that use Linux/POSIX per-process timers and related facilities *****************************************************************************/
-static void timer_notify(timer_pool_t *tp) +static inline void timer_run_posix(timer_pool_t *tp) { int overrun; int64_t prev_tick; @@ -945,10 +934,7 @@ static void timer_notify(timer_pool_t *tp) prev_tick = odp_atomic_fetch_inc_u64(&tp->cur_tick);
/* Scan timer array, looking for timers to expire */ - (void)odp_timer_pool_expire(timer_pool_to_hdl(tp), prev_tick + 1); - - /* Else skip scan of timers. cur_tick was updated and next itimer - * invocation will process older expiration ticks as well */ + timer_pool_scan(tp, prev_tick + 1); }
static void *timer_thread(void *arg) @@ -985,7 +971,7 @@ static void *timer_thread(void *arg) if (ret <= 0) continue;
- timer_notify(tp); + timer_run_posix(tp);
if (num < warm_up) { num++;
commit 68f3af205916dd2e8d0dd82f6ab8cb7f548a353a Author: Petri Savolainen petri.savolainen@nokia.com Date: Thu Sep 19 10:00:17 2019 +0300
linux-gen: timer: remove prev_scan
Use current tick variable to check when timer pool was polled the last time. Prev_scan is duplicate information on that and was removed.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 3b9200c4d..30e63fef8 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2019, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -69,7 +70,10 @@ #define TMO_INACTIVE ((uint64_t)0x8000000000000000)
/* Max timeout in capability. One year in nsec (0x0070 09D3 2DA3 0000). */ -#define MAX_TMO_NSEC (365 * 24 * 3600 * ODP_TIME_SEC_IN_NS) +#define MAX_TMO_NSEC (365 * 24 * ODP_TIME_HOUR_IN_NS) + +/* Max inline timer resolution */ +#define MAX_INLINE_RES_NS 500
/****************************************************************************** * Mutual exclusion in the absence of CAS16 @@ -176,8 +180,8 @@ static inline void set_next_free(_odp_timer_t *tim, uint32_t nf)
typedef struct 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_time_t start_time; odp_atomic_u64_t cur_tick;/* Current tick value */ uint64_t min_rel_tck; uint64_t max_rel_tck; @@ -316,7 +320,6 @@ static odp_timer_pool_t timer_pool_new(const char *name,
memset(tp, 0, tp_size);
- 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);
@@ -364,6 +367,9 @@ static odp_timer_pool_t timer_pool_new(const char *name, if (tp->param.clk_src == ODP_CLOCK_CPU) itimer_init(tp); } + + tp->start_time = odp_time_global(); + return timer_pool_to_hdl(tp); }
@@ -841,49 +847,47 @@ static unsigned odp_timer_pool_expire(odp_timer_pool_t tpid, uint64_t tick) * Inline timer processing *****************************************************************************/
-static unsigned process_timer_pools(void) +static inline int process_timer_pools(void) { timer_pool_t *tp; - odp_time_t prev_scan, now; - uint64_t nticks; - unsigned nexp = 0; + odp_time_t now, start; + uint64_t new_tick, old_tick; + int64_t diff; + int i; + int num_exp = 0;
- for (size_t i = 0; i < MAX_TIMER_POOLS; i++) { + for (i = 0; i < MAX_TIMER_POOLS; i++) { tp = timer_global->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(); + start = tp->start_time; + new_tick = (now.u64 - start.u64) / tp->time_per_tick.u64; + old_tick = odp_atomic_load_u64(&tp->cur_tick); + diff = new_tick - old_tick;
- nticks = (now.u64 - prev_scan.u64) / tp->time_per_tick.u64; - - if (nticks < 1) + if (diff < 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; + if (odp_atomic_cas_u64(&tp->cur_tick, &old_tick, new_tick)) { + if (tp->notify_overrun && diff > 1) { + if (old_tick == 0) { + ODP_ERR("Timer pool (%s) %" PRIi64 " ticks overrun in start up\n", + tp->name, diff - 1); + } else { + ODP_ERR("Timer pool (%s) resolution too high: %" PRIi64 " ticks overrun\n", + tp->name, diff - 1); + tp->notify_overrun = 0; + } } - nexp += odp_timer_pool_expire(timer_pool_to_hdl(tp), - tp_tick + nticks); + num_exp += odp_timer_pool_expire(timer_pool_to_hdl(tp), + new_tick); } } - return nexp; + + return num_exp; }
unsigned int _timer_run(int dec) @@ -1430,7 +1434,7 @@ int odp_timer_init_global(const odp_init_t *params) memset(timer_global, 0, sizeof(timer_global_t)); odp_ticketlock_init(&timer_global->lock); timer_global->shm = shm; - timer_global->highest_res_ns = 500; + timer_global->highest_res_ns = MAX_INLINE_RES_NS; timer_global->min_res_ns = INT64_MAX;
#ifndef ODP_ATOMIC_U128
commit 5c5d9390db4cf3a4cf909effeeb404c557e5c9a2 Author: Petri Savolainen petri.savolainen@nokia.com Date: Wed Oct 2 13:53:52 2019 +0300
example: timer_accuracy: add first timer offset option
Added -f option to control offset to the first timer. This can be used e.g. to avoid best/worst case synchronization of timers to timer tick boundaries / resolution.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/example/timer/odp_timer_accuracy.c b/example/timer/odp_timer_accuracy.c index ecf608316..622814a95 100644 --- a/example/timer/odp_timer_accuracy.c +++ b/example/timer/odp_timer_accuracy.c @@ -14,12 +14,11 @@
#include <odp_api.h>
-#define START_OFFSET_NS ((uint64_t)(300 * ODP_TIME_MSEC_IN_NS)) - typedef struct test_global_t { struct { unsigned long long int period_ns; unsigned long long int res_ns; + unsigned long long int offset_ns; int num; int init; } opt; @@ -39,8 +38,9 @@ static void print_usage(void) "Timer accuracy test application.\n" "\n" "OPTIONS:\n" - " -p, --period <nsec> Timeout period. Default: 200 milliseconds\n" - " -r, --resolution <nsec> Timeout resolution. Default: period / 10\n" + " -p, --period <nsec> Timeout period in nsec. Default: 200 msec\n" + " -r, --resolution <nsec> Timeout resolution in nsec. Default: period / 10\n" + " -f, --first <nsec> First timer offset in nsec. Default: 300 msec\n" " -n, --num <number> Number of timeouts. Default: 50\n" " -i, --init Set global init parameters. Default: init params not set.\n" " -h, --help Display help and exit.\n\n"); @@ -52,16 +52,18 @@ static int parse_options(int argc, char *argv[], test_global_t *test_global) const struct option longopts[] = { {"period", required_argument, NULL, 'p'}, {"resolution", required_argument, NULL, 'r'}, + {"first", required_argument, NULL, 'f'}, {"num", required_argument, NULL, 'n'}, {"init", no_argument, NULL, 'i'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; - const char *shortopts = "+p:r:n:ih"; + const char *shortopts = "+p:r:f:n:ih"; int ret = 0;
test_global->opt.period_ns = 200 * ODP_TIME_MSEC_IN_NS; test_global->opt.res_ns = 0; + test_global->opt.offset_ns = 300 * ODP_TIME_MSEC_IN_NS; test_global->opt.num = 50; test_global->opt.init = 0;
@@ -78,6 +80,9 @@ static int parse_options(int argc, char *argv[], test_global_t *test_global) case 'r': test_global->opt.res_ns = strtoull(optarg, NULL, 0); break; + case 'f': + test_global->opt.offset_ns = strtoull(optarg, NULL, 0); + break; case 'n': test_global->opt.num = atoi(optarg); break; @@ -112,7 +117,7 @@ static int start_timers(test_global_t *test_global) odp_queue_t queue; odp_queue_param_t queue_param; uint64_t tick, start_tick; - uint64_t period_ns, res_ns, start_ns, nsec, res_capa; + uint64_t period_ns, res_ns, start_ns, nsec, res_capa, offset_ns; odp_event_t event; odp_timeout_t timeout; odp_timer_set_t ret; @@ -165,6 +170,7 @@ static int start_timers(test_global_t *test_global)
res_capa = timer_capa.highest_res_ns;
+ offset_ns = test_global->opt.offset_ns; res_ns = test_global->opt.res_ns;
if (res_ns < res_capa) { @@ -178,14 +184,14 @@ static int start_timers(test_global_t *test_global) memset(&timer_param, 0, sizeof(odp_timer_pool_param_t));
timer_param.res_ns = res_ns; - timer_param.min_tmo = START_OFFSET_NS / 2; - timer_param.max_tmo = START_OFFSET_NS + ((num + 1) * period_ns); + timer_param.min_tmo = offset_ns / 2; + timer_param.max_tmo = offset_ns + ((num + 1) * period_ns); timer_param.num_timers = num; timer_param.clk_src = ODP_CLOCK_CPU;
printf("\nTest parameters:\n"); printf(" resolution capa: %" PRIu64 " nsec\n", res_capa); - printf(" start offset: %" PRIu64 " nsec\n", START_OFFSET_NS); + printf(" start offset: %" PRIu64 " nsec\n", offset_ns); printf(" period: %" PRIu64 " nsec\n", period_ns); printf(" resolution: %" PRIu64 " nsec\n", timer_param.res_ns); printf(" min timeout: %" PRIu64 " nsec\n", timer_param.min_tmo); @@ -233,7 +239,7 @@ static int start_timers(test_global_t *test_global) start_tick = odp_timer_current_tick(timer_pool); time = odp_time_local(); start_ns = odp_time_to_ns(time); - test_global->first_ns = start_ns + START_OFFSET_NS; + test_global->first_ns = start_ns + offset_ns;
for (i = 0; i < num; i++) { timer = test_global->timer[i]; @@ -246,7 +252,7 @@ static int start_timers(test_global_t *test_global)
event = odp_timeout_to_event(timeout);
- nsec = START_OFFSET_NS + (i * period_ns); + nsec = offset_ns + (i * period_ns); tick = start_tick + odp_timer_ns_to_tick(timer_pool, nsec);
ret = odp_timer_set_abs(timer, tick, &event);
commit 473b993971ad348bf61fea0c3409336945867361 Author: Petri Savolainen petri.savolainen@nokia.com Date: Wed Oct 2 13:05:06 2019 +0300
example: timer_accuracy: add startup delay
Added delay and extra schedule calls to ensure that (software) timer implementation has passed its initial state before setting up timers.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/example/timer/odp_timer_accuracy.c b/example/timer/odp_timer_accuracy.c index a337e48b5..ecf608316 100644 --- a/example/timer/odp_timer_accuracy.c +++ b/example/timer/odp_timer_accuracy.c @@ -203,6 +203,9 @@ static int start_timers(test_global_t *test_global)
odp_timer_pool_start();
+ /* Spend some time so that current tick would not be zero */ + odp_time_wait_ns(100 * ODP_TIME_MSEC_IN_NS); + test_global->timer_pool = timer_pool;
for (i = 0; i < num; i++) { @@ -216,6 +219,17 @@ static int start_timers(test_global_t *test_global) test_global->timer[i] = timer; }
+ /* Run scheduler few times to ensure that (software) timer is active */ + for (i = 0; i < 1000; i++) { + event = odp_schedule(NULL, ODP_SCHED_NO_WAIT); + + if (event != ODP_EVENT_INVALID) { + printf("Spurious event received\n"); + odp_event_free(event); + return -1; + } + } + start_tick = odp_timer_current_tick(timer_pool); time = odp_time_local(); start_ns = odp_time_to_ns(time);
commit 777a745851a665f31733814a07b2538b94bb65dd Author: Petri Savolainen petri.savolainen@nokia.com Date: Tue Oct 1 16:45:14 2019 +0300
example: timer_accuracy: fix timeout offset
Fix bug in timer start offset calculation. Test results were offset by current local time value.
Signed-off-by: Petri Savolainen petri.savolainen@nokia.com Reviewed-by: Matias Elo matias.elo@nokia.com
diff --git a/example/timer/odp_timer_accuracy.c b/example/timer/odp_timer_accuracy.c index 9409e3404..a337e48b5 100644 --- a/example/timer/odp_timer_accuracy.c +++ b/example/timer/odp_timer_accuracy.c @@ -112,7 +112,7 @@ static int start_timers(test_global_t *test_global) odp_queue_t queue; odp_queue_param_t queue_param; uint64_t tick, start_tick; - uint64_t period_ns, res_ns, start_ns, time_ns, res_capa; + uint64_t period_ns, res_ns, start_ns, nsec, res_capa; odp_event_t event; odp_timeout_t timeout; odp_timer_set_t ret; @@ -178,8 +178,8 @@ static int start_timers(test_global_t *test_global) memset(&timer_param, 0, sizeof(odp_timer_pool_param_t));
timer_param.res_ns = res_ns; - timer_param.min_tmo = period_ns; - timer_param.max_tmo = START_OFFSET_NS + (num * period_ns); + timer_param.min_tmo = START_OFFSET_NS / 2; + timer_param.max_tmo = START_OFFSET_NS + ((num + 1) * period_ns); timer_param.num_timers = num; timer_param.clk_src = ODP_CLOCK_CPU;
@@ -216,7 +216,10 @@ static int start_timers(test_global_t *test_global) test_global->timer[i] = timer; }
- start_tick = 0; + start_tick = odp_timer_current_tick(timer_pool); + time = odp_time_local(); + start_ns = odp_time_to_ns(time); + test_global->first_ns = start_ns + START_OFFSET_NS;
for (i = 0; i < num; i++) { timer = test_global->timer[i]; @@ -229,15 +232,9 @@ static int start_timers(test_global_t *test_global)
event = odp_timeout_to_event(timeout);
- if (i == 0) { - start_tick = odp_timer_current_tick(timer_pool); - time = odp_time_local(); - start_ns = odp_time_to_ns(time); - test_global->first_ns = start_ns + START_OFFSET_NS; - } + nsec = START_OFFSET_NS + (i * period_ns); + tick = start_tick + odp_timer_ns_to_tick(timer_pool, nsec);
- time_ns = test_global->first_ns + (i * period_ns); - tick = start_tick + odp_timer_ns_to_tick(timer_pool, time_ns); ret = odp_timer_set_abs(timer, tick, &event);
if (ret != ODP_TIMER_SUCCESS) {
-----------------------------------------------------------------------
Summary of changes: config/odp-linux-generic.conf | 11 +- example/timer/odp_timer_accuracy.c | 53 ++-- .../linux-generic/include/odp_timer_internal.h | 7 +- platform/linux-generic/odp_timer.c | 294 +++++++++++++-------- platform/linux-generic/test/inline-timer.conf | 2 +- platform/linux-generic/test/process-mode.conf | 2 +- 6 files changed, 231 insertions(+), 138 deletions(-)
hooks/post-receive