Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
  1// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2
  3/*
  4 * Tests for libbpf's hashmap.
  5 *
  6 * Copyright (c) 2019 Facebook
  7 */
  8#include "test_progs.h"
  9#include "bpf/hashmap.h"
 10
 11static int duration = 0;
 12
 13static size_t hash_fn(const void *k, void *ctx)
 14{
 15	return (long)k;
 16}
 17
 18static bool equal_fn(const void *a, const void *b, void *ctx)
 19{
 20	return (long)a == (long)b;
 21}
 22
 23static inline size_t next_pow_2(size_t n)
 24{
 25	size_t r = 1;
 26
 27	while (r < n)
 28		r <<= 1;
 29	return r;
 30}
 31
 32static inline size_t exp_cap(size_t sz)
 33{
 34	size_t r = next_pow_2(sz);
 35
 36	if (sz * 4 / 3 > r)
 37		r <<= 1;
 38	return r;
 39}
 40
 41#define ELEM_CNT 62
 42
 43static void test_hashmap_generic(void)
 44{
 45	struct hashmap_entry *entry, *tmp;
 46	int err, bkt, found_cnt, i;
 47	long long found_msk;
 48	struct hashmap *map;
 49
 50	map = hashmap__new(hash_fn, equal_fn, NULL);
 51	if (CHECK(IS_ERR(map), "hashmap__new",
 52		  "failed to create map: %ld\n", PTR_ERR(map)))
 53		return;
 54
 55	for (i = 0; i < ELEM_CNT; i++) {
 56		const void *oldk, *k = (const void *)(long)i;
 57		void *oldv, *v = (void *)(long)(1024 + i);
 58
 59		err = hashmap__update(map, k, v, &oldk, &oldv);
 60		if (CHECK(err != -ENOENT, "hashmap__update",
 61			  "unexpected result: %d\n", err))
 62			goto cleanup;
 63
 64		if (i % 2) {
 65			err = hashmap__add(map, k, v);
 66		} else {
 67			err = hashmap__set(map, k, v, &oldk, &oldv);
 68			if (CHECK(oldk != NULL || oldv != NULL, "check_kv",
 69				  "unexpected k/v: %p=%p\n", oldk, oldv))
 70				goto cleanup;
 71		}
 72
 73		if (CHECK(err, "elem_add", "failed to add k/v %ld = %ld: %d\n",
 74			       (long)k, (long)v, err))
 75			goto cleanup;
 76
 77		if (CHECK(!hashmap__find(map, k, &oldv), "elem_find",
 78			  "failed to find key %ld\n", (long)k))
 79			goto cleanup;
 80		if (CHECK(oldv != v, "elem_val",
 81			  "found value is wrong: %ld\n", (long)oldv))
 82			goto cleanup;
 83	}
 84
 85	if (CHECK(hashmap__size(map) != ELEM_CNT, "hashmap__size",
 86		  "invalid map size: %zu\n", hashmap__size(map)))
 87		goto cleanup;
 88	if (CHECK(hashmap__capacity(map) != exp_cap(hashmap__size(map)),
 89		  "hashmap_cap",
 90		  "unexpected map capacity: %zu\n", hashmap__capacity(map)))
 91		goto cleanup;
 92
 93	found_msk = 0;
 94	hashmap__for_each_entry(map, entry, bkt) {
 95		long k = (long)entry->key;
 96		long v = (long)entry->value;
 97
 98		found_msk |= 1ULL << k;
 99		if (CHECK(v - k != 1024, "check_kv",
100			  "invalid k/v pair: %ld = %ld\n", k, v))
101			goto cleanup;
102	}
103	if (CHECK(found_msk != (1ULL << ELEM_CNT) - 1, "elem_cnt",
104		  "not all keys iterated: %llx\n", found_msk))
105		goto cleanup;
106
107	for (i = 0; i < ELEM_CNT; i++) {
108		const void *oldk, *k = (const void *)(long)i;
109		void *oldv, *v = (void *)(long)(256 + i);
110
111		err = hashmap__add(map, k, v);
112		if (CHECK(err != -EEXIST, "hashmap__add",
113			  "unexpected add result: %d\n", err))
114			goto cleanup;
115
116		if (i % 2)
117			err = hashmap__update(map, k, v, &oldk, &oldv);
118		else
119			err = hashmap__set(map, k, v, &oldk, &oldv);
120
121		if (CHECK(err, "elem_upd",
122			  "failed to update k/v %ld = %ld: %d\n",
123			  (long)k, (long)v, err))
124			goto cleanup;
125		if (CHECK(!hashmap__find(map, k, &oldv), "elem_find",
126			  "failed to find key %ld\n", (long)k))
127			goto cleanup;
128		if (CHECK(oldv != v, "elem_val",
129			  "found value is wrong: %ld\n", (long)oldv))
130			goto cleanup;
131	}
132
133	if (CHECK(hashmap__size(map) != ELEM_CNT, "hashmap__size",
134		  "invalid updated map size: %zu\n", hashmap__size(map)))
135		goto cleanup;
136	if (CHECK(hashmap__capacity(map) != exp_cap(hashmap__size(map)),
137		  "hashmap__capacity",
138		  "unexpected map capacity: %zu\n", hashmap__capacity(map)))
139		goto cleanup;
140
141	found_msk = 0;
142	hashmap__for_each_entry_safe(map, entry, tmp, bkt) {
143		long k = (long)entry->key;
144		long v = (long)entry->value;
145
146		found_msk |= 1ULL << k;
147		if (CHECK(v - k != 256, "elem_check",
148			  "invalid updated k/v pair: %ld = %ld\n", k, v))
149			goto cleanup;
150	}
151	if (CHECK(found_msk != (1ULL << ELEM_CNT) - 1, "elem_cnt",
152		  "not all keys iterated after update: %llx\n", found_msk))
153		goto cleanup;
154
155	found_cnt = 0;
156	hashmap__for_each_key_entry(map, entry, (void *)0) {
157		found_cnt++;
158	}
159	if (CHECK(!found_cnt, "found_cnt",
160		  "didn't find any entries for key 0\n"))
161		goto cleanup;
162
163	found_msk = 0;
164	found_cnt = 0;
165	hashmap__for_each_key_entry_safe(map, entry, tmp, (void *)0) {
166		const void *oldk, *k;
167		void *oldv, *v;
168
169		k = entry->key;
170		v = entry->value;
171
172		found_cnt++;
173		found_msk |= 1ULL << (long)k;
174
175		if (CHECK(!hashmap__delete(map, k, &oldk, &oldv), "elem_del",
176			  "failed to delete k/v %ld = %ld\n",
177			  (long)k, (long)v))
178			goto cleanup;
179		if (CHECK(oldk != k || oldv != v, "check_old",
180			  "invalid deleted k/v: expected %ld = %ld, got %ld = %ld\n",
181			  (long)k, (long)v, (long)oldk, (long)oldv))
182			goto cleanup;
183		if (CHECK(hashmap__delete(map, k, &oldk, &oldv), "elem_del",
184			  "unexpectedly deleted k/v %ld = %ld\n",
185			  (long)oldk, (long)oldv))
186			goto cleanup;
187	}
188
189	if (CHECK(!found_cnt || !found_msk, "found_entries",
190		  "didn't delete any key entries\n"))
191		goto cleanup;
192	if (CHECK(hashmap__size(map) != ELEM_CNT - found_cnt, "elem_cnt",
193		  "invalid updated map size (already deleted: %d): %zu\n",
194		  found_cnt, hashmap__size(map)))
195		goto cleanup;
196	if (CHECK(hashmap__capacity(map) != exp_cap(hashmap__size(map)),
197		  "hashmap__capacity",
198		  "unexpected map capacity: %zu\n", hashmap__capacity(map)))
199		goto cleanup;
200
201	hashmap__for_each_entry_safe(map, entry, tmp, bkt) {
202		const void *oldk, *k;
203		void *oldv, *v;
204
205		k = entry->key;
206		v = entry->value;
207
208		found_cnt++;
209		found_msk |= 1ULL << (long)k;
210
211		if (CHECK(!hashmap__delete(map, k, &oldk, &oldv), "elem_del",
212			  "failed to delete k/v %ld = %ld\n",
213			  (long)k, (long)v))
214			goto cleanup;
215		if (CHECK(oldk != k || oldv != v, "elem_check",
216			  "invalid old k/v: expect %ld = %ld, got %ld = %ld\n",
217			  (long)k, (long)v, (long)oldk, (long)oldv))
218			goto cleanup;
219		if (CHECK(hashmap__delete(map, k, &oldk, &oldv), "elem_del",
220			  "unexpectedly deleted k/v %ld = %ld\n",
221			  (long)k, (long)v))
222			goto cleanup;
223	}
224
225	if (CHECK(found_cnt != ELEM_CNT || found_msk != (1ULL << ELEM_CNT) - 1,
226		  "found_cnt",
227		  "not all keys were deleted: found_cnt:%d, found_msk:%llx\n",
228		  found_cnt, found_msk))
229		goto cleanup;
230	if (CHECK(hashmap__size(map) != 0, "hashmap__size",
231		  "invalid updated map size (already deleted: %d): %zu\n",
232		  found_cnt, hashmap__size(map)))
233		goto cleanup;
234
235	found_cnt = 0;
236	hashmap__for_each_entry(map, entry, bkt) {
237		CHECK(false, "elem_exists",
238		      "unexpected map entries left: %ld = %ld\n",
239		      (long)entry->key, (long)entry->value);
240		goto cleanup;
241	}
242
243	hashmap__clear(map);
244	hashmap__for_each_entry(map, entry, bkt) {
245		CHECK(false, "elem_exists",
246		      "unexpected map entries left: %ld = %ld\n",
247		      (long)entry->key, (long)entry->value);
248		goto cleanup;
249	}
250
251cleanup:
252	hashmap__free(map);
253}
254
255static size_t collision_hash_fn(const void *k, void *ctx)
256{
257	return 0;
258}
259
260static void test_hashmap_multimap(void)
261{
262	void *k1 = (void *)0, *k2 = (void *)1;
263	struct hashmap_entry *entry;
264	struct hashmap *map;
265	long found_msk;
266	int err, bkt;
267
268	/* force collisions */
269	map = hashmap__new(collision_hash_fn, equal_fn, NULL);
270	if (CHECK(IS_ERR(map), "hashmap__new",
271		  "failed to create map: %ld\n", PTR_ERR(map)))
272		return;
273
274	/* set up multimap:
275	 * [0] -> 1, 2, 4;
276	 * [1] -> 8, 16, 32;
277	 */
278	err = hashmap__append(map, k1, (void *)1);
279	if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
280		goto cleanup;
281	err = hashmap__append(map, k1, (void *)2);
282	if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
283		goto cleanup;
284	err = hashmap__append(map, k1, (void *)4);
285	if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
286		goto cleanup;
287
288	err = hashmap__append(map, k2, (void *)8);
289	if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
290		goto cleanup;
291	err = hashmap__append(map, k2, (void *)16);
292	if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
293		goto cleanup;
294	err = hashmap__append(map, k2, (void *)32);
295	if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
296		goto cleanup;
297
298	if (CHECK(hashmap__size(map) != 6, "hashmap_size",
299		  "invalid map size: %zu\n", hashmap__size(map)))
300		goto cleanup;
301
302	/* verify global iteration still works and sees all values */
303	found_msk = 0;
304	hashmap__for_each_entry(map, entry, bkt) {
305		found_msk |= (long)entry->value;
306	}
307	if (CHECK(found_msk != (1 << 6) - 1, "found_msk",
308		  "not all keys iterated: %lx\n", found_msk))
309		goto cleanup;
310
311	/* iterate values for key 1 */
312	found_msk = 0;
313	hashmap__for_each_key_entry(map, entry, k1) {
314		found_msk |= (long)entry->value;
315	}
316	if (CHECK(found_msk != (1 | 2 | 4), "found_msk",
317		  "invalid k1 values: %lx\n", found_msk))
318		goto cleanup;
319
320	/* iterate values for key 2 */
321	found_msk = 0;
322	hashmap__for_each_key_entry(map, entry, k2) {
323		found_msk |= (long)entry->value;
324	}
325	if (CHECK(found_msk != (8 | 16 | 32), "found_msk",
326		  "invalid k2 values: %lx\n", found_msk))
327		goto cleanup;
328
329cleanup:
330	hashmap__free(map);
331}
332
333static void test_hashmap_empty()
334{
335	struct hashmap_entry *entry;
336	int bkt;
337	struct hashmap *map;
338	void *k = (void *)0;
339
340	/* force collisions */
341	map = hashmap__new(hash_fn, equal_fn, NULL);
342	if (CHECK(IS_ERR(map), "hashmap__new",
343		  "failed to create map: %ld\n", PTR_ERR(map)))
344		goto cleanup;
345
346	if (CHECK(hashmap__size(map) != 0, "hashmap__size",
347		  "invalid map size: %zu\n", hashmap__size(map)))
348		goto cleanup;
349	if (CHECK(hashmap__capacity(map) != 0, "hashmap__capacity",
350		  "invalid map capacity: %zu\n", hashmap__capacity(map)))
351		goto cleanup;
352	if (CHECK(hashmap__find(map, k, NULL), "elem_find",
353		  "unexpected find\n"))
354		goto cleanup;
355	if (CHECK(hashmap__delete(map, k, NULL, NULL), "elem_del",
356		  "unexpected delete\n"))
357		goto cleanup;
358
359	hashmap__for_each_entry(map, entry, bkt) {
360		CHECK(false, "elem_found", "unexpected iterated entry\n");
361		goto cleanup;
362	}
363	hashmap__for_each_key_entry(map, entry, k) {
364		CHECK(false, "key_found", "unexpected key entry\n");
365		goto cleanup;
366	}
367
368cleanup:
369	hashmap__free(map);
370}
371
372void test_hashmap()
373{
374	if (test__start_subtest("generic"))
375		test_hashmap_generic();
376	if (test__start_subtest("multimap"))
377		test_hashmap_multimap();
378	if (test__start_subtest("empty"))
379		test_hashmap_empty();
380}