ping On 21 April 2016 at 15:32, Christophe Milard <christophe.mil...@linaro.org> wrote:
> fixing: https://bugs.linaro.org/show_bug.cgi?id=2108 > > The no_lock_functional_test does not really tests the ODP functionality: > Instead, it actually checks that race conditions can be created between > concurrent running threads (by making these threads writing shared > variables without lock, and later noting the value written was changed by > some of the concurrent threads). > This test therefore validates other tests: if this test passes -i.e. if > we do have race condition- then if the following tests suppress these > race conditions by using some synchronization mechanism, these > synchronization mechanisms can be said to be efficient. > If, on the other hand, the no_lock_functional_test "fails", it says > that the following tests are really inconclusive as the effect of the > tested synchronization mechanism is not proven. > > When running with valgrind, no_lock_functional_test failed, probably > because the extra execution time introduced by valgrind itself made > the chance to run the critical section of the different threads "at > the same time" much less probable. > > The simple solution is to increase the critical section running time > (by largely increasing the number of iterations performed). > The solution taken here is actually to tune the critical section running > time (currentely to ITER_MPLY_FACTOR=3 times the time needed to note > the first race condition). > This means that the test will take longer to run with valgrind, > but will remain short without valgrind. > > Signed-off-by: Christophe Milard <christophe.mil...@linaro.org> > --- > test/validation/lock/lock.c | 71 > ++++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 64 insertions(+), 7 deletions(-) > > diff --git a/test/validation/lock/lock.c b/test/validation/lock/lock.c > index f1f6d69..515bc77 100644 > --- a/test/validation/lock/lock.c > +++ b/test/validation/lock/lock.c > @@ -12,7 +12,10 @@ > #include "lock.h" > > #define VERBOSE 0 > -#define MAX_ITERATIONS 1000 > + > +#define MIN_ITERATIONS 1000 > +#define MAX_ITERATIONS 30000 > +#define ITER_MPLY_FACTOR 3 > > #define SLOW_BARRIER_DELAY 400 > #define BASE_DELAY 6 > @@ -325,6 +328,12 @@ static void *rwlock_recursive_api_tests(void *arg > UNUSED) > return NULL; > } > > +/* > + * Tests that we do have contention between threads when running. > + * Also adjust the number of iterations to be done (by other tests) > + * so we have a fair chance to see that the tested synchronizer > + * does avoid the race condition. > + */ > static void *no_lock_functional_test(void *arg UNUSED) > { > global_shared_mem_t *global_mem; > @@ -335,17 +344,36 @@ static void *no_lock_functional_test(void *arg > UNUSED) > thread_num = odp_cpu_id() + 1; > per_thread_mem = thread_init(); > global_mem = per_thread_mem->global_mem; > - iterations = global_mem->g_iterations; > + iterations = 0; > > odp_barrier_wait(&global_mem->global_barrier); > > sync_failures = 0; > current_errs = 0; > rs_idx = 0; > - resync_cnt = iterations / NUM_RESYNC_BARRIERS; > + resync_cnt = MAX_ITERATIONS / NUM_RESYNC_BARRIERS; > lock_owner_delay = BASE_DELAY; > > - for (cnt = 1; cnt <= iterations; cnt++) { > + /* > + * Tunning the iteration number: > + * Here, we search for an iteration number that guarantees to show > + * race conditions between the odp threads. > + * Iterations is set to ITER_MPLY_FACTOR * cnt where cnt is when > + * the threads start to see "errors" (i.e. effect of other threads > + * running concurrentely without any synchronisation mechanism). > + * In other words, "iterations" is set to ITER_MPLY_FACTOR times the > + * minimum loop count necessary to see a need for synchronisation > + * mechanism. > + * If, later, these "errors" disappear when running other tests up > to > + * "iterations" with synchro, the effect of the tested synchro > mechanism > + * is likely proven. > + * If we reach "MAX_ITERATIONS", and "iteration" remains zero, > + * it means that we cannot see any race condition between the > different > + * running theads (e.g. the OS is not preemptive) and all other > tests > + * being passed won't tell much about the functionality of the > + * tested synchro mechanism. > + */ > + for (cnt = 1; cnt <= MAX_ITERATIONS; cnt++) { > global_mem->global_lock_owner = thread_num; > odp_mb_full(); > thread_delay(per_thread_mem, lock_owner_delay); > @@ -353,6 +381,8 @@ static void *no_lock_functional_test(void *arg UNUSED) > if (global_mem->global_lock_owner != thread_num) { > current_errs++; > sync_failures++; > + if (!iterations) > + iterations = cnt; > } > > global_mem->global_lock_owner = 0; > @@ -362,6 +392,8 @@ static void *no_lock_functional_test(void *arg UNUSED) > if (global_mem->global_lock_owner == thread_num) { > current_errs++; > sync_failures++; > + if (!iterations) > + iterations = cnt; > } > > if (current_errs == 0) > @@ -392,6 +424,31 @@ static void *no_lock_functional_test(void *arg UNUSED) > */ > CU_ASSERT(sync_failures != 0 || global_mem->g_num_threads == 1); > > + /* > + * set the iterration for the future tests to be far above the > + * contention level > + */ > + iterations *= ITER_MPLY_FACTOR; > + > + if (iterations > MAX_ITERATIONS) > + iterations = MAX_ITERATIONS; > + if (iterations < MIN_ITERATIONS) > + iterations = MIN_ITERATIONS; > + > + /* > + * Note that the following statement has race conditions: > + * global_mem->g_iterations should really be an atomic and a TAS > + * function be used. But this would mean that we would be testing > + * synchronisers assuming synchronisers works... > + * If we do not use atomic TAS, we may not get the grand max for > + * all threads, but we are guaranteed to have passed the error > + * threshold, for at least some threads, which is good enough > + */ > + if (iterations > global_mem->g_iterations) > + global_mem->g_iterations = iterations; > + > + odp_mb_full(); > + > thread_finalize(per_thread_mem); > > return NULL; > @@ -910,7 +967,7 @@ void lock_test_no_lock_functional(void) > } > > odp_testinfo_t lock_suite_no_locking[] = { > - ODP_TEST_INFO(lock_test_no_lock_functional), > + ODP_TEST_INFO(lock_test_no_lock_functional), /* must be first */ > ODP_TEST_INFO_NULL > }; > > @@ -1082,7 +1139,7 @@ int lock_init(void) > memset(global_mem, 0, sizeof(global_shared_mem_t)); > > global_mem->g_num_threads = MAX_WORKERS; > - global_mem->g_iterations = MAX_ITERATIONS; > + global_mem->g_iterations = 0; /* tuned by first test */ > global_mem->g_verbose = VERBOSE; > > workers_count = odp_cpumask_default_worker(&mask, 0); > @@ -1106,7 +1163,7 @@ int lock_init(void) > > odp_suiteinfo_t lock_suites[] = { > {"nolocking", lock_suite_init, NULL, > - lock_suite_no_locking}, > + lock_suite_no_locking}, /* must be first */ > {"spinlock", lock_suite_init, NULL, > lock_suite_spinlock}, > {"spinlock_recursive", lock_suite_init, NULL, > -- > 2.1.4 > >
_______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp