xref: /qemu/tests/unit/test-qht.c (revision 1a95404fbd34f4ed66fa2450869fb3b384b0a97b)
1*1a95404fSEmilio G. Cota /*
2*1a95404fSEmilio G. Cota  * Copyright (C) 2016, Emilio G. Cota <cota@braap.org>
3*1a95404fSEmilio G. Cota  *
4*1a95404fSEmilio G. Cota  * License: GNU GPL, version 2 or later.
5*1a95404fSEmilio G. Cota  *   See the COPYING file in the top-level directory.
6*1a95404fSEmilio G. Cota  */
7*1a95404fSEmilio G. Cota #include "qemu/osdep.h"
8*1a95404fSEmilio G. Cota #include <glib.h>
9*1a95404fSEmilio G. Cota #include "qemu/qht.h"
10*1a95404fSEmilio G. Cota 
11*1a95404fSEmilio G. Cota #define N 5000
12*1a95404fSEmilio G. Cota 
13*1a95404fSEmilio G. Cota static struct qht ht;
14*1a95404fSEmilio G. Cota static int32_t arr[N * 2];
15*1a95404fSEmilio G. Cota 
16*1a95404fSEmilio G. Cota static bool is_equal(const void *obj, const void *userp)
17*1a95404fSEmilio G. Cota {
18*1a95404fSEmilio G. Cota     const int32_t *a = obj;
19*1a95404fSEmilio G. Cota     const int32_t *b = userp;
20*1a95404fSEmilio G. Cota 
21*1a95404fSEmilio G. Cota     return *a == *b;
22*1a95404fSEmilio G. Cota }
23*1a95404fSEmilio G. Cota 
24*1a95404fSEmilio G. Cota static void insert(int a, int b)
25*1a95404fSEmilio G. Cota {
26*1a95404fSEmilio G. Cota     int i;
27*1a95404fSEmilio G. Cota 
28*1a95404fSEmilio G. Cota     for (i = a; i < b; i++) {
29*1a95404fSEmilio G. Cota         uint32_t hash;
30*1a95404fSEmilio G. Cota 
31*1a95404fSEmilio G. Cota         arr[i] = i;
32*1a95404fSEmilio G. Cota         hash = i;
33*1a95404fSEmilio G. Cota 
34*1a95404fSEmilio G. Cota         qht_insert(&ht, &arr[i], hash);
35*1a95404fSEmilio G. Cota     }
36*1a95404fSEmilio G. Cota }
37*1a95404fSEmilio G. Cota 
38*1a95404fSEmilio G. Cota static void rm(int init, int end)
39*1a95404fSEmilio G. Cota {
40*1a95404fSEmilio G. Cota     int i;
41*1a95404fSEmilio G. Cota 
42*1a95404fSEmilio G. Cota     for (i = init; i < end; i++) {
43*1a95404fSEmilio G. Cota         uint32_t hash;
44*1a95404fSEmilio G. Cota 
45*1a95404fSEmilio G. Cota         hash = arr[i];
46*1a95404fSEmilio G. Cota         g_assert_true(qht_remove(&ht, &arr[i], hash));
47*1a95404fSEmilio G. Cota     }
48*1a95404fSEmilio G. Cota }
49*1a95404fSEmilio G. Cota 
50*1a95404fSEmilio G. Cota static void check(int a, int b, bool expected)
51*1a95404fSEmilio G. Cota {
52*1a95404fSEmilio G. Cota     struct qht_stats stats;
53*1a95404fSEmilio G. Cota     int i;
54*1a95404fSEmilio G. Cota 
55*1a95404fSEmilio G. Cota     for (i = a; i < b; i++) {
56*1a95404fSEmilio G. Cota         void *p;
57*1a95404fSEmilio G. Cota         uint32_t hash;
58*1a95404fSEmilio G. Cota         int32_t val;
59*1a95404fSEmilio G. Cota 
60*1a95404fSEmilio G. Cota         val = i;
61*1a95404fSEmilio G. Cota         hash = i;
62*1a95404fSEmilio G. Cota         p = qht_lookup(&ht, is_equal, &val, hash);
63*1a95404fSEmilio G. Cota         g_assert_true(!!p == expected);
64*1a95404fSEmilio G. Cota     }
65*1a95404fSEmilio G. Cota     qht_statistics_init(&ht, &stats);
66*1a95404fSEmilio G. Cota     if (stats.used_head_buckets) {
67*1a95404fSEmilio G. Cota         g_assert_cmpfloat(qdist_avg(&stats.chain), >=, 1.0);
68*1a95404fSEmilio G. Cota     }
69*1a95404fSEmilio G. Cota     g_assert_cmpuint(stats.head_buckets, >, 0);
70*1a95404fSEmilio G. Cota     qht_statistics_destroy(&stats);
71*1a95404fSEmilio G. Cota }
72*1a95404fSEmilio G. Cota 
73*1a95404fSEmilio G. Cota static void count_func(struct qht *ht, void *p, uint32_t hash, void *userp)
74*1a95404fSEmilio G. Cota {
75*1a95404fSEmilio G. Cota     unsigned int *curr = userp;
76*1a95404fSEmilio G. Cota 
77*1a95404fSEmilio G. Cota     (*curr)++;
78*1a95404fSEmilio G. Cota }
79*1a95404fSEmilio G. Cota 
80*1a95404fSEmilio G. Cota static void check_n(size_t expected)
81*1a95404fSEmilio G. Cota {
82*1a95404fSEmilio G. Cota     struct qht_stats stats;
83*1a95404fSEmilio G. Cota 
84*1a95404fSEmilio G. Cota     qht_statistics_init(&ht, &stats);
85*1a95404fSEmilio G. Cota     g_assert_cmpuint(stats.entries, ==, expected);
86*1a95404fSEmilio G. Cota     qht_statistics_destroy(&stats);
87*1a95404fSEmilio G. Cota }
88*1a95404fSEmilio G. Cota 
89*1a95404fSEmilio G. Cota static void iter_check(unsigned int count)
90*1a95404fSEmilio G. Cota {
91*1a95404fSEmilio G. Cota     unsigned int curr = 0;
92*1a95404fSEmilio G. Cota 
93*1a95404fSEmilio G. Cota     qht_iter(&ht, count_func, &curr);
94*1a95404fSEmilio G. Cota     g_assert_cmpuint(curr, ==, count);
95*1a95404fSEmilio G. Cota }
96*1a95404fSEmilio G. Cota 
97*1a95404fSEmilio G. Cota static void qht_do_test(unsigned int mode, size_t init_entries)
98*1a95404fSEmilio G. Cota {
99*1a95404fSEmilio G. Cota     qht_init(&ht, 0, mode);
100*1a95404fSEmilio G. Cota 
101*1a95404fSEmilio G. Cota     insert(0, N);
102*1a95404fSEmilio G. Cota     check(0, N, true);
103*1a95404fSEmilio G. Cota     check_n(N);
104*1a95404fSEmilio G. Cota     check(-N, -1, false);
105*1a95404fSEmilio G. Cota     iter_check(N);
106*1a95404fSEmilio G. Cota 
107*1a95404fSEmilio G. Cota     rm(101, 102);
108*1a95404fSEmilio G. Cota     check_n(N - 1);
109*1a95404fSEmilio G. Cota     insert(N, N * 2);
110*1a95404fSEmilio G. Cota     check_n(N + N - 1);
111*1a95404fSEmilio G. Cota     rm(N, N * 2);
112*1a95404fSEmilio G. Cota     check_n(N - 1);
113*1a95404fSEmilio G. Cota     insert(101, 102);
114*1a95404fSEmilio G. Cota     check_n(N);
115*1a95404fSEmilio G. Cota 
116*1a95404fSEmilio G. Cota     rm(10, 200);
117*1a95404fSEmilio G. Cota     check_n(N - 190);
118*1a95404fSEmilio G. Cota     insert(150, 200);
119*1a95404fSEmilio G. Cota     check_n(N - 190 + 50);
120*1a95404fSEmilio G. Cota     insert(10, 150);
121*1a95404fSEmilio G. Cota     check_n(N);
122*1a95404fSEmilio G. Cota 
123*1a95404fSEmilio G. Cota     rm(1, 2);
124*1a95404fSEmilio G. Cota     check_n(N - 1);
125*1a95404fSEmilio G. Cota     qht_reset_size(&ht, 0);
126*1a95404fSEmilio G. Cota     check_n(0);
127*1a95404fSEmilio G. Cota     check(0, N, false);
128*1a95404fSEmilio G. Cota 
129*1a95404fSEmilio G. Cota     qht_destroy(&ht);
130*1a95404fSEmilio G. Cota }
131*1a95404fSEmilio G. Cota 
132*1a95404fSEmilio G. Cota static void qht_test(unsigned int mode)
133*1a95404fSEmilio G. Cota {
134*1a95404fSEmilio G. Cota     qht_do_test(mode, 0);
135*1a95404fSEmilio G. Cota     qht_do_test(mode, 1);
136*1a95404fSEmilio G. Cota     qht_do_test(mode, 2);
137*1a95404fSEmilio G. Cota     qht_do_test(mode, 8);
138*1a95404fSEmilio G. Cota     qht_do_test(mode, 16);
139*1a95404fSEmilio G. Cota     qht_do_test(mode, 8192);
140*1a95404fSEmilio G. Cota     qht_do_test(mode, 16384);
141*1a95404fSEmilio G. Cota }
142*1a95404fSEmilio G. Cota 
143*1a95404fSEmilio G. Cota static void test_default(void)
144*1a95404fSEmilio G. Cota {
145*1a95404fSEmilio G. Cota     qht_test(0);
146*1a95404fSEmilio G. Cota }
147*1a95404fSEmilio G. Cota 
148*1a95404fSEmilio G. Cota static void test_resize(void)
149*1a95404fSEmilio G. Cota {
150*1a95404fSEmilio G. Cota     qht_test(QHT_MODE_AUTO_RESIZE);
151*1a95404fSEmilio G. Cota }
152*1a95404fSEmilio G. Cota 
153*1a95404fSEmilio G. Cota int main(int argc, char *argv[])
154*1a95404fSEmilio G. Cota {
155*1a95404fSEmilio G. Cota     g_test_init(&argc, &argv, NULL);
156*1a95404fSEmilio G. Cota     g_test_add_func("/qht/mode/default", test_default);
157*1a95404fSEmilio G. Cota     g_test_add_func("/qht/mode/resize", test_resize);
158*1a95404fSEmilio G. Cota     return g_test_run();
159*1a95404fSEmilio G. Cota }
160