nfs-ganesha 1.4

test_mh_avl.c

Go to the documentation of this file.
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 }