#include #include #include #include #include #include #include "callout.h" int iters = 100; /* how many times to run (default 100) */ char *event_name(int e); int count_callouts(); void info(int type, callout_id_t h, char *name) { int n; if (!callout_getstats(h, &n)) n = -1; printf("\t%s:: %s: Handle %d: Count %d\n", name, event_name(type), (int)h, n); } /* simple test structure to compose a list */ typedef struct testlist { struct testlist* next; callout_id_t handle; } *testlist_t; void clock_func(int type, callout_id_t h, callout_event_closure_t cl) { info(type, h, (char*)cl); } void network_func(int type, callout_id_t h, callout_event_closure_t cl) { info(type, h, (char*)cl); } void disk_func(int type, callout_id_t h, callout_event_closure_t cl) { info(type, h, (char*)cl); } void pagefault_func(int type, callout_id_t h, callout_event_closure_t cl) { info(type, h, (char*)cl); } void tty_func(int type, callout_id_t h, callout_event_closure_t cl) { info(type, h, (char*)cl); } int genevent() { iters--; if (iters <= 0) { callout_shutdown(); return CALLOUT_EVENT_NULL; } return rand() % 5 + 1; } /* * This function returns the event name... */ char *event_name(int e) { switch (e) { case CALLOUT_EVENT_NULL: return "CALLOUT_EVENT_NULL"; case CALLOUT_EVENT_CLOCK: return "CALLOUT_EVENT_CLOCK"; case CALLOUT_EVENT_NETWORK: return "CALLOUT_EVENT_NETWORK"; case CALLOUT_EVENT_DISK: return "CALLOUT_EVENT_DISK"; case CALLOUT_EVENT_PAGEFAULT: return "CALLOUT_EVENT_PAGEFAULT"; case CALLOUT_EVENT_TTY: return "CALLOUT_EVENT_TTY"; default: return "Unknown event"; } } void usage(char *p) { fprintf(stderr,"Usage: %s [-i cnt] [-t simple | complex | stress | time]\n", p); exit(-1); } /* TYPES OF tests to perform; default to simple. */ #define SIMPLE 1 #define STRESS 2 #define COMPLEX 3 #define TIME 4 void simpleTest() { callout_id_t r1, r2, r3, r4, r5; char *name; r1 = callout_register(CALLOUT_EVENT_CLOCK, clock_func, strdup("Clock")); r2 = callout_register(CALLOUT_EVENT_NETWORK, network_func, strdup("Network")); r3 = callout_register(CALLOUT_EVENT_DISK, disk_func, strdup("Disk")); r4 = callout_register(CALLOUT_EVENT_PAGEFAULT, pagefault_func, strdup("Pagefault")); r5 = callout_register(CALLOUT_EVENT_TTY, tty_func, strdup("TTY")); printf("Registered five handlers.\n"); callout_unregister( r1, (callout_event_closure_t *)&name); printf("Unregistered %s handler.\n", name); callout_unregister( r2, (callout_event_closure_t *)&name); printf("Unregistered %s handler.\n", name); callout_unregister( r3, (callout_event_closure_t *)&name); printf("Unregistered %s handler.\n", name); callout_unregister( r4, (callout_event_closure_t *)&name); printf("Unregistered %s handler.\n", name); callout_unregister( r5, (callout_event_closure_t *)&name); printf("Unregistered %s handler.\n", name); printf("Registered five more handlers.\n"); r1 = callout_register(CALLOUT_EVENT_CLOCK, clock_func, strdup("Clock")); r2 = callout_register(CALLOUT_EVENT_NETWORK, network_func, strdup("Network")); r3 = callout_register(CALLOUT_EVENT_DISK, disk_func, strdup("Disk")); r4 = callout_register(CALLOUT_EVENT_PAGEFAULT, pagefault_func, strdup("Pagefault")); r5 = callout_register(CALLOUT_EVENT_TTY, tty_func, strdup("TTY")); } void complexTest() { int i; testlist_t temp; testlist_t head = (testlist_t)malloc(sizeof(struct testlist)); testlist_t t = head; printf("Starting to register event handlers.\n"); /* register a event handlers .. */ for ( i = 0; i < 1300; i++ ) { if ( t != NULL ) { char s[100]; int e = i%5 + 1; sprintf(s, "Callout function %d (Event: %s)", i, event_name(e)); t->handle = callout_register( i % 5 + 1, clock_func, strdup(s)); t->next = (testlist_t)malloc(sizeof(struct testlist)); t = t->next; } else break; } printf("Registered 1300 event handlers.\n"); printf("Unregistering some event handlers.\n"); /* reg/unreg a few */ for ( i = 0; i < 130; i++ ) { if (head != NULL) { char *name; callout_unregister(head->handle, (callout_event_closure_t *)&name); printf("Unregistered %s\n", name); temp = head; head = head->next; free(temp); } else break; } printf("Unregistered 130 event handlers.\n"); /* register more event handlers*/ for ( i = 1300; i < 2300; i++ ) { if ( t != NULL ) { char s[100]; int e = i%5 + 1; sprintf(s, "Callout function %d (Event: %s)", i, event_name(e)); t->handle = callout_register( i % 5 + 1, clock_func, strdup(s)); t->next = (testlist_t)malloc(sizeof(struct testlist)); t = t->next; } else break; } printf("Registered 1000 event handlers.\n"); printf("Doing the map test.\n"); /* Map test ... */ count_callouts(); printf("Done\n"); } void stressTest() { int i; callout_id_t r, r1; int ret; char *name; printf("Registering a lot of events.\n"); /* Attempt to overrun memory. */ for ( i = 0; i < 56789; i++ ) { r = callout_register(CALLOUT_EVENT_CLOCK, clock_func, strdup("CLOCK")); if (i==10) r1 = r; if (r== CALLOUT_ID_NULL) { printf("callout_register: Error while registering.\n"); break; } } printf("Trying to unregister a handle multiple times.\n" ); /* given the last handle, unregister it a few times. */ ret = callout_unregister( r1, (callout_event_closure_t *)&name); if ( ret == FALSE ) printf( "callout_unregister: Cannot unregister.\n"); else printf("Successful unregister.\n"); ret = callout_unregister( r1, (callout_event_closure_t *)&name); if ( ret == FALSE ) printf( "callout_unregister: Cannot unregister.\n"); else printf("Successful unregister.\n"); ret = callout_unregister( r1, (callout_event_closure_t *)&name); if ( ret == FALSE ) printf( "callout_unregister: Cannot unregister.\n"); else printf("Successful unregister.\n"); printf("Unregistering a few random handles.\n"); /* Unregister random handles */ srand(13); for ( i = 0; i < 120; i++ ) { ret = callout_unregister( (callout_id_t)(rand()), (callout_event_closure_t *)&name); if ( ret == FALSE ) printf("callout_unregister: Cannot unregister.\n"); else printf("Successful unregister.\n"); } printf("Stress test done.\n"); } /* * This function is used for timing .... */ void do_nothing_func(int type, callout_id_t h, callout_event_closure_t cl) { } /* * Timetest performs a simple registration of 10,000 callouts */ void timeTest() { int i; for( i = 0; i < 100000; i++ ) { callout_register(i % 5 + 1, do_nothing_func, "Some Handler"); } } int main(int argc, char **argv) { int test = SIMPLE; struct rusage r1; struct rusage r2; long t1, t2; int n = iters; int c, errflg = 0; optarg = NULL; while (!errflg && (c = getopt(argc, argv, "i:t:")) != -1) switch (c) { case 'i': n = iters = atoi(optarg); break; case 't' : if (!strcasecmp(optarg, "complex")) test = COMPLEX; else if (!strcmp(optarg, "stress")) test = STRESS; else if (!strcmp(optarg, "simple")) test = SIMPLE; else if (!strcmp(optarg, "time")) test = TIME; else usage(argv[0]); break; default : errflg++; usage(argv[0]); } if ( test == STRESS ) stressTest(); else if ( test == COMPLEX ) complexTest(); else if ( test == TIME ) timeTest(); else simpleTest(); printf("Calling callout_boot()\n"); getrusage(RUSAGE_SELF, &r1); /* TIMERS WOULD START HERE */ callout_boot(genevent); /* TIMERS WOULD END HERE */ getrusage(RUSAGE_SELF, &r2); printf("Done with callout_boot()\n"); t1 = (long)(r2.ru_utime.tv_sec - r1.ru_utime.tv_sec) * 1000 + (long)(r2.ru_utime.tv_usec - r1.ru_utime.tv_usec )/1000; printf("Time Taken = %ld milliseconds\n", t1); if (test == TIME) { int num_calls; printf("Calling genevent() %d times.\n", n); iters = n; getrusage(RUSAGE_SELF, &r1); while (genevent() != CALLOUT_EVENT_NULL) ; getrusage(RUSAGE_SELF, &r2); t2 = (long)(r2.ru_utime.tv_sec - r1.ru_utime.tv_sec) * 1000 + (long)(r2.ru_utime.tv_usec - r1.ru_utime.tv_usec )/1000; printf("Time taken for the genevent() calls = %ld\n", t2); num_calls = count_callouts(); printf("Time taken for the dispatches only = %ld\n", t1-t2); printf("Average time taken = %ld ns\n", (t1 - t2) * 1000000/num_calls); } if ( test == STRESS || test == COMPLEX ) { printf("Doing the map test.\n"); /* map a few things ... */ count_callouts(); } return 0; } /* * This is an example map function */ void mapcount(int type, callout_map_closure_t mapcl, callout_id_t h, callout_event_closure_t cl) { int n; if (callout_getstats(h, &n) == FALSE) { printf("Bad Handle !\n"); } else { int *np = (int*)mapcl; (*np) += n; } } /* * this function counts the total number of callouts done */ int count_callouts() { int numcalls = 0; callout_map(mapcount, &numcalls); printf("Total number of callouts is %d\n", numcalls); return numcalls; }