aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2015-04-30 18:37:41 -0400
committerDavid S. Miller <davem@davemloft.net>2015-05-03 23:08:53 -0400
commit1aa661f5c3df15432530f01f1023d556fa81b95d (patch)
tree55a7bdd26921f3c58159358c0fdea130721c82d6 /lib
parentf54e84b6e9f07a93a5f27f55bf28982c06f45109 (diff)
rhashtable-test: Measure time to insert, remove & traverse entries
Make test configurable by allowing to specify all relevant knobs through module parameters. Do several test runs and measure the average time it takes to insert & remove all entries. Note, a deferred resize might still continue to run in the background. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/test_rhashtable.c100
1 files changed, 69 insertions, 31 deletions
diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c
index c60fd5d9eb6b..e3d31bf527a9 100644
--- a/lib/test_rhashtable.c
+++ b/lib/test_rhashtable.c
@@ -1,14 +1,9 @@
1/* 1/*
2 * Resizable, Scalable, Concurrent Hash Table 2 * Resizable, Scalable, Concurrent Hash Table
3 * 3 *
4 * Copyright (c) 2014 Thomas Graf <tgraf@suug.ch> 4 * Copyright (c) 2014-2015 Thomas Graf <tgraf@suug.ch>
5 * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net> 5 * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net>
6 * 6 *
7 * Based on the following paper:
8 * https://www.usenix.org/legacy/event/atc11/tech/final_files/Triplett.pdf
9 *
10 * Code partially derived from nft_hash
11 *
12 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
@@ -27,9 +22,28 @@
27#include <linux/slab.h> 22#include <linux/slab.h>
28 23
29 24
30#define TEST_HT_SIZE 8
31#define TEST_ENTRIES 2048
32#define TEST_PTR ((void *) 0xdeadbeef) 25#define TEST_PTR ((void *) 0xdeadbeef)
26#define MAX_ENTRIES 1000000
27
28static int entries = 50000;
29module_param(entries, int, 0);
30MODULE_PARM_DESC(entries, "Number of entries to add (default: 50000)");
31
32static int runs = 4;
33module_param(runs, int, 0);
34MODULE_PARM_DESC(runs, "Number of test runs per variant (default: 4)");
35
36static int max_size = 65536;
37module_param(max_size, int, 0);
38MODULE_PARM_DESC(runs, "Maximum table size (default: 65536)");
39
40static bool shrinking = false;
41module_param(shrinking, bool, 0);
42MODULE_PARM_DESC(shrinking, "Enable automatic shrinking (default: off)");
43
44static int size = 8;
45module_param(size, int, 0);
46MODULE_PARM_DESC(size, "Initial size hint of table (default: 8)");
33 47
34struct test_obj { 48struct test_obj {
35 void *ptr; 49 void *ptr;
@@ -37,8 +51,7 @@ struct test_obj {
37 struct rhash_head node; 51 struct rhash_head node;
38}; 52};
39 53
40static const struct rhashtable_params test_rht_params = { 54static struct rhashtable_params test_rht_params = {
41 .nelem_hint = TEST_HT_SIZE,
42 .head_offset = offsetof(struct test_obj, node), 55 .head_offset = offsetof(struct test_obj, node),
43 .key_offset = offsetof(struct test_obj, value), 56 .key_offset = offsetof(struct test_obj, value),
44 .key_len = sizeof(int), 57 .key_len = sizeof(int),
@@ -50,7 +63,7 @@ static int __init test_rht_lookup(struct rhashtable *ht)
50{ 63{
51 unsigned int i; 64 unsigned int i;
52 65
53 for (i = 0; i < TEST_ENTRIES * 2; i++) { 66 for (i = 0; i < entries * 2; i++) {
54 struct test_obj *obj; 67 struct test_obj *obj;
55 bool expected = !(i % 2); 68 bool expected = !(i % 2);
56 u32 key = i; 69 u32 key = i;
@@ -110,26 +123,28 @@ static void test_bucket_stats(struct rhashtable *ht, bool quiet)
110 } 123 }
111 124
112 pr_info(" Traversal complete: counted=%u, nelems=%u, entries=%d\n", 125 pr_info(" Traversal complete: counted=%u, nelems=%u, entries=%d\n",
113 total, atomic_read(&ht->nelems), TEST_ENTRIES); 126 total, atomic_read(&ht->nelems), entries);
114 127
115 if (total != atomic_read(&ht->nelems) || total != TEST_ENTRIES) 128 if (total != atomic_read(&ht->nelems) || total != entries)
116 pr_warn("Test failed: Total count mismatch ^^^"); 129 pr_warn("Test failed: Total count mismatch ^^^");
117} 130}
118 131
119static int __init test_rhashtable(struct rhashtable *ht) 132static s64 __init test_rhashtable(struct rhashtable *ht)
120{ 133{
121 struct bucket_table *tbl; 134 struct bucket_table *tbl;
122 struct test_obj *obj; 135 struct test_obj *obj;
123 struct rhash_head *pos, *next; 136 struct rhash_head *pos, *next;
124 int err; 137 int err;
125 unsigned int i; 138 unsigned int i;
139 s64 start, end;
126 140
127 /* 141 /*
128 * Insertion Test: 142 * Insertion Test:
129 * Insert TEST_ENTRIES into table with all keys even numbers 143 * Insert entries into table with all keys even numbers
130 */ 144 */
131 pr_info(" Adding %d keys\n", TEST_ENTRIES); 145 pr_info(" Adding %d keys\n", entries);
132 for (i = 0; i < TEST_ENTRIES; i++) { 146 start = ktime_get_ns();
147 for (i = 0; i < entries; i++) {
133 struct test_obj *obj; 148 struct test_obj *obj;
134 149
135 obj = kzalloc(sizeof(*obj), GFP_KERNEL); 150 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
@@ -157,8 +172,8 @@ static int __init test_rhashtable(struct rhashtable *ht)
157 test_bucket_stats(ht, true); 172 test_bucket_stats(ht, true);
158 rcu_read_unlock(); 173 rcu_read_unlock();
159 174
160 pr_info(" Deleting %d keys\n", TEST_ENTRIES); 175 pr_info(" Deleting %d keys\n", entries);
161 for (i = 0; i < TEST_ENTRIES; i++) { 176 for (i = 0; i < entries; i++) {
162 u32 key = i * 2; 177 u32 key = i * 2;
163 178
164 obj = rhashtable_lookup_fast(ht, &key, test_rht_params); 179 obj = rhashtable_lookup_fast(ht, &key, test_rht_params);
@@ -168,7 +183,10 @@ static int __init test_rhashtable(struct rhashtable *ht)
168 kfree(obj); 183 kfree(obj);
169 } 184 }
170 185
171 return 0; 186 end = ktime_get_ns();
187 pr_info(" Duration of test: %lld ns\n", end - start);
188
189 return end - start;
172 190
173error: 191error:
174 tbl = rht_dereference_rcu(ht->tbl, ht); 192 tbl = rht_dereference_rcu(ht->tbl, ht);
@@ -183,22 +201,42 @@ static struct rhashtable ht;
183 201
184static int __init test_rht_init(void) 202static int __init test_rht_init(void)
185{ 203{
186 int err; 204 int i, err;
205 u64 total_time = 0;
187 206
188 pr_info("Running resizable hashtable tests...\n"); 207 entries = min(entries, MAX_ENTRIES);
189 208
190 err = rhashtable_init(&ht, &test_rht_params); 209 test_rht_params.automatic_shrinking = shrinking;
191 if (err < 0) { 210 test_rht_params.max_size = max_size;
192 pr_warn("Test failed: Unable to initialize hashtable: %d\n", 211 test_rht_params.nelem_hint = size;
193 err);
194 return err;
195 }
196 212
197 err = test_rhashtable(&ht); 213 pr_info("Running rhashtable test nelem=%d, max_size=%d, shrinking=%d\n",
214 size, max_size, shrinking);
198 215
199 rhashtable_destroy(&ht); 216 for (i = 0; i < runs; i++) {
217 s64 time;
200 218
201 return err; 219 pr_info("Test %02d:\n", i);
220 err = rhashtable_init(&ht, &test_rht_params);
221 if (err < 0) {
222 pr_warn("Test failed: Unable to initialize hashtable: %d\n",
223 err);
224 continue;
225 }
226
227 time = test_rhashtable(&ht);
228 rhashtable_destroy(&ht);
229 if (time < 0) {
230 pr_warn("Test failed: return code %lld\n", time);
231 return -EINVAL;
232 }
233
234 total_time += time;
235 }
236
237 pr_info("Average test time: %llu\n", total_time / runs);
238
239 return 0;
202} 240}
203 241
204static void __exit test_rht_exit(void) 242static void __exit test_rht_exit(void)