Linux Audio

Check our new training course

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