nfs-ganesha 1.4
|
00001 #include <limits.h> 00002 #include <stdio.h> 00003 #include <stdlib.h> 00004 #include <stddef.h> 00005 #include <string.h> 00006 #include <assert.h> 00007 00008 #include "CUnit/Basic.h" 00009 00010 #include "avltree.h" 00011 #include "murmur3.h" 00012 00013 #define DEBUG 1 00014 00015 /* STATICS we use across multiple tests */ 00016 struct avltree avl_tree_1; 00017 00018 /* dirent-like structure */ 00019 typedef struct avl_unit_val 00020 { 00021 struct avltree_node node_n; 00022 struct avltree_node node_hk; 00023 struct { 00024 uint64_t k; 00025 uint32_t p; /* nprobes , eff. metric */ 00026 } hk; 00027 char *name; 00028 uint64_t fsal_cookie; 00029 } avl_unit_val_t; 00030 00031 static inline int 00032 avl_unit_hk_cmpf(const struct avltree_node *lhs, 00033 const struct avltree_node *rhs) 00034 { 00035 avl_unit_val_t *lk, *rk; 00036 00037 lk = avltree_container_of(lhs, avl_unit_val_t, node_hk); 00038 rk = avltree_container_of(rhs, avl_unit_val_t, node_hk); 00039 00040 if (lk->hk.k < rk->hk.k) 00041 return (-1); 00042 00043 if (lk->hk.k == rk->hk.k) 00044 return (0); 00045 00046 return (1); 00047 } 00048 00049 avl_unit_val_t* 00050 avl_unit_new_val(const char *name) 00051 { 00052 avl_unit_val_t *v = malloc(sizeof(avl_unit_val_t)); 00053 memset(v, 0, sizeof(avl_unit_val_t)); 00054 v->name = (char *) name; 00055 00056 return v; 00057 } 00058 00059 static int qp_avl_insert(struct avltree *t, avl_unit_val_t *v) 00060 { 00061 /* 00062 * Insert with quadatic, linear probing. A unique k is assured for 00063 * any k whenever size(t) < max(uint64_t). 00064 * 00065 * First try quadratic probing, with coeff. 2 (since m = 2^n.) 00066 * A unique k is not assured, since the codomain is not prime. 00067 * If this fails, fall back to linear probing from hk.k+1. 00068 * 00069 * On return, the stored key is in v->hk.k, the iteration 00070 * count in v->hk.p. 00071 **/ 00072 struct avltree_node *tmpnode; 00073 uint32_t j, j2; 00074 uint32_t hk[4]; 00075 00076 assert(avltree_size(t) < UINT64_MAX); 00077 00078 MurmurHash3_x64_128(v->name, strlen(v->name), 67, hk); 00079 memcpy(&v->hk.k, hk, 8); 00080 00081 for (j = 0; j < UINT64_MAX; j++) { 00082 v->hk.k = (v->hk.k + (j * 2)); 00083 tmpnode = avltree_insert(&v->node_hk, t); 00084 if (!tmpnode) { 00085 /* success, note iterations and return */ 00086 v->hk.p = j; 00087 return (0); 00088 } 00089 } 00090 00091 /* warn debug */ 00092 00093 memcpy(&v->hk.k, hk, 8); 00094 for (j2 = 1 /* tried j=0 */; j2 < UINT64_MAX; j2++) { 00095 v->hk.k = v->hk.k + j2; 00096 tmpnode = avltree_insert(&v->node_hk, t); 00097 if (!tmpnode) { 00098 /* success, note iterations and return */ 00099 v->hk.p = j + j2; 00100 return (0); 00101 } 00102 j2++; 00103 } 00104 00105 /* warn crit */ 00106 return (-1); 00107 } 00108 00109 /* This permits inlining, also elides some locally-scoped stores in 00110 * do_lookup. */ 00111 static inline struct avltree_node *avltree_inline_lookup( 00112 const struct avltree_node *key, 00113 const struct avltree *tree) 00114 { 00115 struct avltree_node *node = tree->root; 00116 int is_left = 0, res = 0; 00117 00118 while (node) { 00119 res = avl_unit_hk_cmpf(node, key); /* may inline */ 00120 if (res == 0) 00121 return node; 00122 if ((is_left = res > 0)) 00123 node = node->left; 00124 else 00125 node = node->right; 00126 } 00127 return (NULL); 00128 } 00129 00130 static avl_unit_val_t * 00131 qp_avl_lookup_s(struct avltree *t, avl_unit_val_t *v, int maxj) 00132 { 00133 struct avltree_node *node; 00134 avl_unit_val_t *v2; 00135 uint32_t j, j2; 00136 uint32_t hk[4]; 00137 00138 assert(avltree_size(t) < UINT64_MAX); 00139 00140 MurmurHash3_x64_128(v->name, strlen(v->name), 67, hk); 00141 memcpy(&v->hk.k, hk, 8); 00142 00143 for (j = 0; j < maxj; j++) { 00144 v->hk.k = (v->hk.k + (j * 2)); 00145 node = avltree_inline_lookup(&v->node_hk, t); 00146 if (node) { 00147 /* it's almost but not entirely certain that node is 00148 * related to v. in the general case, j is also not 00149 * constrained to be v->hk.p */ 00150 v2 = avltree_container_of(node, avl_unit_val_t, node_hk); 00151 if (! strcmp(v->name, v2->name)) 00152 return (v2); 00153 } 00154 } 00155 00156 /* warn crit */ 00157 return (NULL); 00158 } 00159 00160 static struct dir_data 00161 { 00162 char *name; 00163 } dir_data[] = { 00164 ".gitignore", 00165 "Makefile", 00166 "Makefile.gate", 00167 "acpi-ext.c", 00168 "acpi-processor.c", 00169 "acpi.c", 00170 "asm-offsets.c", 00171 "audit.c", 00172 "brl_emu.c", 00173 "cpufreq", 00174 "crash.c", 00175 "crash_dump.c", 00176 "cyclone.c", 00177 "dma-mapping.c", 00178 "efi.c", 00179 "efi_stub.S", 00180 "entry.S", 00181 "entry.h", 00182 "err_inject.c", 00183 "esi.c", 00184 "esi_stub.S", 00185 "fsys.S", 00186 "fsyscall_gtod_data.h", 00187 "ftrace.c", 00188 "gate-data.S", 00189 "gate.S", 00190 "gate.lds.S", 00191 "head.S", 00192 "ia64_ksyms.c", 00193 "init_task.c", 00194 "iosapic.c", 00195 "irq.c", 00196 "irq_ia64.c", 00197 "irq_lsapic.c", 00198 "ivt.S", 00199 "jprobes.S", 00200 "kprobes.c", 00201 "machine_kexec.c", 00202 "machvec.c", 00203 "mca.c", 00204 "mca_asm.S", 00205 "mca_drv.c", 00206 "mca_drv.h", 00207 "mca_drv_asm.S", 00208 "minstate.h", 00209 "module.c", 00210 "msi_ia64.c", 00211 "nr-irqs.c", 00212 "numa.c", 00213 "pal.S", 00214 "palinfo.c", 00215 "paravirt.c", 00216 "paravirt_inst.h", 00217 "paravirt_patch.c", 00218 "paravirt_patchlist.c", 00219 "paravirt_patchlist.h", 00220 "paravirtentry.S", 00221 "patch.c", 00222 "pci-dma.c", 00223 "pci-swiotlb.c", 00224 "perfmon.c", 00225 "perfmon_default_smpl.c", 00226 "perfmon_generic.h", 00227 "perfmon_itanium.h", 00228 "perfmon_mckinley.h", 00229 "perfmon_montecito.h", 00230 "process.c", 00231 "ptrace.c", 00232 "relocate_kernel.S", 00233 "sal.c", 00234 "salinfo.c", 00235 "setup.c", 00236 "sigframe.h", 00237 "signal.c", 00238 "smp.c", 00239 "smpboot.c", 00240 "sys_ia64.c", 00241 "time.c", 00242 "topology.c", 00243 "traps.c", 00244 "unaligned.c", 00245 "uncached.c", 00246 "unwind.c", 00247 "unwind_decoder.c", 00248 "unwind_i.h", 00249 "vmlinux.lds.S", 00250 0 00251 }; 00252 00253 void 00254 avl_unit_free_val(avl_unit_val_t *v) 00255 { 00256 free(v); 00257 } 00258 00259 void 00260 avl_unit_clear_tree(struct avltree *t) 00261 { 00262 avl_unit_val_t *v; 00263 struct avltree_node *node, *next_node; 00264 00265 00266 if (avltree_size(t) < 1) 00267 return; 00268 00269 node = avltree_first(t); 00270 while (node) { 00271 next_node = avltree_next(node); 00272 v = avltree_container_of(node, avl_unit_val_t, node_hk); 00273 avltree_remove(&v->node_hk, &avl_tree_1); 00274 free(v->name); 00275 avl_unit_free_val(v); 00276 node = next_node; 00277 } 00278 } 00279 00280 /* dne */ 00281 void avltree_destroy(struct avltree *t) 00282 { 00283 return; 00284 } 00285 00286 void 00287 avl_unit_clear_and_destroy_tree(struct avltree *t) 00288 { 00289 avl_unit_clear_tree(t); 00290 avltree_destroy(t); 00291 } 00292 00293 /* 00294 * BEGIN SUITE INITIALIZATION and CLEANUP FUNCTIONS 00295 */ 00296 00297 void avl_unit_PkgInit(void) 00298 { 00299 /* nothing */ 00300 } 00301 00302 /* 00303 * The suite initialization function. 00304 * Initializes resources to be shared across tests. 00305 * Returns zero on success, non-zero otherwise. 00306 * 00307 */ 00308 int init_suite1(void) 00309 { 00310 00311 avltree_init(&avl_tree_1, avl_unit_hk_cmpf, 0 /* flags */); 00312 00313 return 0; 00314 } 00315 00316 /* The suite cleanup function. 00317 * Closes the temporary resources used by the tests. 00318 * Returns zero on success, non-zero otherwise. 00319 */ 00320 int clean_suite1(void) 00321 { 00322 if (avltree_size(&avl_tree_1) > 0) 00323 avl_unit_clear_tree(&avl_tree_1); 00324 00325 avltree_destroy(&avl_tree_1); 00326 00327 return 0; 00328 } 00329 00330 /* 00331 * END SUITE INITIALIZATION and CLEANUP FUNCTIONS 00332 */ 00333 00334 00335 /* 00336 * BEGIN BASIC TESTS 00337 */ 00338 00339 void inserts_tree_1(void) 00340 { 00341 avl_unit_val_t *v; 00342 char *s; 00343 int ix, code; 00344 00345 ix = 0; 00346 while ((s = dir_data[ix].name) != NULL) { 00347 v = avl_unit_new_val(strdup(s)); 00348 code = qp_avl_insert(&avl_tree_1, v); 00349 if (code == -1) 00350 abort(); 00351 if (v->hk.p > 0) 00352 printf("%d positive p %d %s\n", ix, v->hk.p, s); 00353 ++ix; 00354 } 00355 } 00356 00357 void check_tree_1(void) 00358 { 00359 int code = 0; 00360 CU_ASSERT_EQUAL(code, 0); 00361 } 00362 00363 void lookups_tree_1(void) 00364 { 00365 struct avltree_node *node; 00366 avl_unit_val_t *v2, *v; 00367 char *s; 00368 int ix; 00369 00370 ix = 0; 00371 while ((s = dir_data[ix].name) != NULL) { 00372 v = avl_unit_new_val(s); 00373 00374 /* lookup mapping */ 00375 v2 = qp_avl_lookup_s(&avl_tree_1, v, 1); 00376 if (!v2) 00377 abort(); 00378 else { 00379 /* printf("%d %d %s\n", ix, v2->hk.p, v2->name); */ 00380 } 00381 ++ix; 00382 } 00383 00384 /* free v */ 00385 avl_unit_free_val(v); 00386 } 00387 00388 void deletes_tree_1(void) 00389 { 00390 avl_unit_clear_tree(&avl_tree_1); 00391 avltree_init(&avl_tree_1, avl_unit_hk_cmpf, 0 /* flags */); 00392 } 00393 00394 void inserts_tree_2(void) 00395 { 00396 avl_unit_val_t *v; 00397 char s[256]; 00398 int ix, code; 00399 00400 for (ix = 0; ix < 100000; ++ix) { 00401 sprintf(s, "file%d", ix); 00402 v = avl_unit_new_val(strdup(s)); 00403 code = qp_avl_insert(&avl_tree_1, v); 00404 if (code == -1) 00405 abort(); 00406 if (v->hk.p > 0) 00407 printf("%d positive p %d %s\n", ix, v->hk.p, s); 00408 } 00409 } 00410 00411 void check_tree_2(void) 00412 { 00413 int code = 0; 00414 CU_ASSERT_EQUAL(code, 0); 00415 } 00416 00417 void lookups_tree_2(void) 00418 { 00419 struct avltree_node *node = NULL; 00420 avl_unit_val_t *v2, *v; 00421 char s[256]; 00422 int ix; 00423 00424 /* attempts 100K mits, 100K misses */ 00425 for (ix = 0; ix < 200000; ++ix) { 00426 sprintf(s, "file%d", ix); 00427 v = avl_unit_new_val(s); 00428 v2 = qp_avl_lookup_s(&avl_tree_1, v, 1); 00429 if (!v2) 00430 if (ix < 100000) 00431 abort(); 00432 else { 00433 /* printf("%d %d %s\n", ix, v2->hk.p, v2->name); */ 00434 } 00435 } 00436 00437 /* free v */ 00438 avl_unit_free_val(v); 00439 } 00440 00441 void deletes_tree_2(void) 00442 { 00443 avl_unit_clear_tree(&avl_tree_1); 00444 } 00445 00446 /* The main() function for setting up and running the tests. 00447 * Returns a CUE_SUCCESS on successful running, another 00448 * CUnit error code on failure. 00449 */ 00450 int main() 00451 { 00452 /* initialize the CUnit test registry... get this party started */ 00453 if (CUE_SUCCESS != CU_initialize_registry()) 00454 return CU_get_error(); 00455 00456 /* General avl_tree test. */ 00457 CU_TestInfo avl_tree_unit_1_arr[] = { 00458 { "Tree insertions 1.", inserts_tree_1 }, 00459 { "Tree check 1.", check_tree_1 }, 00460 { "Tree lookups 1.", lookups_tree_1 }, 00461 { "Tree deletes 1.", deletes_tree_1 }, 00462 { "Tree insertions 2.", inserts_tree_2 }, 00463 { "Tree check 2.", check_tree_2 }, 00464 { "Tree lookups 2.", lookups_tree_2 }, 00465 { "Tree deletes 2.", deletes_tree_2 }, 00466 CU_TEST_INFO_NULL, 00467 }; 00468 00469 CU_SuiteInfo suites[] = { 00470 { "Rb tree operations 1", init_suite1, clean_suite1, 00471 avl_tree_unit_1_arr }, 00472 CU_SUITE_INFO_NULL, 00473 }; 00474 00475 CU_ErrorCode error = CU_register_suites(suites); 00476 00477 /* Initialize the avl_tree package */ 00478 avl_unit_PkgInit(); 00479 00480 /* Run all tests using the CUnit Basic interface */ 00481 CU_basic_set_mode(CU_BRM_VERBOSE); 00482 CU_basic_run_tests(); 00483 CU_cleanup_registry(); 00484 00485 return CU_get_error(); 00486 }