From 32f5cd52026752f476547a46590f522415c4decc Mon Sep 17 00:00:00 2001 From: murf Date: Mon, 10 Sep 2007 16:59:18 +0000 Subject: Committing my test for astobj2, hashtest2.c, along with makefile changes in utils. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@82140 f38db490-d61c-443f-a65b-d21fe96a405b --- utils/Makefile | 22 ++- utils/hashtest2.c | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 utils/hashtest2.c diff --git a/utils/Makefile b/utils/Makefile index 717c0dc07..fcc9b477c 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -16,7 +16,7 @@ .PHONY: clean all uninstall # to get check_expr, add it to the ALL_UTILS list -ALL_UTILS:=astman smsq stereorize streamplayer aelparse muted check_expr conf2ael +ALL_UTILS:=astman smsq stereorize streamplayer aelparse muted check_expr conf2ael hashtest2 UTILS:=$(ALL_UTILS) include $(ASTTOPDIR)/Makefile.rules @@ -114,6 +114,26 @@ aelparse.o: ASTCFLAGS+=-I../res -DSTANDALONE_AEL aelparse: aelparse.o aelbison.o pbx_ael.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o +astobj2.c : ../main/astobj2.c ../include/asterisk/astobj2.h + cp ../main/astobj2.c . + +utils.c : ../main/utils.c + cp ../main/utils.c . + +sha1.c : ../main/sha1.c + cp ../main/sha1.c . + +sha1.o : sha1.c +utils.o : utils.c + +astobj2.o : astobj2.c + +hashtest2.o : hashtest2.c + $(CC) -g -O0 -c hashtest2.c -I/usr/include -I../include + +hashtest2 : hashtest2.o md5.o utils.o astobj2.o sha1.o + $(CC) -g -O0 -o hashtest2 hashtest2.o astobj2.o utils.o md5.o sha1.o -lpthread + extconf.o : extconf.c conf2ael: conf2ael.o ast_expr2f.o ast_expr2.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o strcompat.o diff --git a/utils/hashtest2.c b/utils/hashtest2.c new file mode 100644 index 000000000..b71684939 --- /dev/null +++ b/utils/hashtest2.c @@ -0,0 +1,399 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2007, Steve Murphy + * + * Steve Murphy + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ +/*! \file + * + * \brief A program to thoroughly thrash a hash table, testing + * out locking safety, and making sure all functionality + * is functioning. Run with 5 or more threads to get that + * fully intense firestorm of activity. If your + * hash tables don't crash, lock up, or go weird, it must + * be good code! Even features some global counters + * that will get slightly behind because they aren't lock-protected. + * + * \author Steve Murphy + */ + +#include "asterisk.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "asterisk/lock.h" +#include "asterisk/astobj2.h" +#include "asterisk/channel.h" +#include "asterisk/utils.h" +#include "asterisk/module.h" + +int testno = 2; + +/* stuff we need to make this work with the astobj2 stuff */ + +void ast_cli(int *fd, char *str, ...) +{ +} + +int64_t ast_mark(int prof_id, int x) +{ +} + +/* my OBJECT */ +struct ht_element +{ + char *key; + char *val; +}; + + +static int hash_string(const void *obj, const int flags) +{ + unsigned char *str = ((struct ht_element*)obj)->key; + int total; + + for (total=0; *str; str++) + { + unsigned int tmp = total; + total <<= 1; /* multiply by 2 */ + total += tmp; /* multiply by 3 */ + total <<= 2; /* multiply by 12 */ + total += tmp; /* multiply by 13 */ + + total += ((unsigned int)(*str)); + } + if (total < 0) + total = -total; + return total; +} + +static int hashtab_compare_strings(void *a, void *b, int flags) +{ + const struct ht_element *ae = a, *be = b; + return !strcmp(ae->key, be->key) ? CMP_MATCH : 0; +} + +/* random numbers */ + +my_rand(int incl_low, int incl_high, unsigned int *seedp) +{ + if (incl_high == 0) + return 0; + + return incl_low + (rand_r(seedp) % incl_high); +} + + + + +/* the testing routines */ + +static int glob_highwater = 0; +struct ao2_container *glob_hashtab = 0; +unsigned int glob_seed = 0; +int els_removed = 0; +int els_added = 0; +int els_lookedup = 0; +int els_found = 0; +int els_traversals = 0; + +/* all the operations to perform on the hashtab */ + +void ht_destroy(void *obj) +{ + const struct ht_element *o = obj; + if (o->key) + free(o->key); + if (o->val) + free(o->val); +} + + +static void add_element(void) +{ + char keybuf[100]; + struct ht_element *x = ao2_alloc(sizeof(struct ht_element), ht_destroy); + sprintf(keybuf,"key%08d", glob_highwater++); + x->key = strdup(keybuf); + x->val = strdup("interesting data"); +#ifdef DEBUG + printf("+ %s\n", keybuf); +#endif + ao2_link(glob_hashtab, x); + + els_added++; /* unprotected, sometimes off, but, not really important, either */ +} + +static void traverse_elements(void) +{ + struct ht_element *el; + struct ao2_iterator it = ao2_iterator_init(glob_hashtab, 0); +#ifdef DEBUG + printf("Traverse hashtab\n"); +#endif + while ((el = ao2_iterator_next(&it))) { + ao2_ref(el,-1); + } + els_traversals++; /* unprotected, sometimes off, but, not really important, either */ +} + +static void * del_element(unsigned int *seedp) +{ + char keybuf[100]; + struct ht_element *el, lookup; + int x; + + /* pick a random element from 0 to highwater-1 */ + x = my_rand(0,glob_highwater-1,seedp); + sprintf(keybuf, "key%08d", x); +#ifdef DEBUG + printf("- %s", keybuf); +#endif + lookup.key = keybuf; + el = ao2_find(glob_hashtab, &lookup, OBJ_POINTER); + if (el) { +#ifdef DEBUG + printf("...YES (el=%x)\n", (unsigned long)el); +#endif + ao2_unlink(glob_hashtab, el); /* mistakenly tried to use ao2_ref(c,-2) here to unlink. Bad Boy! */ + els_removed++; + } else { +#ifdef DEBUG + printf("...NO.\n"); +#endif + return 0; + } + return el; +} + +static int lookup_element(unsigned int *seedp) +{ + char keybuf[100]; + struct ht_element *el, lookup; + int x; + + /* pick a random element from 0 to highwater-1 */ + x = my_rand(0,glob_highwater-1,seedp); + sprintf(keybuf, "key%08d", x); + lookup.key = keybuf; + el = ao2_find(glob_hashtab, &lookup, OBJ_POINTER); + els_lookedup++; + if (el) { + els_found++; + ao2_ref(el, -1); /* toss out this ref, no longer needed */ + return 1; + } else { + return 0; + } +} + + +static void *hashtest(void *data) +{ + int my_els_removed = 0; + int my_els_added = 0; + int my_els_lookedup = 0; + int my_els_found = 0; + int my_els_traversals = 0; + int my_testno = testno++; + + /* data will be a random number == use as a seed for random numbers */ + unsigned long seed = (unsigned long)data; + printf("hashtest thread created... test beginning\n"); + + /* main test routine-- a global hashtab exists, pound it like crazy */ + int its; + for(its=0;its<100000;its++) + { + void *seed2 = &seed; + int op = my_rand(0,100, seed2); + if (op<60) { + my_els_lookedup++; +#ifdef DEBUG + printf("%d[%d]: LOOKUP\n", my_testno, its); +#endif + if ((my_els_lookedup%1000)==0) { + printf("."); + fflush(stdout); + } + if (lookup_element(seed2)) + my_els_found++; + } else if (op < 61) { /* make this 61 and it'll take 16 minutes to run */ +#ifdef DEBUG + printf("%d[%d]: TRAVERSE\n", my_testno, its); +#endif + traverse_elements(); + my_els_traversals++; + + } else if (op < 80) { +#ifdef DEBUG + printf("%d[%d]: REMOVE\n", my_testno, its); +#endif + if (del_element(seed2)) + my_els_removed++; + } else { + my_els_added++; +#ifdef DEBUG + printf("%d[%d]: ADD\n", my_testno, its); +#endif + add_element(); + } + } + printf("\nhashtest thread %d exiting.... lookups=%d/%d, added=%d, removed=%d, traversals=%d;\n", + my_testno, my_els_found, my_els_lookedup, my_els_added, my_els_removed, my_els_traversals); + printf("\ntotals..................... lookups=%d/%d, added=%d, removed=%d; traversals=%d\n", + els_found, els_lookedup, els_added, els_removed, els_traversals); + pthread_exit(0); +} + +void run_hashtest(int numthr) +{ + pthread_t thr[numthr]; + void *thrres[numthr]; + int i; + + /* init a single global hashtab, then... */ + glob_hashtab = ao2_container_alloc(180000, hash_string, hashtab_compare_strings); + + /* set a random seed */ + glob_seed = (unsigned int)time(0); + srand(glob_seed); + + /* create threads, each running hashtest */ + for(i=0;i 2 || atoi(argv[1]) < 1) + { + printf("Usage: hashtest \n"); + exit(1); + } + + /* one arg == number of threads to create */ + run_hashtest(atoi(argv[1])); + + return 0; +} + + +struct ast_app *pbx_findapp(const char *app) +{ + return (struct ast_app*)1; /* so as not to trigger an error */ +} + +int ast_add_profile(const char *x, uint64_t scale) +{ +} + +int ast_loader_register(int (*updater)(void)) +{ + return 1; +} + +int ast_loader_unregister(int (*updater)(void)) +{ + return 1; +} +void ast_module_register(const struct ast_module_info *x) +{ +} + +void ast_module_unregister(const struct ast_module_info *x) +{ +} + + +void ast_cli_register_multiple(void) +{ +} + +void ast_register_file_version(const char *file, const char *version) +{ +} + +void ast_unregister_file_version(const char *file) +{ + +} + +void ast_cli_unregister_multiple(void) +{ +} + +void ast_context_destroy(void) +{ +} + +void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) +{ + va_list vars; + va_start(vars,fmt); + printf("LOG: lev:%d file:%s line:%d func: %s ", + level, file, line, function); + vprintf(fmt, vars); + fflush(stdout); + va_end(vars); +} + +void ast_verbose(const char *fmt, ...) +{ + va_list vars; + va_start(vars,fmt); + + printf("VERBOSE: "); + vprintf(fmt, vars); + fflush(stdout); + va_end(vars); +} + +void ast_register_thread(char *name) +{ + +} + +void ast_unregister_thread(void *id) +{ +} -- cgit v1.2.3