Changeset 5d230a30 in mainline


Ignore:
Timestamp:
2012-11-24T02:11:38Z (11 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
69146b93
Parents:
3ac5086
Message:

urcu: Added stress test checking for premature exits of rcu_sync via sequence numbers.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/rcutest/rcutest.c

    r3ac5086 r5d230a30  
    4444#include <async.h>
    4545#include <fibril.h>
     46#include <fibril_synch.h>
    4647#include <compiler/barrier.h>
     48#include <futex.h>
    4749
    4850#include <rcu.h>
    4951
    50 #include "fibril_synch.h"
    5152
    5253
     
    8687static bool dont_wait_for_new_reader(struct test_info*);
    8788static bool wait_for_exiting_reader(struct test_info*);
     89static bool seq_test(struct test_info*);
     90
    8891
    8992static test_desc_t test_desc[] = {
     
    140143        {
    141144                .aggregate = false,
     145                .type = T_STRESS,
     146                .func = seq_test,
     147                .name = "seq",
     148                .desc = "Checks lock/unlock/sync w/ global time sequence.",
     149        },
     150        {
     151                .aggregate = false,
    142152                .type = T_OTHER,
    143153                .func = NULL,
     
    150160
    151161/*--------------------------------------------------------------------*/
     162
     163static size_t next_rand(size_t seed)
     164{
     165        return (seed * 1103515245 + 12345) & ((1U << 31) - 1);
     166}
     167
    152168
    153169typedef int (*fibril_func_t)(void *);
     
    600616/*--------------------------------------------------------------------*/
    601617
     618typedef struct {
     619        atomic_t time;
     620        atomic_t max_start_time_of_done_sync;
     621       
     622        size_t total_workers;
     623        size_t done_reader_cnt;
     624        size_t done_updater_cnt;
     625        fibril_mutex_t done_cnt_mtx;
     626        fibril_condvar_t done_cnt_changed;
     627
     628        size_t read_iters;
     629        size_t upd_iters;
     630       
     631        atomic_t seed;
     632        int failed;
     633} seq_test_info_t;
     634
     635
     636static void signal_seq_fibril_done(seq_test_info_t *arg, size_t *cnt)
     637{
     638        fibril_mutex_lock(&arg->done_cnt_mtx);
     639        ++*cnt;
     640       
     641        if (arg->total_workers == arg->done_reader_cnt + arg->done_updater_cnt) {
     642                fibril_condvar_signal(&arg->done_cnt_changed);
     643        }
     644       
     645        fibril_mutex_unlock(&arg->done_cnt_mtx);
     646}
     647
     648static int seq_reader(seq_test_info_t *arg)
     649{
     650        rcu_register_fibril();
     651       
     652        size_t seed = (size_t) atomic_preinc(&arg->seed);
     653        bool first = (seed == 1);
     654       
     655        for (size_t k = 0; k < arg->read_iters; ++k) {
     656                /* Print progress if the first reader fibril. */
     657                if (first && 0 == k % (arg->read_iters/100 + 1)) {
     658                        printf(".");
     659                }
     660               
     661                rcu_read_lock();
     662                atomic_count_t start_time = atomic_preinc(&arg->time);
     663               
     664                /* Do some work. */
     665                seed = next_rand(seed);
     666                size_t idle_iters = seed % 8;
     667               
     668                for (size_t i = 0; i < idle_iters; ++i) {
     669                        fibril_yield();
     670                }
     671               
     672                /*
     673                 * Check if the most recently started rcu_sync of the already
     674                 * finished rcu_syncs did not happen to start after this reader
     675                 * and, therefore, should have waited for this reader to exit
     676                 * (but did not - since it already announced it completed).
     677                 */
     678                if (start_time <= atomic_get(&arg->max_start_time_of_done_sync)) {
     679                        arg->failed = 1;
     680                }
     681               
     682                rcu_read_unlock();
     683        }
     684       
     685        rcu_deregister_fibril();
     686
     687        signal_seq_fibril_done(arg, &arg->done_reader_cnt);
     688        return 0;
     689}
     690
     691static int seq_updater(seq_test_info_t *arg)
     692{
     693        rcu_register_fibril();
     694       
     695        for (size_t k = 0; k < arg->upd_iters; ++k) {
     696                atomic_count_t start_time = atomic_get(&arg->time);
     697                rcu_synchronize();
     698               
     699                /* This is prone to a race but if it happens it errs to the safe side.*/
     700                if (atomic_get(&arg->max_start_time_of_done_sync) < start_time) {
     701                        atomic_set(&arg->max_start_time_of_done_sync, start_time);
     702                }
     703        }
     704       
     705        rcu_deregister_fibril();
     706       
     707        signal_seq_fibril_done(arg, &arg->done_updater_cnt);
     708        return 0;
     709}
     710
     711static bool seq_test(test_info_t *test_info)
     712{
     713        size_t reader_cnt = test_info->thread_cnt;
     714        size_t updater_cnt = test_info->thread_cnt;
     715               
     716        seq_test_info_t info = {
     717                .time = {0},
     718                .max_start_time_of_done_sync = {0},
     719                .read_iters = 10 * 1000,
     720                .upd_iters = 5 * 1000,
     721                .total_workers = updater_cnt + reader_cnt,
     722                .done_reader_cnt = 0,
     723                .done_updater_cnt = 0,
     724                .done_cnt_mtx = FIBRIL_MUTEX_INITIALIZER(info.done_cnt_mtx),
     725                .done_cnt_changed = FIBRIL_CONDVAR_INITIALIZER(info.done_cnt_changed),
     726                .seed = {0},
     727                .failed = 0,
     728        };
     729       
     730        /* Create and start worker fibrils. */
     731        for (size_t k = 0; k + k < reader_cnt + updater_cnt; ++k) {
     732                bool ok = create_fibril((fibril_func_t) seq_reader, &info);
     733                ok = ok && create_fibril((fibril_func_t) seq_updater, &info);
     734               
     735                if (!ok) {
     736                        /* Let the already created fibrils corrupt the stack. */
     737                        return false;
     738                }
     739        }
     740       
     741        /* Wait for all worker fibrils to complete their work. */
     742        fibril_mutex_lock(&info.done_cnt_mtx);
     743       
     744        while (info.total_workers != info.done_reader_cnt + info.done_updater_cnt) {
     745                fibril_condvar_wait(&info.done_cnt_changed, &info.done_cnt_mtx);
     746        }
     747       
     748        fibril_mutex_unlock(&info.done_cnt_mtx);
     749       
     750        if (info.failed) {
     751                printf("Error: rcu_sync() did not wait for a preexisting reader.");
     752        }
     753       
     754        return 0 == info.failed;
     755}
     756
     757/*--------------------------------------------------------------------*/
     758
    602759static FIBRIL_MUTEX_INITIALIZE(blocking_mtx);
    603760
     
    712869                        printf("Err: Invalid number of threads '%s'; using 1.\n", argv[2]);
    713870                }
     871        } else {
     872                info->thread_cnt = 1;
    714873        }
    715874       
Note: See TracChangeset for help on using the changeset viewer.