aboutsummaryrefslogtreecommitdiff
path: root/test/validation/api/time/time.c
diff options
context:
space:
mode:
authorMatias Elo <matias.elo@nokia.com>2023-08-08 11:02:27 +0300
committerGitHub <noreply@github.com>2023-08-08 11:02:27 +0300
commitde97121a2e3afa072f7c51a0570f4b3bed0236c2 (patch)
tree1f34d2767951f54d11f0b9c8d48b0db04490d2c1 /test/validation/api/time/time.c
parent2b359fc1759726826cf4e2afddbd0b7e39fab4c7 (diff)
parent1200684b94bf18ae98ba63fb49e9cda546b4832a (diff)
Merge ODP v1.41.1.0v1.41.1.0_DPDK_22.11
Merge ODP linux-generic v1.41.1.0 into linux-dpdk.
Diffstat (limited to 'test/validation/api/time/time.c')
-rw-r--r--test/validation/api/time/time.c263
1 files changed, 246 insertions, 17 deletions
diff --git a/test/validation/api/time/time.c b/test/validation/api/time/time.c
index f285bf8e4..22189ce03 100644
--- a/test/validation/api/time/time.c
+++ b/test/validation/api/time/time.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2015-2018, Linaro Limited
- * Copyright (c) 2019-2022, Nokia
+ * Copyright (c) 2019-2023, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -12,6 +12,7 @@
#include <time.h>
#include <odp_api.h>
+#include <odp/helper/odph_api.h>
#include "odp_cunit_common.h"
#define BUSY_LOOP_CNT 30000000 /* used for t > min resolution */
@@ -19,6 +20,11 @@
#define MAX_TIME_RATE 15000000000
#define DELAY_TOLERANCE 40000000 /* deviation for delay */
#define WAIT_SECONDS 3
+#define MAX_WORKERS 32
+#define TIME_SAMPLES 2
+#define TIME_TOLERANCE_NS 1000000
+#define TIME_TOLERANCE_CI_NS 40000000
+#define GLOBAL_SHM_NAME "GlobalTimeTest"
static uint64_t local_res;
static uint64_t global_res;
@@ -28,6 +34,96 @@ typedef uint64_t time_res_cb(void);
typedef odp_time_t time_from_ns_cb(uint64_t ns);
typedef uint64_t time_nsec_cb(void);
+typedef struct {
+ uint32_t num_threads;
+ odp_barrier_t test_barrier;
+ odp_time_t time[MAX_WORKERS + 1][TIME_SAMPLES];
+} global_shared_mem_t;
+
+static global_shared_mem_t *global_mem;
+static odp_instance_t *instance;
+
+static int time_global_init(odp_instance_t *inst)
+{
+ odp_shm_t global_shm;
+ odp_init_t init_param;
+ odph_helper_options_t helper_options;
+ uint32_t workers_count, max_threads;
+
+ if (odph_options(&helper_options)) {
+ ODPH_ERR("odph_options() failed\n");
+ return -1;
+ }
+
+ odp_init_param_init(&init_param);
+ init_param.mem_model = helper_options.mem_model;
+
+ if (0 != odp_init_global(inst, &init_param, NULL)) {
+ ODPH_ERR("odp_init_global() failed\n");
+ return -1;
+ }
+ if (0 != odp_init_local(*inst, ODP_THREAD_CONTROL)) {
+ ODPH_ERR("odp_init_local() failed\n");
+ return -1;
+ }
+
+ global_shm = odp_shm_reserve(GLOBAL_SHM_NAME,
+ sizeof(global_shared_mem_t),
+ ODP_CACHE_LINE_SIZE, 0);
+ if (global_shm == ODP_SHM_INVALID) {
+ ODPH_ERR("Unable reserve memory for global_shm\n");
+ return -1;
+ }
+
+ global_mem = odp_shm_addr(global_shm);
+ memset(global_mem, 0, sizeof(global_shared_mem_t));
+
+ global_mem->num_threads = MAX_WORKERS;
+
+ workers_count = odp_cpumask_default_worker(NULL, 0);
+
+ max_threads = (workers_count >= MAX_WORKERS) ?
+ MAX_WORKERS : workers_count;
+
+ if (max_threads < global_mem->num_threads) {
+ printf("Requested num of threads is too large\n");
+ printf("reducing from %" PRIu32 " to %" PRIu32 "\n",
+ global_mem->num_threads,
+ max_threads);
+ global_mem->num_threads = max_threads;
+ }
+
+ printf("Num of threads used = %" PRIu32 "\n",
+ global_mem->num_threads);
+
+ instance = inst;
+
+ return 0;
+}
+
+static int time_global_term(odp_instance_t inst)
+{
+ odp_shm_t shm;
+
+ shm = odp_shm_lookup(GLOBAL_SHM_NAME);
+ if (0 != odp_shm_free(shm)) {
+ ODPH_ERR("odp_shm_free() failed\n");
+ return -1;
+ }
+
+ if (0 != odp_term_local()) {
+ ODPH_ERR("odp_term_local() failed\n");
+ return -1;
+ }
+
+ if (0 != odp_term_global(inst)) {
+ ODPH_ERR("odp_term_global() failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
static void time_test_constants(void)
{
uint64_t ns;
@@ -423,16 +519,14 @@ static void time_test_wait_until(time_cb time_cur, time_from_ns_cb time_from_ns)
DELAY_TOLERANCE);
if (odp_time_cmp(wait, lower_limit) < 0) {
- fprintf(stderr, "Exceed lower limit: "
- "wait is %" PRIu64 ", lower_limit %" PRIu64 "\n",
- odp_time_to_ns(wait), odp_time_to_ns(lower_limit));
+ ODPH_ERR("Exceed lower limit: wait is %" PRIu64 ", lower_limit %" PRIu64 "\n",
+ odp_time_to_ns(wait), odp_time_to_ns(lower_limit));
CU_FAIL("Exceed lower limit\n");
}
if (odp_time_cmp(wait, upper_limit) > 0) {
- fprintf(stderr, "Exceed upper limit: "
- "wait is %" PRIu64 ", upper_limit %" PRIu64 "\n",
- odp_time_to_ns(wait), odp_time_to_ns(lower_limit));
+ ODPH_ERR("Exceed upper limit: wait is %" PRIu64 ", upper_limit %" PRIu64 "\n",
+ odp_time_to_ns(wait), odp_time_to_ns(lower_limit));
CU_FAIL("Exceed upper limit\n");
}
}
@@ -466,16 +560,14 @@ static void time_test_wait_ns(void)
DELAY_TOLERANCE);
if (odp_time_cmp(diff, lower_limit) < 0) {
- fprintf(stderr, "Exceed lower limit: "
- "diff is %" PRIu64 ", lower_limit %" PRIu64 "\n",
- odp_time_to_ns(diff), odp_time_to_ns(lower_limit));
+ ODPH_ERR("Exceed lower limit: diff is %" PRIu64 ", lower_limit %" PRIu64 "\n",
+ odp_time_to_ns(diff), odp_time_to_ns(lower_limit));
CU_FAIL("Exceed lower limit\n");
}
if (odp_time_cmp(diff, upper_limit) > 0) {
- fprintf(stderr, "Exceed upper limit: "
- "diff is %" PRIu64 ", upper_limit %" PRIu64 "\n",
- odp_time_to_ns(diff), odp_time_to_ns(upper_limit));
+ ODPH_ERR("Exceed upper limit: diff is %" PRIu64 ", upper_limit %" PRIu64 "\n",
+ odp_time_to_ns(diff), odp_time_to_ns(upper_limit));
CU_FAIL("Exceed upper limit\n");
}
}
@@ -486,13 +578,13 @@ static void check_time_diff(double t_odp, double t_system,
{
if (t_odp > t_system * 1.05) {
CU_FAIL("ODP time too high");
- fprintf(stderr, "ODP time too high (%s/%d): t_odp: %f, t_system: %f\n",
- test, id, t_odp, t_system);
+ ODPH_ERR("ODP time too high (%s/%d): t_odp: %f, t_system: %f\n",
+ test, id, t_odp, t_system);
}
if (t_odp < t_system * 0.95) {
CU_FAIL("ODP time too low");
- fprintf(stderr, "ODP time too low (%s/%d): t_odp: %f, t_system: %f\n",
- test, id, t_odp, t_system);
+ ODPH_ERR("ODP time too low (%s/%d): t_odp: %f, t_system: %f\n",
+ test, id, t_odp, t_system);
}
}
@@ -589,6 +681,138 @@ static void time_test_accuracy_nsec(void)
}
}
+static int time_test_global_sync_thr(void *arg ODP_UNUSED)
+{
+ int tid = odp_thread_id();
+ odp_shm_t global_shm = odp_shm_lookup(GLOBAL_SHM_NAME);
+ global_shared_mem_t *global_mem = odp_shm_addr(global_shm);
+
+ if (!global_mem)
+ return 1;
+
+ odp_barrier_wait(&global_mem->test_barrier);
+ global_mem->time[tid][0] = odp_time_global();
+ odp_time_wait_ns(ODP_TIME_MSEC_IN_NS * 100);
+ odp_barrier_wait(&global_mem->test_barrier);
+ global_mem->time[tid][1] = odp_time_global();
+
+ return 0;
+}
+
+static void time_test_global_sync(const int ctrl)
+{
+ odp_cpumask_t cpumask;
+ odph_thread_common_param_t thr_common;
+ odph_thread_param_t thr_param;
+ odph_thread_t thread_tbl[MAX_WORKERS];
+ const uint64_t tolerance =
+ odp_cunit_ci() ? TIME_TOLERANCE_CI_NS : TIME_TOLERANCE_NS;
+ const int num = ctrl ? 2 : global_mem->num_threads;
+
+ if (num < 2) {
+ printf(" number of threads is less than two, test skipped. ");
+ return;
+ }
+
+ odp_barrier_init(&global_mem->test_barrier, num);
+
+ odph_thread_param_init(&thr_param);
+ thr_param.start = time_test_global_sync_thr;
+
+ odph_thread_common_param_init(&thr_common);
+ thr_common.instance = *instance;
+
+ int thr = 0;
+
+ if (ctrl) {
+ /* Test sync between one control and one worker thread. */
+ odp_cpumask_default_control(&cpumask, 1);
+ thr_common.cpumask = &cpumask;
+ thr_param.thr_type = ODP_THREAD_CONTROL;
+
+ int r = odph_thread_create(&thread_tbl[thr++],
+ &thr_common, &thr_param, 1);
+ CU_ASSERT_FATAL(r == 1);
+ odp_cpumask_default_worker(&cpumask, 1);
+ } else {
+ /* Test sync between num worker threads. */
+ odp_cpumask_default_worker(&cpumask, num);
+ }
+
+ int cpu = odp_cpumask_first(&cpumask);
+
+ while (cpu >= 0) {
+ odp_cpumask_t cpumask_one;
+
+ /*
+ * Delay for more than the tolerance, so that we notice if the
+ * thread's view of global time is affected.
+ */
+ odp_time_wait_ns(tolerance * 2);
+
+ odp_cpumask_zero(&cpumask_one);
+ odp_cpumask_set(&cpumask_one, cpu);
+ thr_common.cpumask = &cpumask_one;
+ thr_param.thr_type = ODP_THREAD_WORKER;
+
+ int r = odph_thread_create(&thread_tbl[thr++],
+ &thr_common, &thr_param, 1);
+ CU_ASSERT_FATAL(r == 1);
+
+ cpu = odp_cpumask_next(&cpumask, cpu);
+ }
+
+ CU_ASSERT(odph_thread_join(thread_tbl, num) == num);
+
+ for (int s = 0; s < TIME_SAMPLES; s++) {
+ int min_idx = 0, max_idx = 0;
+ uint64_t min = UINT64_MAX, max = 0;
+ double avg = 0;
+
+ for (int i = 1; i < num + 1; i++) {
+ uint64_t t = odp_time_to_ns(global_mem->time[i][s]);
+
+ if (t < min) {
+ min = t;
+ min_idx = i;
+ }
+ }
+
+ printf("\nround %d\nthread time diffs: ", s);
+
+ for (int i = 1; i < num + 1; i++) {
+ uint64_t t = odp_time_to_ns(global_mem->time[i][s]) - min;
+
+ printf("%" PRIu64 " ", t);
+
+ if (t > max) {
+ max = t;
+ max_idx = i;
+ }
+
+ avg += t;
+ }
+
+ /* The min result itself is not included in the average. */
+ avg /= num - 1;
+ printf("\nmin: %" PRIu64 " (tid %d) max diff: %" PRIu64
+ " (tid %d) avg diff: %g", min, min_idx, max, max_idx, avg);
+ CU_ASSERT(max < tolerance);
+ }
+
+ printf("\n");
+}
+
+static void time_test_global_sync_workers(void)
+{
+ time_test_global_sync(0);
+}
+
+static void time_test_global_sync_control(void)
+{
+ time_test_global_sync(1);
+}
+
odp_testinfo_t time_suite_time[] = {
ODP_TEST_INFO(time_test_constants),
ODP_TEST_INFO(time_test_local_res),
@@ -614,6 +838,8 @@ odp_testinfo_t time_suite_time[] = {
ODP_TEST_INFO(time_test_global_strict_diff),
ODP_TEST_INFO(time_test_global_strict_sum),
ODP_TEST_INFO(time_test_global_strict_cmp),
+ ODP_TEST_INFO(time_test_global_sync_workers),
+ ODP_TEST_INFO(time_test_global_sync_control),
ODP_TEST_INFO_NULL
};
@@ -630,6 +856,9 @@ int main(int argc, char *argv[])
if (odp_cunit_parse_options(argc, argv))
return -1;
+ odp_cunit_register_global_init(time_global_init);
+ odp_cunit_register_global_term(time_global_term);
+
ret = odp_cunit_register(time_suites);
if (ret == 0)