OSDN Git Service

test_hash.c: split test_int_hash into arch-specific functions
[uclinux-h8/linux.git] / lib / test_hash.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Test cases for <linux/hash.h> and <linux/stringhash.h>
4  * This just verifies that various ways of computing a hash
5  * produce the same thing and, for cases where a k-bit hash
6  * value is requested, is of the requested size.
7  *
8  * We fill a buffer with a 255-byte null-terminated string,
9  * and use both full_name_hash() and hashlen_string() to hash the
10  * substrings from i to j, where 0 <= i < j < 256.
11  *
12  * The returned values are used to check that __hash_32() and
13  * __hash_32_generic() compute the same thing.  Likewise hash_32()
14  * and hash_64().
15  */
16
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt "\n"
18
19 #include <linux/compiler.h>
20 #include <linux/types.h>
21 #include <linux/module.h>
22 #include <linux/hash.h>
23 #include <linux/stringhash.h>
24 #include <linux/printk.h>
25
26 /* 32-bit XORSHIFT generator.  Seed must not be zero. */
27 static u32 __init __attribute_const__
28 xorshift(u32 seed)
29 {
30         seed ^= seed << 13;
31         seed ^= seed >> 17;
32         seed ^= seed << 5;
33         return seed;
34 }
35
36 /* Given a non-zero x, returns a non-zero byte. */
37 static u8 __init __attribute_const__
38 mod255(u32 x)
39 {
40         x = (x & 0xffff) + (x >> 16);   /* 1 <= x <= 0x1fffe */
41         x = (x & 0xff) + (x >> 8);      /* 1 <= x <= 0x2fd */
42         x = (x & 0xff) + (x >> 8);      /* 1 <= x <= 0x100 */
43         x = (x & 0xff) + (x >> 8);      /* 1 <= x <= 0xff */
44         return x;
45 }
46
47 /* Fill the buffer with non-zero bytes. */
48 static void __init
49 fill_buf(char *buf, size_t len, u32 seed)
50 {
51         size_t i;
52
53         for (i = 0; i < len; i++) {
54                 seed = xorshift(seed);
55                 buf[i] = mod255(seed);
56         }
57 }
58
59 /* Holds most testing variables for the int test. */
60 struct test_hash_params {
61         /* Pointer to integer to be hashed. */
62         unsigned long long *h64;
63         /* Low 32-bits of integer to be hashed. */
64         u32 h0;
65         /* Arch-specific hash result. */
66         u32 h1;
67         /* Generic hash result. */
68         u32 h2;
69         /* ORed hashes of given size (in bits). */
70         u32 (*hash_or)[33];
71 };
72
73 #ifdef HAVE_ARCH__HASH_32
74 static bool __init
75 test_int__hash_32(struct test_hash_params *params)
76 {
77         params->hash_or[1][0] |= params->h2 = __hash_32_generic(params->h0);
78 #if HAVE_ARCH__HASH_32 == 1
79         if (params->h1 != params->h2) {
80                 pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
81                        params->h0, params->h1, params->h2);
82                 return false;
83         }
84 #endif
85         return true;
86 }
87 #endif
88
89 #ifdef HAVE_ARCH_HASH_64
90 static bool __init
91 test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
92 {
93         params->h2 = hash_64_generic(*params->h64, *k);
94 #if HAVE_ARCH_HASH_64 == 1
95         if (params->h1 != params->h2) {
96                 pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
97                        *params->h64, *k, params->h1, params->h2);
98                 return false;
99         }
100 #else
101         if (params->h2 > *m) {
102                 pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
103                        *params->h64, *k, params->h1, *m);
104                 return false;
105         }
106 #endif
107         return true;
108 }
109 #endif
110
111 /*
112  * Test the various integer hash functions.  h64 (or its low-order bits)
113  * is the integer to hash.  hash_or accumulates the OR of the hash values,
114  * which are later checked to see that they cover all the requested bits.
115  *
116  * Because these functions (as opposed to the string hashes) are all
117  * inline, the code being tested is actually in the module, and you can
118  * recompile and re-test the module without rebooting.
119  */
120 static bool __init
121 test_int_hash(unsigned long long h64, u32 hash_or[2][33])
122 {
123         int k;
124         struct test_hash_params params = { &h64, (u32)h64, 0, 0, hash_or };
125
126         /* Test __hash32 */
127         hash_or[0][0] |= params.h1 = __hash_32(params.h0);
128 #ifdef HAVE_ARCH__HASH_32
129         if (!test_int__hash_32(&params))
130                 return false;
131 #endif
132
133         /* Test k = 1..32 bits */
134         for (k = 1; k <= 32; k++) {
135                 u32 const m = ((u32)2 << (k-1)) - 1;    /* Low k bits set */
136
137                 /* Test hash_32 */
138                 hash_or[0][k] |= params.h1 = hash_32(params.h0, k);
139                 if (params.h1 > m) {
140                         pr_err("hash_32(%#x, %d) = %#x > %#x", params.h0, k, params.h1, m);
141                         return false;
142                 }
143
144                 /* Test hash_64 */
145                 hash_or[1][k] |= params.h1 = hash_64(h64, k);
146                 if (params.h1 > m) {
147                         pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, params.h1, m);
148                         return false;
149                 }
150 #ifdef HAVE_ARCH_HASH_64
151                 if (!test_int_hash_64(&params, &m, &k))
152                         return false;
153 #endif
154         }
155
156         return true;
157 }
158
159 #define SIZE 256        /* Run time is cubic in SIZE */
160
161 static int __init
162 test_hash_init(void)
163 {
164         char buf[SIZE+1];
165         u32 string_or = 0, hash_or[2][33] = { { 0, } };
166         unsigned tests = 0;
167         unsigned long long h64 = 0;
168         int i, j;
169
170         fill_buf(buf, SIZE, 1);
171
172         /* Test every possible non-empty substring in the buffer. */
173         for (j = SIZE; j > 0; --j) {
174                 buf[j] = '\0';
175
176                 for (i = 0; i <= j; i++) {
177                         u64 hashlen = hashlen_string(buf+i, buf+i);
178                         u32 h0 = full_name_hash(buf+i, buf+i, j-i);
179
180                         /* Check that hashlen_string gets the length right */
181                         if (hashlen_len(hashlen) != j-i) {
182                                 pr_err("hashlen_string(%d..%d) returned length"
183                                         " %u, expected %d",
184                                         i, j, hashlen_len(hashlen), j-i);
185                                 return -EINVAL;
186                         }
187                         /* Check that the hashes match */
188                         if (hashlen_hash(hashlen) != h0) {
189                                 pr_err("hashlen_string(%d..%d) = %08x != "
190                                         "full_name_hash() = %08x",
191                                         i, j, hashlen_hash(hashlen), h0);
192                                 return -EINVAL;
193                         }
194
195                         string_or |= h0;
196                         h64 = h64 << 32 | h0;   /* For use with hash_64 */
197                         if (!test_int_hash(h64, hash_or))
198                                 return -EINVAL;
199                         tests++;
200                 } /* i */
201         } /* j */
202
203         /* The OR of all the hash values should cover all the bits */
204         if (~string_or) {
205                 pr_err("OR of all string hash results = %#x != %#x",
206                         string_or, -1u);
207                 return -EINVAL;
208         }
209         if (~hash_or[0][0]) {
210                 pr_err("OR of all __hash_32 results = %#x != %#x",
211                         hash_or[0][0], -1u);
212                 return -EINVAL;
213         }
214 #ifdef HAVE_ARCH__HASH_32
215 #if HAVE_ARCH__HASH_32 != 1     /* Test is pointless if results match */
216         if (~hash_or[1][0]) {
217                 pr_err("OR of all __hash_32_generic results = %#x != %#x",
218                         hash_or[1][0], -1u);
219                 return -EINVAL;
220         }
221 #endif
222 #endif
223
224         /* Likewise for all the i-bit hash values */
225         for (i = 1; i <= 32; i++) {
226                 u32 const m = ((u32)2 << (i-1)) - 1;    /* Low i bits set */
227
228                 if (hash_or[0][i] != m) {
229                         pr_err("OR of all hash_32(%d) results = %#x "
230                                 "(%#x expected)", i, hash_or[0][i], m);
231                         return -EINVAL;
232                 }
233                 if (hash_or[1][i] != m) {
234                         pr_err("OR of all hash_64(%d) results = %#x "
235                                 "(%#x expected)", i, hash_or[1][i], m);
236                         return -EINVAL;
237                 }
238         }
239
240         /* Issue notices about skipped tests. */
241 #ifdef HAVE_ARCH__HASH_32
242 #if HAVE_ARCH__HASH_32 != 1
243         pr_info("__hash_32() is arch-specific; not compared to generic.");
244 #endif
245 #else
246         pr_info("__hash_32() has no arch implementation to test.");
247 #endif
248 #ifdef HAVE_ARCH_HASH_64
249 #if HAVE_ARCH_HASH_64 != 1
250         pr_info("hash_64() is arch-specific; not compared to generic.");
251 #endif
252 #else
253         pr_info("hash_64() has no arch implementation to test.");
254 #endif
255
256         pr_notice("%u tests passed.", tests);
257
258         return 0;
259 }
260
261 static void __exit test_hash_exit(void)
262 {
263 }
264
265 module_init(test_hash_init);    /* Does everything */
266 module_exit(test_hash_exit);    /* Does nothing */
267
268 MODULE_LICENSE("GPL");