@@ -34,6 +34,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))
@@ -638,6 +639,7 @@ int main(int argc, char *argv[])
odp_pktio_t *pktio;
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)) {
@@ -718,7 +720,11 @@ 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.res_ns);
tparams.min_tmo = 0;
tparams.max_tmo = 10000 * ODP_TIME_SEC_IN_NS;
tparams.num_timers = num_workers; /* One timer per worker */
@@ -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,11 @@ 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.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 */
@@ -23,6 +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 */
@@ -259,6 +260,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 +279,10 @@ 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.res_ns/ODP_TIME_USEC_IN_NS);
args->min_us = 0;
args->max_us = 10000000;
args->period_us = 1000000;
@@ -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,80 @@ 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 +873,18 @@ 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 +1093,8 @@ int odp_timer_init_global(void)
#endif
odp_atomic_init_u32(&num_timer_pools, 0);
+ timer_res_init();
+
block_sigalarm();
return 0;
@@ -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
@@ -140,6 +142,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;
@@ -150,7 +153,10 @@ 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.res_ns);
tparam.min_tmo = 1 * ODP_TIME_SEC_IN_NS;
tparam.max_tmo = 10 * ODP_TIME_SEC_IN_NS;
tparam.num_timers = 1;
@@ -480,6 +486,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
@@ -505,12 +512,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.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;
@@ -524,9 +534,9 @@ 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.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));