11a95404fSEmilio G. Cota /* 21a95404fSEmilio G. Cota * Copyright (C) 2016, Emilio G. Cota <cota@braap.org> 31a95404fSEmilio G. Cota * 41a95404fSEmilio G. Cota * License: GNU GPL, version 2 or later. 51a95404fSEmilio G. Cota * See the COPYING file in the top-level directory. 61a95404fSEmilio G. Cota */ 71a95404fSEmilio G. Cota #include "qemu/osdep.h" 81a95404fSEmilio G. Cota #include "qemu/qht.h" 99c7d64ebSEmilio G. Cota #include "qemu/rcu.h" 101a95404fSEmilio G. Cota 111a95404fSEmilio G. Cota #define N 5000 121a95404fSEmilio G. Cota 131a95404fSEmilio G. Cota static struct qht ht; 141a95404fSEmilio G. Cota static int32_t arr[N * 2]; 151a95404fSEmilio G. Cota 16*61b8cef1SEmilio G. Cota static bool is_equal(const void *ap, const void *bp) 171a95404fSEmilio G. Cota { 18*61b8cef1SEmilio G. Cota const int32_t *a = ap; 19*61b8cef1SEmilio G. Cota const int32_t *b = bp; 201a95404fSEmilio G. Cota 211a95404fSEmilio G. Cota return *a == *b; 221a95404fSEmilio G. Cota } 231a95404fSEmilio G. Cota 241a95404fSEmilio G. Cota static void insert(int a, int b) 251a95404fSEmilio G. Cota { 261a95404fSEmilio G. Cota int i; 271a95404fSEmilio G. Cota 281a95404fSEmilio G. Cota for (i = a; i < b; i++) { 291a95404fSEmilio G. Cota uint32_t hash; 301a95404fSEmilio G. Cota 311a95404fSEmilio G. Cota arr[i] = i; 321a95404fSEmilio G. Cota hash = i; 331a95404fSEmilio G. Cota 341a95404fSEmilio G. Cota qht_insert(&ht, &arr[i], hash); 351a95404fSEmilio G. Cota } 361a95404fSEmilio G. Cota } 371a95404fSEmilio G. Cota 381a95404fSEmilio G. Cota static void rm(int init, int end) 391a95404fSEmilio G. Cota { 401a95404fSEmilio G. Cota int i; 411a95404fSEmilio G. Cota 421a95404fSEmilio G. Cota for (i = init; i < end; i++) { 431a95404fSEmilio G. Cota uint32_t hash; 441a95404fSEmilio G. Cota 451a95404fSEmilio G. Cota hash = arr[i]; 461a95404fSEmilio G. Cota g_assert_true(qht_remove(&ht, &arr[i], hash)); 471a95404fSEmilio G. Cota } 481a95404fSEmilio G. Cota } 491a95404fSEmilio G. Cota 501a95404fSEmilio G. Cota static void check(int a, int b, bool expected) 511a95404fSEmilio G. Cota { 521a95404fSEmilio G. Cota struct qht_stats stats; 531a95404fSEmilio G. Cota int i; 541a95404fSEmilio G. Cota 559c7d64ebSEmilio G. Cota rcu_read_lock(); 561a95404fSEmilio G. Cota for (i = a; i < b; i++) { 571a95404fSEmilio G. Cota void *p; 581a95404fSEmilio G. Cota uint32_t hash; 591a95404fSEmilio G. Cota int32_t val; 601a95404fSEmilio G. Cota 611a95404fSEmilio G. Cota val = i; 621a95404fSEmilio G. Cota hash = i; 63*61b8cef1SEmilio G. Cota /* test both lookup variants; results should be the same */ 64*61b8cef1SEmilio G. Cota if (i % 2) { 65*61b8cef1SEmilio G. Cota p = qht_lookup(&ht, &val, hash); 66*61b8cef1SEmilio G. Cota } else { 67*61b8cef1SEmilio G. Cota p = qht_lookup_custom(&ht, &val, hash, is_equal); 68*61b8cef1SEmilio G. Cota } 691a95404fSEmilio G. Cota g_assert_true(!!p == expected); 701a95404fSEmilio G. Cota } 719c7d64ebSEmilio G. Cota rcu_read_unlock(); 729c7d64ebSEmilio G. Cota 731a95404fSEmilio G. Cota qht_statistics_init(&ht, &stats); 741a95404fSEmilio G. Cota if (stats.used_head_buckets) { 751a95404fSEmilio G. Cota g_assert_cmpfloat(qdist_avg(&stats.chain), >=, 1.0); 761a95404fSEmilio G. Cota } 771a95404fSEmilio G. Cota g_assert_cmpuint(stats.head_buckets, >, 0); 781a95404fSEmilio G. Cota qht_statistics_destroy(&stats); 791a95404fSEmilio G. Cota } 801a95404fSEmilio G. Cota 811a95404fSEmilio G. Cota static void count_func(struct qht *ht, void *p, uint32_t hash, void *userp) 821a95404fSEmilio G. Cota { 831a95404fSEmilio G. Cota unsigned int *curr = userp; 841a95404fSEmilio G. Cota 851a95404fSEmilio G. Cota (*curr)++; 861a95404fSEmilio G. Cota } 871a95404fSEmilio G. Cota 881a95404fSEmilio G. Cota static void check_n(size_t expected) 891a95404fSEmilio G. Cota { 901a95404fSEmilio G. Cota struct qht_stats stats; 911a95404fSEmilio G. Cota 921a95404fSEmilio G. Cota qht_statistics_init(&ht, &stats); 931a95404fSEmilio G. Cota g_assert_cmpuint(stats.entries, ==, expected); 941a95404fSEmilio G. Cota qht_statistics_destroy(&stats); 951a95404fSEmilio G. Cota } 961a95404fSEmilio G. Cota 971a95404fSEmilio G. Cota static void iter_check(unsigned int count) 981a95404fSEmilio G. Cota { 991a95404fSEmilio G. Cota unsigned int curr = 0; 1001a95404fSEmilio G. Cota 1011a95404fSEmilio G. Cota qht_iter(&ht, count_func, &curr); 1021a95404fSEmilio G. Cota g_assert_cmpuint(curr, ==, count); 1031a95404fSEmilio G. Cota } 1041a95404fSEmilio G. Cota 1051a95404fSEmilio G. Cota static void qht_do_test(unsigned int mode, size_t init_entries) 1061a95404fSEmilio G. Cota { 1077266ae91SEmilio G. Cota /* under KVM we might fetch stats from an uninitialized qht */ 1087266ae91SEmilio G. Cota check_n(0); 1097266ae91SEmilio G. Cota 110*61b8cef1SEmilio G. Cota qht_init(&ht, is_equal, 0, mode); 1111a95404fSEmilio G. Cota 1127266ae91SEmilio G. Cota check_n(0); 1131a95404fSEmilio G. Cota insert(0, N); 1141a95404fSEmilio G. Cota check(0, N, true); 1151a95404fSEmilio G. Cota check_n(N); 1161a95404fSEmilio G. Cota check(-N, -1, false); 1171a95404fSEmilio G. Cota iter_check(N); 1181a95404fSEmilio G. Cota 1191a95404fSEmilio G. Cota rm(101, 102); 1201a95404fSEmilio G. Cota check_n(N - 1); 1211a95404fSEmilio G. Cota insert(N, N * 2); 1221a95404fSEmilio G. Cota check_n(N + N - 1); 1231a95404fSEmilio G. Cota rm(N, N * 2); 1241a95404fSEmilio G. Cota check_n(N - 1); 1251a95404fSEmilio G. Cota insert(101, 102); 1261a95404fSEmilio G. Cota check_n(N); 1271a95404fSEmilio G. Cota 1281a95404fSEmilio G. Cota rm(10, 200); 1291a95404fSEmilio G. Cota check_n(N - 190); 1301a95404fSEmilio G. Cota insert(150, 200); 1311a95404fSEmilio G. Cota check_n(N - 190 + 50); 1321a95404fSEmilio G. Cota insert(10, 150); 1331a95404fSEmilio G. Cota check_n(N); 1341a95404fSEmilio G. Cota 1351a95404fSEmilio G. Cota rm(1, 2); 1361a95404fSEmilio G. Cota check_n(N - 1); 1371a95404fSEmilio G. Cota qht_reset_size(&ht, 0); 1381a95404fSEmilio G. Cota check_n(0); 1391a95404fSEmilio G. Cota check(0, N, false); 1401a95404fSEmilio G. Cota 1411a95404fSEmilio G. Cota qht_destroy(&ht); 1421a95404fSEmilio G. Cota } 1431a95404fSEmilio G. Cota 1441a95404fSEmilio G. Cota static void qht_test(unsigned int mode) 1451a95404fSEmilio G. Cota { 1461a95404fSEmilio G. Cota qht_do_test(mode, 0); 1471a95404fSEmilio G. Cota qht_do_test(mode, 1); 1481a95404fSEmilio G. Cota qht_do_test(mode, 2); 1491a95404fSEmilio G. Cota qht_do_test(mode, 8); 1501a95404fSEmilio G. Cota qht_do_test(mode, 16); 1511a95404fSEmilio G. Cota qht_do_test(mode, 8192); 1521a95404fSEmilio G. Cota qht_do_test(mode, 16384); 1531a95404fSEmilio G. Cota } 1541a95404fSEmilio G. Cota 1551a95404fSEmilio G. Cota static void test_default(void) 1561a95404fSEmilio G. Cota { 1571a95404fSEmilio G. Cota qht_test(0); 1581a95404fSEmilio G. Cota } 1591a95404fSEmilio G. Cota 1601a95404fSEmilio G. Cota static void test_resize(void) 1611a95404fSEmilio G. Cota { 1621a95404fSEmilio G. Cota qht_test(QHT_MODE_AUTO_RESIZE); 1631a95404fSEmilio G. Cota } 1641a95404fSEmilio G. Cota 1651a95404fSEmilio G. Cota int main(int argc, char *argv[]) 1661a95404fSEmilio G. Cota { 1671a95404fSEmilio G. Cota g_test_init(&argc, &argv, NULL); 1681a95404fSEmilio G. Cota g_test_add_func("/qht/mode/default", test_default); 1691a95404fSEmilio G. Cota g_test_add_func("/qht/mode/resize", test_resize); 1701a95404fSEmilio G. Cota return g_test_run(); 1711a95404fSEmilio G. Cota } 172