1 /******************************************************************************
4 * Test harness for the various set implementations.
6 * Copyright (c) 2002-2003, K A Fraser
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
12 * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution. Neither the name of the Keir Fraser
18 * nor the names of its contributors may be used to endorse or
19 * promote products derived from this software without specific
20 * prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/resource.h>
41 #include <sys/types.h>
43 #include <sys/times.h>
54 #include "portable_defns.h"
58 /* This produces an operation log for the 'replay' checker. */
59 /*#define DO_WRITE_LOG*/
62 #define MAX_ITERATIONS 100000
63 #define MAX_WALL_TIME 50 /* seconds */
65 #define MAX_ITERATIONS 100000000
66 #define MAX_WALL_TIME 10 /* seconds */
70 * ***************** LOGGING
73 #define MAX_LOG_RECORDS 256
75 #define LOG_KIND_INT 0
76 #define LOG_KIND_STRING 1
77 #define LOG_KIND_FLOAT 2
87 static log_record_t log_records[MAX_LOG_RECORDS];
89 static int num_log_records = 0;
91 static void log_int (char *name, int val) {
92 log_records[num_log_records].name = name;
93 log_records[num_log_records].kind = LOG_KIND_INT;
94 log_records[num_log_records].val_int = val;
98 static void log_string (char *name, char *val) {
99 log_records[num_log_records].name = name;
100 log_records[num_log_records].kind = LOG_KIND_STRING;
101 log_records[num_log_records].val_string = val;
105 static void log_float (char *name, float val) {
106 log_records[num_log_records].name = name;
107 log_records[num_log_records].kind = LOG_KIND_FLOAT;
108 log_records[num_log_records].val_float = val;
112 static void dump_log (void) {
115 fprintf (stdout, "-------------------------------------------"
116 "---------------------------\n");
117 for (i = 0; i < num_log_records; i ++)
120 memset(padding, ' ', sizeof(padding) - 1);
122 if (30-strlen(log_records[i].name) >= 0){
123 padding[30-strlen(log_records[i].name)] = '\0';
125 fprintf (stdout, "%s%s = ", padding, log_records[i].name);
127 int kind = log_records [i].kind;
128 if (kind == LOG_KIND_INT) {
129 fprintf (stdout, "%d\n", log_records[i].val_int);
130 } else if (kind == LOG_KIND_STRING) {
131 fprintf (stdout, "%s\n", log_records[i].val_string);
132 } else if (kind == LOG_KIND_FLOAT) {
133 fprintf (stdout, "%.3f\n", log_records[i].val_float);
137 fprintf (stdout, "-------------------------------------------"
138 "---------------------------\n");
140 for (i = 0; i < num_log_records; i ++)
142 int kind = log_records [i].kind;
143 if (i != 0) { fprintf (stderr, " "); }
144 if (kind == LOG_KIND_INT) {
145 fprintf (stderr, "%d", log_records[i].val_int);
146 } else if (kind == LOG_KIND_STRING) {
147 fprintf (stderr, "%s", log_records[i].val_string);
148 } else if (kind == LOG_KIND_FLOAT) {
149 fprintf (stderr, "%.3f", log_records[i].val_float);
152 fprintf (stderr, " LOG\n");
156 * ************** END OF LOGGING
159 #define TVAL(x) ((x.tv_sec * 1000000) + x.tv_usec)
161 /* Log tables. Written out at end-of-day. */
162 typedef struct log_st
164 interval_t start, end;
166 void *val, *old_val; /* @old_val used by update() and remove() */
168 #define SIZEOF_GLOBAL_LOG (num_threads*MAX_ITERATIONS*sizeof(log_t))
169 static log_t *global_log;
170 static interval_t interval = 0;
172 static bool_t go = FALSE;
173 static int threads_initialised1 = 0, max_key, log_max_key;
174 static int threads_initialised2 = 0;
175 static int threads_initialised3 = 0;
178 static unsigned long proportion;
180 static struct timeval start_time, done_time;
181 static struct tms start_tms, done_tms;
183 static int successes[MAX_THREADS];
186 static int processors[MAX_THREADS];
189 /* All the variables accessed in the critical main loop. */
198 #define nrand(_r) (((_r) = (_r) * 1103515245) + 12345)
200 static void alarm_handler( int arg)
202 shared.alarm_time = 1;
205 /*int cntr[MAX_THREADS] = { 0 };*/
207 static void *thread_start(void *arg)
214 log_t *log = global_log + id*MAX_ITERATIONS;
217 unsigned long r = ((unsigned long)arg)+3; /*RDTICK();*/
218 unsigned int prop = proportion;
219 unsigned int _max_key = max_key;
222 i = processor_bind(P_LWPID, P_MYID, processors[id], NULL);
225 printf("Failed to bind to processor %d! (%d)\n", processors[id], i);
232 _init_ptst_subsystem();
233 _init_gc_subsystem();
234 _init_set_subsystem();
235 shared.set = set_alloc();
238 /* BARRIER FOR ALL THREADS */
240 int n_id, id = threads_initialised1;
241 while ( (n_id = CASIO(&threads_initialised1, id, id+1)) != id )
244 while ( threads_initialised1 != num_threads ) MB();
247 /* Start search structure off with a well-distributed set of inital keys */
248 for ( i = (_max_key / num_threads); i != 0; i >>= 1 )
250 for ( k = i >> 1; k < (_max_key / num_threads); k += i )
252 set_update(shared.set,
253 k + id * (_max_key / num_threads),
254 (void *)0xdeadbee0, 1);
260 int n_id, id = threads_initialised2;
261 while ( (n_id = CASIO(&threads_initialised2, id, id+1)) != id )
264 while ( threads_initialised2 != num_threads ) MB();
268 (void)signal(SIGALRM, &alarm_handler);
269 (void)alarm(MAX_WALL_TIME);
271 gettimeofday(&start_time, NULL);
282 get_interval(my_int);
284 for ( i = 0; (i < MAX_ITERATIONS) && !shared.alarm_time; i++ )
286 /* O-3: ignore ; 4-11: proportion ; 12: ins/del */
287 k = (nrand(r) >> 4) & (_max_key - 1);
292 if ( ((r>>4)&255) < prop )
294 ov = v = set_lookup(shared.set, k);
296 else if ( ((r>>12)&1) )
298 v = (void *)((r&~7)|0x8);
299 ov = set_update(shared.set, k, v, 1);
304 ov = set_remove(shared.set, k);
308 get_interval(my_int);
317 /* BARRIER FOR ALL THREADS */
319 int n_id, id = threads_initialised3;
320 while ( (n_id = CASIO(&threads_initialised3, id, id+1)) != id )
323 while ( threads_initialised3 != num_threads ) MB();
328 extern void check_tree(set_t *);
329 check_tree(shared.set);
333 if ( id == num_threads - 1 )
335 gettimeofday(&done_time, NULL);
338 _destroy_gc_subsystem();
346 #define THREAD_TEST thread_start
347 #define THREAD_FLAGS THR_BOUND
350 static pthread_attr_t attr;
353 static void test_multithreaded (void)
356 pthread_t thrs[MAX_THREADS];
358 int min_successes, max_successes;
359 int ticksps = sysconf(_SC_CLK_TCK);
360 float wall_time, user_time, sys_time;
362 if ( num_threads == 1 ) goto skip_thread_creation;
365 i = pthread_attr_init (&attr);
367 fprintf (stderr, "URK! pthread_attr_init rc=%d\n", i);
369 i = pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
371 fprintf (stderr, "URK! pthread_attr_setscope rc=%d\n", i);
376 pthread_setconcurrency(num_threads + 1);
378 pthread_setconcurrency(num_threads);
381 for (i = 0; i < num_threads; i ++)
385 pthread_create (&thrs[i], &attr, THREAD_TEST, (void *)i);
387 pthread_create (&thrs[i], NULL, THREAD_TEST, (void *)i);
391 skip_thread_creation:
392 if ( num_threads == 1 )
398 for (i = 0; i < num_threads; i ++)
400 (void)pthread_join (thrs[i], NULL);
404 wall_time = (float)(TVAL(done_time) - TVAL(start_time))/ 1000000;
405 user_time = ((float)(done_tms.tms_utime - start_tms.tms_utime))/ticksps;
406 sys_time = ((float)(done_tms.tms_stime - start_tms.tms_stime))/ticksps;
408 log_float ("wall_time_s", wall_time);
409 log_float ("user_time_s", user_time);
410 log_float ("system_time_s", sys_time);
413 min_successes = INT_MAX;
414 max_successes = INT_MIN;
415 for ( i = 0; i < num_threads; i++ )
417 num_successes += successes[i];
418 if ( successes[i] < min_successes ) min_successes = successes[i];
419 if ( successes[i] > max_successes ) max_successes = successes[i];
422 log_int ("min_successes", min_successes);
423 log_int ("max_successes", max_successes);
424 log_int ("num_successes", num_successes);
426 log_float("us_per_success", (num_threads*wall_time*1000000.0)/num_successes);
428 log_int("log max key", log_max_key);
432 static void tstp_handler(int sig, siginfo_t *info, ucontext_t *uc)
434 static unsigned int sem = 0;
435 unsigned long *esp = (unsigned long *)(uc->uc_mcontext.gregs[7]);
438 while ( CASIO(&sem, 0, 1) != 0 ) sched_yield();
440 printf("Signal %d for pid %d\n", sig, pid);
441 printf("%d: EIP=%08x EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", pid,
442 uc->uc_mcontext.gregs[14], uc->uc_mcontext.gregs[11],
443 uc->uc_mcontext.gregs[ 8], uc->uc_mcontext.gregs[10],
444 uc->uc_mcontext.gregs[ 9]);
445 printf("%d: ESP=%08x EBP=%08x ESI=%08x EDI=%08x EFL=%08x\n", pid,
446 uc->uc_mcontext.gregs[ 7], uc->uc_mcontext.gregs[ 6],
447 uc->uc_mcontext.gregs[ 5], uc->uc_mcontext.gregs[ 4],
448 uc->uc_mcontext.gregs[16]);
453 for ( ; ; ) sched_yield();
457 int main (int argc, char **argv)
461 unsigned long log_header[] = { 0, MAX_ITERATIONS, 0 };
465 printf("%s <num_threads> <read_proportion> <key power> <log name>\n"
466 "(0 <= read_proportion <= 256)\n", argv[0]);
472 printf("%s <num_threads> <read_proportion> <key power>\n"
473 "(0 <= read_proportion <= 256)\n", argv[0]);
478 memset(&shared, 0, sizeof(shared));
480 num_threads = atoi(argv[1]);
481 log_int ("num_threads", num_threads);
483 proportion = atoi(argv[2]);
484 log_float ("frac_reads", (float)proportion/256.0);
486 log_max_key = atoi(argv[3]);
487 max_key = 1 << atoi(argv[3]);
488 log_int("max_key", max_key);
490 log_int ("max_iterations", MAX_ITERATIONS);
492 log_int ("wall_time_limit_s", MAX_WALL_TIME);
496 int st, maxcpu = sysconf(_SC_CPUID_MAX), i, j=0;
498 /* Favour processors that don't handle I/O interrupts. */
499 for ( i = 0; i <= maxcpu; i++ )
501 st = p_online(i, P_STATUS);
502 if ( st == P_NOINTR )
504 if ( j == num_threads ) break;
506 if ( j == num_threads ) break;
510 /* Fall back to the system quads if necessary. */
511 for ( i = 0; i <= maxcpu; i++ )
513 st = p_online(i, P_STATUS);
514 if ( st == P_ONLINE )
516 if ( j == num_threads ) break;
518 if ( j == num_threads ) break;
522 if ( j != num_threads )
524 printf("Urk! Not enough CPUs for threads (%d < %d)\n",
532 log_header[0] = num_threads;
533 log_header[2] = max_key;
534 global_log = malloc(SIZEOF_GLOBAL_LOG);
539 struct sigaction act;
540 memset(&act, 0, sizeof(act));
541 act.sa_handler = (void *)tstp_handler;
542 act.sa_flags = SA_SIGINFO;
543 sigaction(SIGTSTP, &act, NULL);
544 sigaction(SIGQUIT, &act, NULL);
545 sigaction(SIGSEGV, &act, NULL);
549 test_multithreaded ();
554 printf("Writing log...\n");
555 /* Write logs to data file */
556 fd = open(argv[4], O_WRONLY | O_CREAT | O_TRUNC, 0644);
559 fprintf(stderr, "Error writing log!\n");
563 if ( (write(fd, log_header, sizeof(log_header)) != sizeof(log_header)) ||
564 (write(fd, global_log, SIZEOF_GLOBAL_LOG) != SIZEOF_GLOBAL_LOG) )
566 fprintf(stderr, "Log write truncated or erroneous\n");