From cd5b318daf4aecd249c3f07df93700c0f749484c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 20 Nov 2015 18:17:17 +0100 Subject: rhashtable-test: add cond_resched() to thread test This should fix for soft lockup bugs triggered on slow systems. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- lib/test_rhashtable.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c index 8c1ad1ced72c..63654e359256 100644 --- a/lib/test_rhashtable.c +++ b/lib/test_rhashtable.c @@ -236,6 +236,8 @@ static int thread_lookup_test(struct thread_data *tdata) obj->value, key); err++; } + + cond_resched(); } return err; } @@ -251,6 +253,7 @@ static int threadfunc(void *data) for (i = 0; i < entries; i++) { tdata->objs[i].value = (tdata->id << 16) | i; + cond_resched(); err = rhashtable_insert_fast(&ht, &tdata->objs[i].node, test_rht_params); if (err == -ENOMEM || err == -EBUSY) { @@ -285,6 +288,8 @@ static int threadfunc(void *data) goto out; } tdata->objs[i].value = TEST_INSERT_FAIL; + + cond_resched(); } err = thread_lookup_test(tdata); if (err) { -- cgit v1.2.3 From 9e9089e5a2d788db417d4d1f836eecc2fc44e9ff Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 20 Nov 2015 18:17:18 +0100 Subject: rhashtable-test: retry insert operations After adding cond_resched() calls to threadfunc(), a surprisingly high rate of insert failures occurred probably due to table resizes getting a better chance to run in background. To not soften up the remaining tests, retry inserts until they either succeed or fail permanently. Also change the non-threaded test to retry insert operations, too. Suggested-by: Thomas Graf Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- lib/test_rhashtable.c | 53 ++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c index 63654e359256..cfc3440f17e7 100644 --- a/lib/test_rhashtable.c +++ b/lib/test_rhashtable.c @@ -76,6 +76,20 @@ static struct rhashtable_params test_rht_params = { static struct semaphore prestart_sem; static struct semaphore startup_sem = __SEMAPHORE_INITIALIZER(startup_sem, 0); +static int insert_retry(struct rhashtable *ht, struct rhash_head *obj, + const struct rhashtable_params params) +{ + int err, retries = -1; + + do { + retries++; + cond_resched(); + err = rhashtable_insert_fast(ht, obj, params); + } while (err == -EBUSY); + + return err ? : retries; +} + static int __init test_rht_lookup(struct rhashtable *ht) { unsigned int i; @@ -157,7 +171,7 @@ static s64 __init test_rhashtable(struct rhashtable *ht) { struct test_obj *obj; int err; - unsigned int i, insert_fails = 0; + unsigned int i, insert_retries = 0; s64 start, end; /* @@ -170,22 +184,16 @@ static s64 __init test_rhashtable(struct rhashtable *ht) struct test_obj *obj = &array[i]; obj->value = i * 2; - - err = rhashtable_insert_fast(ht, &obj->node, test_rht_params); - if (err == -ENOMEM || err == -EBUSY) { - /* Mark failed inserts but continue */ - obj->value = TEST_INSERT_FAIL; - insert_fails++; - } else if (err) { + err = insert_retry(ht, &obj->node, test_rht_params); + if (err > 0) + insert_retries += err; + else if (err) return err; - } - - cond_resched(); } - if (insert_fails) - pr_info(" %u insertions failed due to memory pressure\n", - insert_fails); + if (insert_retries) + pr_info(" %u insertions retried due to memory pressure\n", + insert_retries); test_bucket_stats(ht); rcu_read_lock(); @@ -244,7 +252,7 @@ static int thread_lookup_test(struct thread_data *tdata) static int threadfunc(void *data) { - int i, step, err = 0, insert_fails = 0; + int i, step, err = 0, insert_retries = 0; struct thread_data *tdata = data; up(&prestart_sem); @@ -253,21 +261,18 @@ static int threadfunc(void *data) for (i = 0; i < entries; i++) { tdata->objs[i].value = (tdata->id << 16) | i; - cond_resched(); - err = rhashtable_insert_fast(&ht, &tdata->objs[i].node, - test_rht_params); - if (err == -ENOMEM || err == -EBUSY) { - tdata->objs[i].value = TEST_INSERT_FAIL; - insert_fails++; + err = insert_retry(&ht, &tdata->objs[i].node, test_rht_params); + if (err > 0) { + insert_retries += err; } else if (err) { pr_err(" thread[%d]: rhashtable_insert_fast failed\n", tdata->id); goto out; } } - if (insert_fails) - pr_info(" thread[%d]: %d insert failures\n", - tdata->id, insert_fails); + if (insert_retries) + pr_info(" thread[%d]: %u insertions retried due to memory pressure\n", + tdata->id, insert_retries); err = thread_lookup_test(tdata); if (err) { -- cgit v1.2.3 From 95e435afefe98b8ef6ae8b764879a064cd931a5c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 20 Nov 2015 18:17:19 +0100 Subject: rhashtable-test: calculate max_entries value by default A maximum table size of 64k entries is insufficient for the multiple threads test even in default configuration (10 threads * 50000 objects = 500000 objects in total). Since we know how many objects will be inserted, calculate the max size unless overridden by parameter. Note that specifying the exact number of objects upon table init won't suffice as that value is being rounded down to the next power of two - anticipate this by rounding up to the next power of two in beforehand. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- lib/test_rhashtable.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c index cfc3440f17e7..6fa77b3f0e80 100644 --- a/lib/test_rhashtable.c +++ b/lib/test_rhashtable.c @@ -36,9 +36,9 @@ static int runs = 4; module_param(runs, int, 0); MODULE_PARM_DESC(runs, "Number of test runs per variant (default: 4)"); -static int max_size = 65536; +static int max_size = 0; module_param(max_size, int, 0); -MODULE_PARM_DESC(runs, "Maximum table size (default: 65536)"); +MODULE_PARM_DESC(runs, "Maximum table size (default: calculated)"); static bool shrinking = false; module_param(shrinking, bool, 0); @@ -321,7 +321,7 @@ static int __init test_rht_init(void) entries = min(entries, MAX_ENTRIES); test_rht_params.automatic_shrinking = shrinking; - test_rht_params.max_size = max_size; + test_rht_params.max_size = max_size ? : roundup_pow_of_two(entries); test_rht_params.nelem_hint = size; pr_info("Running rhashtable test nelem=%d, max_size=%d, shrinking=%d\n", @@ -367,6 +367,8 @@ static int __init test_rht_init(void) return -ENOMEM; } + test_rht_params.max_size = max_size ? : + roundup_pow_of_two(tcount * entries); err = rhashtable_init(&ht, &test_rht_params); if (err < 0) { pr_warn("Test failed: Unable to initialize hashtable: %d\n", -- cgit v1.2.3 From d662e037fc88b187494a95b5bc19b3c0e9b9ea36 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 20 Nov 2015 18:17:20 +0100 Subject: rhashtable-test: allow to retry even if -ENOMEM was returned This is rather a hack to expose the current issue with rhashtable to under high pressure sometimes return -ENOMEM even though system memory is not exhausted and a consecutive insert may succeed. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- lib/test_rhashtable.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c index 6fa77b3f0e80..270bf7289b1e 100644 --- a/lib/test_rhashtable.c +++ b/lib/test_rhashtable.c @@ -52,6 +52,10 @@ static int tcount = 10; module_param(tcount, int, 0); MODULE_PARM_DESC(tcount, "Number of threads to spawn (default: 10)"); +static bool enomem_retry = false; +module_param(enomem_retry, bool, 0); +MODULE_PARM_DESC(enomem_retry, "Retry insert even if -ENOMEM was returned (default: off)"); + struct test_obj { int value; struct rhash_head node; @@ -79,14 +83,22 @@ static struct semaphore startup_sem = __SEMAPHORE_INITIALIZER(startup_sem, 0); static int insert_retry(struct rhashtable *ht, struct rhash_head *obj, const struct rhashtable_params params) { - int err, retries = -1; + int err, retries = -1, enomem_retries = 0; do { retries++; cond_resched(); err = rhashtable_insert_fast(ht, obj, params); + if (err == -ENOMEM && enomem_retry) { + enomem_retries++; + err = -EBUSY; + } } while (err == -EBUSY); + if (enomem_retries) + pr_info(" %u insertions retried after -ENOMEM\n", + enomem_retries); + return err ? : retries; } -- cgit v1.2.3