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" 9*9c7d64ebSEmilio 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 161a95404fSEmilio G. Cota static bool is_equal(const void *obj, const void *userp) 171a95404fSEmilio G. Cota { 181a95404fSEmilio G. Cota const int32_t *a = obj; 191a95404fSEmilio G. Cota const int32_t *b = userp; 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 55*9c7d64ebSEmilio 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; 631a95404fSEmilio G. Cota p = qht_lookup(&ht, is_equal, &val, hash); 641a95404fSEmilio G. Cota g_assert_true(!!p == expected); 651a95404fSEmilio G. Cota } 66*9c7d64ebSEmilio G. Cota rcu_read_unlock(); 67*9c7d64ebSEmilio G. Cota 681a95404fSEmilio G. Cota qht_statistics_init(&ht, &stats); 691a95404fSEmilio G. Cota if (stats.used_head_buckets) { 701a95404fSEmilio G. Cota g_assert_cmpfloat(qdist_avg(&stats.chain), >=, 1.0); 711a95404fSEmilio G. Cota } 721a95404fSEmilio G. Cota g_assert_cmpuint(stats.head_buckets, >, 0); 731a95404fSEmilio G. Cota qht_statistics_destroy(&stats); 741a95404fSEmilio G. Cota } 751a95404fSEmilio G. Cota 761a95404fSEmilio G. Cota static void count_func(struct qht *ht, void *p, uint32_t hash, void *userp) 771a95404fSEmilio G. Cota { 781a95404fSEmilio G. Cota unsigned int *curr = userp; 791a95404fSEmilio G. Cota 801a95404fSEmilio G. Cota (*curr)++; 811a95404fSEmilio G. Cota } 821a95404fSEmilio G. Cota 831a95404fSEmilio G. Cota static void check_n(size_t expected) 841a95404fSEmilio G. Cota { 851a95404fSEmilio G. Cota struct qht_stats stats; 861a95404fSEmilio G. Cota 871a95404fSEmilio G. Cota qht_statistics_init(&ht, &stats); 881a95404fSEmilio G. Cota g_assert_cmpuint(stats.entries, ==, expected); 891a95404fSEmilio G. Cota qht_statistics_destroy(&stats); 901a95404fSEmilio G. Cota } 911a95404fSEmilio G. Cota 921a95404fSEmilio G. Cota static void iter_check(unsigned int count) 931a95404fSEmilio G. Cota { 941a95404fSEmilio G. Cota unsigned int curr = 0; 951a95404fSEmilio G. Cota 961a95404fSEmilio G. Cota qht_iter(&ht, count_func, &curr); 971a95404fSEmilio G. Cota g_assert_cmpuint(curr, ==, count); 981a95404fSEmilio G. Cota } 991a95404fSEmilio G. Cota 1001a95404fSEmilio G. Cota static void qht_do_test(unsigned int mode, size_t init_entries) 1011a95404fSEmilio G. Cota { 1027266ae91SEmilio G. Cota /* under KVM we might fetch stats from an uninitialized qht */ 1037266ae91SEmilio G. Cota check_n(0); 1047266ae91SEmilio G. Cota 1051a95404fSEmilio G. Cota qht_init(&ht, 0, mode); 1061a95404fSEmilio G. Cota 1077266ae91SEmilio G. Cota check_n(0); 1081a95404fSEmilio G. Cota insert(0, N); 1091a95404fSEmilio G. Cota check(0, N, true); 1101a95404fSEmilio G. Cota check_n(N); 1111a95404fSEmilio G. Cota check(-N, -1, false); 1121a95404fSEmilio G. Cota iter_check(N); 1131a95404fSEmilio G. Cota 1141a95404fSEmilio G. Cota rm(101, 102); 1151a95404fSEmilio G. Cota check_n(N - 1); 1161a95404fSEmilio G. Cota insert(N, N * 2); 1171a95404fSEmilio G. Cota check_n(N + N - 1); 1181a95404fSEmilio G. Cota rm(N, N * 2); 1191a95404fSEmilio G. Cota check_n(N - 1); 1201a95404fSEmilio G. Cota insert(101, 102); 1211a95404fSEmilio G. Cota check_n(N); 1221a95404fSEmilio G. Cota 1231a95404fSEmilio G. Cota rm(10, 200); 1241a95404fSEmilio G. Cota check_n(N - 190); 1251a95404fSEmilio G. Cota insert(150, 200); 1261a95404fSEmilio G. Cota check_n(N - 190 + 50); 1271a95404fSEmilio G. Cota insert(10, 150); 1281a95404fSEmilio G. Cota check_n(N); 1291a95404fSEmilio G. Cota 1301a95404fSEmilio G. Cota rm(1, 2); 1311a95404fSEmilio G. Cota check_n(N - 1); 1321a95404fSEmilio G. Cota qht_reset_size(&ht, 0); 1331a95404fSEmilio G. Cota check_n(0); 1341a95404fSEmilio G. Cota check(0, N, false); 1351a95404fSEmilio G. Cota 1361a95404fSEmilio G. Cota qht_destroy(&ht); 1371a95404fSEmilio G. Cota } 1381a95404fSEmilio G. Cota 1391a95404fSEmilio G. Cota static void qht_test(unsigned int mode) 1401a95404fSEmilio G. Cota { 1411a95404fSEmilio G. Cota qht_do_test(mode, 0); 1421a95404fSEmilio G. Cota qht_do_test(mode, 1); 1431a95404fSEmilio G. Cota qht_do_test(mode, 2); 1441a95404fSEmilio G. Cota qht_do_test(mode, 8); 1451a95404fSEmilio G. Cota qht_do_test(mode, 16); 1461a95404fSEmilio G. Cota qht_do_test(mode, 8192); 1471a95404fSEmilio G. Cota qht_do_test(mode, 16384); 1481a95404fSEmilio G. Cota } 1491a95404fSEmilio G. Cota 1501a95404fSEmilio G. Cota static void test_default(void) 1511a95404fSEmilio G. Cota { 1521a95404fSEmilio G. Cota qht_test(0); 1531a95404fSEmilio G. Cota } 1541a95404fSEmilio G. Cota 1551a95404fSEmilio G. Cota static void test_resize(void) 1561a95404fSEmilio G. Cota { 1571a95404fSEmilio G. Cota qht_test(QHT_MODE_AUTO_RESIZE); 1581a95404fSEmilio G. Cota } 1591a95404fSEmilio G. Cota 1601a95404fSEmilio G. Cota int main(int argc, char *argv[]) 1611a95404fSEmilio G. Cota { 1621a95404fSEmilio G. Cota g_test_init(&argc, &argv, NULL); 1631a95404fSEmilio G. Cota g_test_add_func("/qht/mode/default", test_default); 1641a95404fSEmilio G. Cota g_test_add_func("/qht/mode/resize", test_resize); 1651a95404fSEmilio G. Cota return g_test_run(); 1661a95404fSEmilio G. Cota } 167