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, api-next has been updated via c16f1363303cd5fc11324acbc4dfebe0a9680a41 (commit) via fbdc9ca1e38e6c97014e68bf7b83e59096a170b7 (commit) via 2e08ac6e40551704c43233b40a9227a19fd4623b (commit) via 5386c44d204f0b42f2773cf87126ff8981bf3270 (commit) from 56dbc8702500f7d7e518fcea4f3b1ff853722004 (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 c16f1363303cd5fc11324acbc4dfebe0a9680a41 Author: Kevin Wang kevin.wang@arm.com Date: Thu Jul 20 11:43:26 2017 +0800
doc: userguide: add odp_timer_capability() section to user guide
Signed-off-by: Kevin Wang kevin.wang@arm.com Reviewed-by: Brian Brooks brian.brooks@arm.com Reviewed-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/doc/users-guide/users-guide-timer.adoc b/doc/users-guide/users-guide-timer.adoc index 9cd30de1..4a8bad74 100644 --- a/doc/users-guide/users-guide-timer.adoc +++ b/doc/users-guide/users-guide-timer.adoc @@ -6,7 +6,8 @@ timing features found in various platforms that support ODP implementations. Timers are drawn from specialized pools called _timer pools_ that have their own abstract type (`odp_timer_pool_t`). Each timer pool is a logically independent time source with its own _resolution_ measured in nanoseconds (ns) -and a maximum number of timers that it can support. Applications can have many +and a maximum number of timers that it can support. The max _resolution_ is +able to be obtained from `odp_timer_capability()`. Applications can have many timers active at the same time and can set them to use either relative or absolute time. Associated with each timer is a queue that is to receive events when this timer expires. This queue is created by a separate
commit fbdc9ca1e38e6c97014e68bf7b83e59096a170b7 Author: Kevin Wang kevin.wang@arm.com Date: Thu Jul 20 11:43:25 2017 +0800
validation/example: call odp_timer_capability() before creating timer pool
Use odp_timer_capability() to determine the max timer resolution
Signed-off-by: Kevin Wang kevin.wang@arm.com Reviewed-by: Brian Brooks brian.brooks@arm.com Reviewed-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c index 9336cec1..02282e81 100644 --- a/example/generator/odp_generator.c +++ b/example/generator/odp_generator.c @@ -32,6 +32,7 @@ #define APPL_MODE_UDP 0 /**< UDP mode */ #define APPL_MODE_PING 1 /**< ping mode */ #define APPL_MODE_RCV 2 /**< receive mode */ +#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/** print appl mode */ #define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x)) @@ -813,6 +814,7 @@ int main(int argc, char *argv[]) interface_t *ifs; odp_instance_t instance; odph_odpthread_params_t thr_params; + odp_timer_capability_t timer_capa;
/* Init ODP before calling anything else */ if (odp_init_global(&instance, NULL, NULL)) { @@ -898,7 +900,12 @@ int main(int argc, char *argv[]) odp_pool_print(pool);
/* Create timer pool */ - tparams.res_ns = 1 * ODP_TIME_MSEC_IN_NS; + if (odp_timer_capability(ODP_CLOCK_CPU, &timer_capa)) { + EXAMPLE_ERR("Error: get timer capacity failed.\n"); + exit(EXIT_FAILURE); + } + tparams.res_ns = MAX(1 * ODP_TIME_MSEC_IN_NS, + timer_capa.highest_res_ns); tparams.min_tmo = 0; tparams.max_tmo = 10000 * ODP_TIME_SEC_IN_NS; tparams.num_timers = num_workers; /* One timer per worker */ diff --git a/example/timer/odp_timer_simple.c b/example/timer/odp_timer_simple.c index 70804bb7..6c76f2a2 100644 --- a/example/timer/odp_timer_simple.c +++ b/example/timer/odp_timer_simple.c @@ -18,6 +18,8 @@ /* ODP main header */ #include <odp_api.h>
+#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) { odp_instance_t instance; @@ -35,6 +37,7 @@ int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) uint64_t tick; odp_timeout_t tmo; int ret = 0; + odp_timer_capability_t timer_capa;
/* * Init ODP app @@ -61,7 +64,12 @@ int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) /* * Create pool of timeouts */ - tparams.res_ns = 10 * ODP_TIME_MSEC_IN_NS; + if (odp_timer_capability(ODP_CLOCK_CPU, &timer_capa)) { + ret += 1; + goto err_tp; + } + tparams.res_ns = MAX(10 * ODP_TIME_MSEC_IN_NS, + timer_capa.highest_res_ns); tparams.min_tmo = 10 * ODP_TIME_MSEC_IN_NS; tparams.max_tmo = 1 * ODP_TIME_SEC_IN_NS; tparams.num_timers = 1; /* One timer per worker */ diff --git a/example/timer/odp_timer_test.c b/example/timer/odp_timer_test.c index 2196b8c1..486227d1 100644 --- a/example/timer/odp_timer_test.c +++ b/example/timer/odp_timer_test.c @@ -23,7 +23,7 @@ #define MAX_WORKERS 32 /**< Max worker threads */ #define NUM_TMOS 10000 /**< Number of timers */ #define WAIT_NUM 10 /**< Max tries to rx last tmo per worker */ - +#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/** Test arguments */ typedef struct { @@ -259,6 +259,7 @@ static void parse_args(int argc, char *argv[], test_args_t *args) { int opt; int long_index; + odp_timer_capability_t timer_capa;
static const struct option longopts[] = { {"count", required_argument, NULL, 'c'}, @@ -277,8 +278,12 @@ static void parse_args(int argc, char *argv[], test_args_t *args) odph_parse_options(argc, argv, shortopts, longopts);
/* defaults */ + odp_timer_capability(ODP_CLOCK_CPU, &timer_capa); + args->cpu_count = 0; /* all CPU's */ - args->resolution_us = 10000; + args->resolution_us = MAX(10000, + timer_capa.highest_res_ns / + ODP_TIME_USEC_IN_NS); args->min_us = 0; args->max_us = 10000000; args->period_us = 1000000; diff --git a/test/common_plat/validation/api/timer/timer.c b/test/common_plat/validation/api/timer/timer.c index 88135160..6c177d4c 100644 --- a/test/common_plat/validation/api/timer/timer.c +++ b/test/common_plat/validation/api/timer/timer.c @@ -20,6 +20,8 @@ #include "test_debug.h" #include "timer.h"
+#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + /** @private Timeout range in milliseconds (ms) */ #define RANGE_MS 2000
@@ -149,6 +151,7 @@ void timer_test_odp_timer_cancel(void) odp_timeout_t tmo; odp_timer_set_t rc; uint64_t tick; + odp_timer_capability_t timer_capa;
odp_pool_param_init(¶ms); params.type = ODP_POOL_TIMEOUT; @@ -159,7 +162,11 @@ void timer_test_odp_timer_cancel(void) if (pool == ODP_POOL_INVALID) CU_FAIL_FATAL("Timeout pool create failed");
- tparam.res_ns = 100 * ODP_TIME_MSEC_IN_NS; + if (odp_timer_capability(ODP_CLOCK_CPU, &timer_capa)) + CU_FAIL_FATAL("Get timer capability failed") + + tparam.res_ns = MAX(100 * ODP_TIME_MSEC_IN_NS, + timer_capa.highest_res_ns); tparam.min_tmo = 1 * ODP_TIME_SEC_IN_NS; tparam.max_tmo = 10 * ODP_TIME_SEC_IN_NS; tparam.num_timers = 1; @@ -506,6 +513,7 @@ void timer_test_odp_timer_all(void) uint64_t ns; uint64_t t2; pthrd_arg thrdarg; + odp_timer_capability_t timer_capa;
/* Reserve at least one core for running other processes so the timer * test hopefully can run undisturbed and thus get better timing @@ -531,12 +539,15 @@ void timer_test_odp_timer_all(void)
#define NAME "timer_pool" #define RES (10 * ODP_TIME_MSEC_IN_NS / 3) -#define MIN (10 * ODP_TIME_MSEC_IN_NS / 3) -#define MAX (1000000 * ODP_TIME_MSEC_IN_NS) +#define MIN_TMO (10 * ODP_TIME_MSEC_IN_NS / 3) +#define MAX_TMO (1000000 * ODP_TIME_MSEC_IN_NS) /* Create a timer pool */ - tparam.res_ns = RES; - tparam.min_tmo = MIN; - tparam.max_tmo = MAX; + if (odp_timer_capability(ODP_CLOCK_CPU, &timer_capa)) + CU_FAIL("Error: get timer capacity failed.\n"); + + tparam.res_ns = MAX(RES, timer_capa.highest_res_ns); + tparam.min_tmo = MIN_TMO; + tparam.max_tmo = MAX_TMO; tparam.num_timers = num_workers * NTIMERS; tparam.priv = 0; tparam.clk_src = ODP_CLOCK_CPU; @@ -550,9 +561,10 @@ void timer_test_odp_timer_all(void) if (odp_timer_pool_info(tp, &tpinfo) != 0) CU_FAIL("odp_timer_pool_info"); CU_ASSERT(strcmp(tpinfo.name, NAME) == 0); - CU_ASSERT(tpinfo.param.res_ns == RES); - CU_ASSERT(tpinfo.param.min_tmo == MIN); - CU_ASSERT(tpinfo.param.max_tmo == MAX); + CU_ASSERT(tpinfo.param.res_ns == MAX(RES, + timer_capa.highest_res_ns)); + CU_ASSERT(tpinfo.param.min_tmo == MIN_TMO); + CU_ASSERT(tpinfo.param.max_tmo == MAX_TMO); CU_ASSERT(strcmp(tpinfo.name, NAME) == 0);
LOG_DBG("Timer pool handle: %" PRIu64 "\n", odp_timer_pool_to_u64(tp));
commit 2e08ac6e40551704c43233b40a9227a19fd4623b Author: Kevin Wang kevin.wang@arm.com Date: Thu Jul 20 11:43:24 2017 +0800
linux-generic: timer: implement odp_timer_capability()
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.wang@arm.com Reviewed-by: Brian Brooks brian.brooks@arm.com Reviewed-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index bf7f1acd..9fc0675d 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -73,6 +73,9 @@ static _odp_atomic_flag_t locks[NUM_LOCKS]; /* Multiple locks per cache line! */ #define IDX2LOCK(idx) (&locks[(idx) % NUM_LOCKS]) #endif
+/* Max timer resolution in nanoseconds */ +static uint64_t highest_res_ns; + /****************************************************************************** * Translation between timeout buffer and timeout header *****************************************************************************/ @@ -192,6 +195,8 @@ 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 +#define TIMER_RES_ROUNDUP_FACTOR 10 static odp_atomic_u32_t num_timer_pools; static odp_timer_pool *timer_pool[MAX_TIMER_POOLS];
@@ -820,6 +825,83 @@ 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 */ + highest_res_ns = 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 */ + highest_res_ns = res; + /* Test the next timer resolution candidate */ + res /= 10; + } + +timer_res_init_done: + highest_res_ns *= TIMER_RES_ROUNDUP_FACTOR; + 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; @@ -877,6 +959,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->highest_res_ns = highest_res_ns; + } 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) @@ -1093,8 +1189,10 @@ int odp_timer_init_global(const odp_init_t *params) time_per_ratelimit_period = odp_time_global_from_ns(CONFIG_TIMER_RUN_RATELIMIT_NS);
- if (!inline_timers) + if (!inline_timers) { + timer_res_init(); block_sigalarm(); + }
return 0; }
commit 5386c44d204f0b42f2773cf87126ff8981bf3270 Author: Kevin Wang kevin.wang@arm.com Date: Thu Jul 20 11:43:23 2017 +0800
api: timer: add odp_timer_capability() api
Currently, user needs to decide the timer resolution before creating a timer pool. But sometimes it will cause timer overrun as the system can't support such high resolution. So a new API is required to expose the timer capability to the user.
Signed-off-by: Kevin Wang kevin.wang@arm.com Reviewed-by: Brian Brooks brian.brooks@arm.com Reviewed-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/api/spec/timer.h b/include/odp/api/spec/timer.h index 75f9db98..b76f5654 100644 --- a/include/odp/api/spec/timer.h +++ b/include/odp/api/spec/timer.h @@ -108,6 +108,33 @@ typedef struct { } odp_timer_pool_param_t;
/** + * Timer capability + */ +typedef struct { + /** Highest timer resolution in nanoseconds. + * + * This defines the highest resolution supported by a timer. + * It's the minimum valid value for 'res_ns' timer pool + * parameter. + */ + uint64_t highest_res_ns; +} odp_timer_capability_t; + +/** + * Query timer capabilities + * + * Outputs timer capabilities on success. + * + * @param clk_src Clock source for timers + * @param[out] capa Pointer to capability structure for output + * + * @retval 0 on success + * @retval <0 on failure + */ +int odp_timer_capability(odp_timer_clk_src_t clk_src, + odp_timer_capability_t *capa); + +/** * Create a timer pool * * The use of pool name is optional. Unique names are not required.
-----------------------------------------------------------------------
Summary of changes: doc/users-guide/users-guide-timer.adoc | 3 +- example/generator/odp_generator.c | 9 ++- example/timer/odp_timer_simple.c | 10 ++- example/timer/odp_timer_test.c | 9 ++- include/odp/api/spec/timer.h | 27 +++++++ platform/linux-generic/odp_timer.c | 100 +++++++++++++++++++++++++- test/common_plat/validation/api/timer/timer.c | 30 +++++--- 7 files changed, 173 insertions(+), 15 deletions(-)
hooks/post-receive