1 /* BLURB gpl
2
3 Coda File System
4 Release 5
5
6 Copyright (c) 1987-2016 Carnegie Mellon University
7 Additional copyrights listed below
8
9 This code is distributed "AS IS" without warranty of any kind under
10 the terms of the GNU General Public Licence Version 2, as shown in the
11 file LICENSE. The technical and financial contributors to Coda are
12 listed in the file CREDITS.
13
14 Additional copyrights
15 none currently
16
17 #*/
18
19 /*
20 *
21 * RVM Stress Test Program
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #include <string.h>
40 #include <time.h>
41
42 #include <rvm/rvm.h>
43 #include <rvm/rvm_statistics.h>
44 #include <rvm/rvm_segment.h>
45 #include <rvm/rds.h>
46
47 #ifdef __CYGWIN32__
48 /* XXX MJC: hack -- no random(), srandom() so use rand() (and forget about
49 setting seeds for now */
50 #define random rand
51 #define srandom
52 #endif
53
54 #ifndef RVM_MAJOR_VERSION
55 #define RVM_MAJOR_VERSION 1
56 #endif /* RVM_MAJOR_VERSION */
57 #ifndef RVM_MINOR_VERSION
58 #define RVM_MINOR_VERSION 3
59 #endif /* RVM_MINOR_VERSION */
60 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
61 #include "rvm_query.h"
62 #endif /* VERSION_TEST */
63
64 #ifdef RVM_USELWP
65 #include "rvm_lwp.h"
66 #elif defined(RVM_USEPT)
67 #include "rvm_pthread.h"
68 #else /* fake cthreads wrapper */
69 /* XXX bogus by Eric and Peter to get compile */
70 #include <cthreads.h>
71 /* define types symbolically to permit use of non-Cthread thread support */
72 #define RVM_MUTEX struct mutex
73 #define RVM_CONDITION struct condition
74 #endif
75
76 extern rvm_region_def_t *RegionDefs; /* hooks to rds */
77 extern long NRegionDefs;
78 extern rvm_bool_t rds_testsw; /* special test mode switch */
79
80 #ifdef CODA_ASSERT
81 #undef CODA_ASSERT
82 #endif
83 #define CODA_ASSERT(ex) \
84 { \
85 if (!(ex)) \
86 { \
87 fprintf(stderr,"ASSERTion failed: file \"%s\", line %d\n", \
88 __FILE__, __LINE__); \
89 fflush(stderr); \
90 abort(); \
91 } \
92 }
93
94 #undef CRITICAL
95 #define CRITICAL(lock,body) do { \
96 mutex_lock(&lock); { body } mutex_unlock(&lock); \
97 } while(0)
98
99 typedef struct list_entry_s
100 {
101 struct list_entry_s *nextentry; /* in accordance with insque(3) */
102 struct list_entry_s *preventry;
103 union
104 {
105 struct list_entry_s *name; /* back pointer to head of list */
106 int length; /* length of list if header */
107 } list;
108 rvm_bool_t is_header; /* true if list header */
109 }
110 list_entry_t;
111
112 typedef struct
113 {
114 list_entry_t links; /* allocated list links */
115 int size; /* usable size of block */
116 rvm_length_t chksum; /* block checksum */
117 char *ptr; /* ptr to rds allocated space */
118 }
119 block_t;
120 /* system variables */
121 #define CMD_MAX 2048 /* maximum cmd line length */
122 static char cmd_line[CMD_MAX]; /* command line buffer */
123 static char *cmd_cur; /* ptr to current command line
124 position */
125
126 list_entry_t alloc_list; /* list of allocated blocks */
127 RVM_MUTEX alloc_list_lock; /* protects list header & block links */
128
129 int nthreads = 0; /* Number of threads */
130 cthread_t *threads; /* thread handles vector */
131 int *last; /* last operation of thread */
132 rvm_bool_t Terminate = rvm_false; /* thread exit switch */
133 RVM_MUTEX init_lock; /* syncronize worker start */
134 RVM_MUTEX thread_lock = MUTEX_INITIALIZER; /* lock for thread exit code */
135 RVM_CONDITION init_cv; /* signal thread start completion */
136 RVM_CONDITION thread_exit_code; /* code to signal termination to main */
137
138 RVM_MUTEX chk_lock = MUTEX_INITIALIZER; /* segment checker variables */
139 rvm_bool_t chk_block; /* require threads to block for chk */
140 RVM_CONDITION blk_code; /* blocked threads wait code */
141 RVM_CONDITION chk_code; /* checker wait code */
142 int blk_cnt; /* counter for blocked threads */
143 rvm_length_t optimizations; /* optimizations used in test */
144 int max_cycles; /* maximum operation loop cycles */
145 int max_ranges; /* maximum number ranges/trans */
146 int max_trans; /* max number trans per modify test */
147 int max_block_size; /* maximum modification block size */
148 int max_mod_size; /* maximum modification size */
149 int max_moby_size; /* maximum moby modification size */
150 int num_pre_alloc; /* number of blocks to preallocate */
151 int cycle; /* operation loop cycle count */
152 int op_cnt; /* basher operation count */
153 int max_op_cnt; /* operation count threshold */
154 int chk_range_frac; /* fraction of ranges to check */
155 int abort_frac; /* fraction of trans to abort */
156 int restore_frac; /* fraction of trans to begin in
157 restore mode and commit */
158 int flush_frac; /* fraction of trans to commit/flush */
159 int trunc_frac; /* truncation threshold */
160 int epoch_trunc_frac; /* epoch truncation threshold */
161 int incr_trunc_time; /* incr trunc run time slice */
162 int seed; /* random num gen seed */
163 int chk_alloc; /* allocation checking level */
164 rvm_offset_t DataLen; /* length of data raw partition */
165 char DataFileName[MAXPATHLEN+1]; /* heap segment file name */
166 char LogFileName[MAXPATHLEN+1]; /* log file name */
167 char PlumberFileName[MAXPATHLEN+1]; /* plumber file name */
168 FILE *PlumberFile; /* file descriptor for plumber file */
169 struct timeval init_time; /* time when test run started */
170 rvm_length_t rec_buf_len; /* recovery buffer length */
171 rvm_length_t flush_buf_len; /* flush buffer length */
172 rvm_length_t max_read_len; /* maximum read length */
173 rvm_bool_t all_tests; /* do all tests */
174 rvm_bool_t time_tests; /* timestamp op loop if true */
175 rvm_bool_t vm_test; /* compare vm with segment if true */
176 rvm_bool_t moby_test; /* do large range test if true */
177 rvm_bool_t chk_sum_sw; /* request checksumming */
178 rvm_bool_t no_yield_sw; /* request no-yield truncations */
179 rvm_bool_t vm_protect_sw; /* request vm buffer protection */
180 rvm_bool_t pre_alloc_trunc; /* truncate after preallocation */
181 rvm_bool_t show_brk; /* print break point */
182 rvm_bool_t do_private_map; /* Do a private mapping */
183
184 FILE *para_file; /* parameter file */
185
186 /* string name lookup entry declarations */
187
188 typedef enum
189 {
190 UNKNOWN = -123456789, /* unknown string key */
191
192 ALL_KEY = 1, /* key for do all entities */
193 ABORT_KEY, /* set abort fraction key */
194 BLOCK_SIZE_KEY, /* allocation block size key */
195 BRK_KEY, /* show break point key */
196 CHK_ALLOC_KEY, /* allocation checker key */
197 CHK_SUM_KEY, /* rvm_chk_sum key */
198 CYCLES_KEY, /* number of cycles key */
199 DATA_KEY, /* set data file key */
200 FLUSH_KEY, /* set flush fraction key */
201 FLUSH_BUF_KEY, /* set flush buffer length key */
202 INCR_KEY, /* enable incrmental truncation key */
203 LOG_KEY, /* set log file key */
204 MAX_READ_KEY, /* set max read length key */
205 MOBY_KEY, /* moby range test key */
206 MOBY_MAX_KEY, /* maximum moby range size key */
207 MOD_SIZE_KEY, /* maximum modification size key */
208 NONE_KEY, /* no choices key */
209 OPS_KEY, /* number of operations/cycle key */
210 OPT_KEY, /* set optimizations key */
211 PARMS_KEY, /* show test parameters key */
212 PLUMBER_KEY, /* setup plumber file key */
213 PRE_ALLOC_KEY, /* number of blocks to preallocate */
214 PRE_ALLOC_TRUNC_KEY, /* truncate after preallocation */
215 PRIORITY_KEY, /* set run priority */
216 QUIT_KEY, /* quit program key */
217 RANGES_KEY, /* set num ranges key */
218 REC_BUF_KEY, /* set recovery buffer length */
219 RESTORE_KEY, /* set restore fraction key */
220 RUN_KEY, /* start tests key */
221 SEED_KEY, /* random num gen key */
222 THREADS_KEY, /* set num threads key */
223 TIME_KEY, /* timestamp cycle key */
224 TRANS_KEY, /* set num trans key */
225 TRUNC_KEY, /* set truncation fraction key */
226 EPOCH_TRUNC_KEY, /* set epoch truncation fraction key */
227 INCR_TRUNC_TIME_KEY, /* set incr trunc time slice key */
228 VM_KEY, /* key for vm check */
229 CHK_RANGE_KEY, /* set chk_range fraction key */
230 NO_YIELD_KEY, /* set no_yield truncation mode */
231 VM_PROT_KEY, /* request vm buffer protection */
232 VM_MAP_PRIV /* set RVM_MAP_PRIVATE option */
233 }
234 key_id_t;
235
236 #define STR_NAME_LEN 31 /* maximum length of string name */
237
238 typedef struct /* string name vector entry */
239 {
240 char str_name[STR_NAME_LEN+1]; /* character string for name */
241 key_id_t key;
242 }
243 str_name_entry_t;
244
245 /* test parameter defaults */
246
247 #define FLUSH_DEFAULT 20
248 #define ABORT_DEFAULT 10
249 #define RESTORE_DEFAULT 20
250 #define TRANS_DEFAULT 10
251 #define RANGES_DEFAULT 100
252 #define CYCLES_DEFAULT -1
253 #define OP_CNT_DEFAULT 1000
254 #define THREADS_DEFAULT 25
255 #define BLOCK_SIZE_DEFAULT 10000
256 #define MOD_SIZE_DEFAULT 10000
257 #define MOBY_MOD_SIZE_DEFAULT 1000000
258 #define PRE_ALLOC_DEFAULT 1000
259 #define SEED_DEFAULT 1
260 #define CHK_ALLOC_DEFAULT 0
261 #define CHK_RANGE_DEFAULT 0
262 /* list maintainance functions */
263
264 /* list header initializer */
init_list_head(whichlist)265 static void init_list_head(whichlist)
266 list_entry_t *whichlist; /* pointer to list header */
267 {
268 whichlist->nextentry = whichlist; /* pointers are to self now */
269 whichlist->preventry = whichlist;
270 whichlist->list.length = 0; /* list is empty */
271 whichlist->is_header = rvm_true; /* mark header */
272 }
273
274 /* list entry initializer */
init_list_ent(entry)275 static void init_list_ent(entry)
276 list_entry_t *entry;
277 {
278 entry->nextentry = NULL;
279 entry->preventry = NULL;
280 entry->list.name = NULL;
281 entry->is_header = rvm_false;
282 }
283 /* list entry mover */
move_list_ent(fromptr,toptr,victim)284 static list_entry_t *move_list_ent(fromptr, toptr, victim)
285 register list_entry_t *fromptr; /* from list header */
286 register list_entry_t *toptr; /* to list header */
287 register list_entry_t *victim; /* pointer to entry to be moved */
288 {
289
290 if (fromptr != NULL)
291 {
292 CODA_ASSERT(fromptr->is_header);
293 if ((victim == NULL) && (fromptr->list.length == 0))
294 return NULL;
295 else
296 {
297 if (victim == NULL) /* choose 1st if no victim */
298 victim = fromptr->nextentry;
299 CODA_ASSERT(!victim->is_header);
300 CODA_ASSERT(victim->list.name == fromptr);
301
302 /* remque((void *)victim); */ /* unlink from first list */
303 if (victim->nextentry)
304 victim->nextentry->preventry = victim->preventry;
305 if (victim->preventry)
306 victim->preventry->nextentry = victim->nextentry;
307 victim->preventry = victim->nextentry = NULL;
308
309 fromptr->list.length --;
310 }
311 }
312 else
313 {
314 CODA_ASSERT(victim != NULL);
315 CODA_ASSERT(!victim->is_header);
316 CODA_ASSERT(toptr != NULL);
317 }
318
319 if (toptr != NULL)
320 {
321 CODA_ASSERT(toptr->is_header);
322 victim->list.name = toptr;
323 /* insque((void *)victim,(void *)toptr->preventry); */ /* insert at tail of second list */
324 victim->preventry = toptr->preventry;
325 victim->nextentry = toptr;
326 victim->preventry->nextentry = toptr->preventry = victim;
327 toptr->list.length ++;
328 }
329 else victim->list.name = NULL;
330
331 return victim;
332 }
333 /* Byte-aligned checksum and move functions */
334
335 #define LENGTH_MASK ((rvm_length_t)(~(sizeof(rvm_length_t)-1)))
336 #define ROUND_TO_LENGTH(len) (((rvm_length_t)((rvm_length_t)(len) \
337 +sizeof(rvm_length_t)-1)) \
338 & LENGTH_MASK)
339 #define CHOP_TO_LENGTH(len) ((rvm_length_t)((rvm_length_t)(len) \
340 & LENGTH_MASK))
341 #define ALIGNED_LEN(addr,len) (ROUND_TO_LENGTH((rvm_length_t)(addr) \
342 +(rvm_length_t)(len)) \
343 - CHOP_TO_LENGTH(addr))
344 #define BYTE_SKEW(len) ((rvm_length_t)(len) & ~LENGTH_MASK)
345
346 /* zero-pad unused bytes of word */
zero_pad(word,addr,leading)347 static rvm_length_t zero_pad(word,addr,leading)
348 rvm_length_t word; /* value to be zero-padded */
349 char *addr; /* address of 1st/last byte */
350 rvm_bool_t leading; /* true if leading bytes are zeroed */
351 {
352 char *word_array = (char *)&word; /* byte access of word value */
353 int skew = BYTE_SKEW(addr);
354 int i;
355
356 if (leading) /* zero pad leading bytes */
357 {
358 for (i=sizeof(rvm_length_t)-1; i>0; i--)
359 if (i <= skew) word_array[i-1] = 0;
360 }
361 else /* zero pad trailing bytes */
362 {
363 for (i=0; i<(sizeof(rvm_length_t)-1); i++)
364 if (i >= skew) word_array[i+1] = 0;
365 }
366
367 return word;
368 }
369 /* checksum function: forms checksum of arbitrarily aligned range
370 by copying preceeding, trailing bytes to make length 0 mod length size */
check_sum(nvaddr,len)371 static rvm_length_t check_sum(nvaddr,len)
372 char *nvaddr; /* address of 1st byte */
373 rvm_length_t len; /* byte count */
374 {
375 rvm_length_t *base; /* 0 mod sizeof(rvm_length_t) addr */
376 rvm_length_t length; /* number of words to sum */
377 rvm_length_t chk_sum; /* check sum temp */
378 rvm_length_t i;
379
380 if (len == 0) return 0;
381
382 /* get zero-byte aligned base address & length of region */
383 base = (rvm_length_t *)CHOP_TO_LENGTH(nvaddr);
384 length = (ALIGNED_LEN(nvaddr,len)/sizeof(rvm_length_t)) - 1;
385
386 /* process boundary words */
387 chk_sum = zero_pad(*base,nvaddr,rvm_true);
388 if (length >= 2)
389 chk_sum += zero_pad(base[length--],&nvaddr[len-1],rvm_false);
390 if (length <= 1) return chk_sum;
391
392 /* form check sum of remaining full words */
393 for (i=1; i < length; i++)
394 chk_sum += base[i];
395
396 return chk_sum;
397 }
398 /* test block check sum */
test_chk_sum(block)399 static rvm_bool_t test_chk_sum(block)
400 block_t *block;
401 {
402 rvm_length_t chksum;
403
404 chksum = check_sum(block->ptr,block->size);
405 if (chksum != block->chksum)
406 {
407 fprintf(stderr, "chktst %p, %ld\n", block->ptr, chksum);
408 printf("\n? Block checksum doesn't match\n");
409 CODA_ASSERT(rvm_false);
410 }
411
412 return rvm_true;
413 }
414 /* pick random block from alloc list */
pick_random()415 static block_t *pick_random()
416 {
417 block_t *block; /* allocated block descriptor */
418 int i;
419
420 /* exit if list empty */
421 if (alloc_list.list.length == 0)
422 return NULL;
423
424 #if 0
425 /* check checksums of all blocks on the list */
426 block = (block_t *)alloc_list.nextentry;
427 for (i = alloc_list.list.length; i > 0;i--) {
428 block = (block_t *)block->links.nextentry;
429 test_chk_sum(block);
430 }
431 #endif
432
433 /* pick a random block */
434 block = (block_t *)alloc_list.nextentry;
435 for (i = random() % alloc_list.list.length; i > 0;i--)
436 block = (block_t *)block->links.nextentry;
437
438 return block;
439 }
440 /* allocator */
do_malloc(id)441 static void do_malloc(id)
442 int id; /* thread id */
443 {
444 rvm_tid_t tid; /* transaction identifier */
445 rvm_return_t ret; /* rvm error return */
446 int err; /* rds error return */
447 block_t *block; /* allocated block descriptor */
448
449 /* pick a size and allocate a block in recoverable heap */
450 block = (block_t *)malloc(sizeof(block_t));
451 init_list_ent(&block->links);
452 block->size = random() % max_block_size;
453 if (block->size == 0) block->size = 1;
454 block->ptr = rds_malloc(block->size, 0, &err);
455 if (err != SUCCESS)
456 {
457 if (err > SUCCESS)
458 printf("\n%d: rds_malloc = %s\n", id,
459 /* rvm_return((rvm_return_t *)err)); XXX BOGUS JET */
460 rvm_return((rvm_return_t)err));
461 else
462 {
463 if (err == ENO_ROOM) return;
464 printf("\n%d: rds_malloc = %d\n", id, err);
465 }
466 CODA_ASSERT(rvm_false);
467 }
468
469 /* transactionally clear the allocated space */
470 rvm_init_tid(&tid);
471 if ((ret=rvm_begin_transaction(&tid,no_restore))
472 != RVM_SUCCESS)
473 {
474 printf("\n%d: ERROR: malloc begin_trans, code: %s\n",
475 id,rvm_return(ret));
476 CODA_ASSERT(rvm_false);
477 }
478 if ((ret=rvm_set_range(&tid,block->ptr,block->size))
479 != RVM_SUCCESS)
480 {
481 printf("\n%d: ERROR: malloc set_range, code: %s\n",
482 id,rvm_return(ret));
483 CODA_ASSERT(rvm_false);
484 }
485 memset(block->ptr, 0, block->size); /* blow away obsolete guards */
486 block->chksum = 0;
487 /* commit the block */
488 if ((ret=rvm_end_transaction(&tid,no_flush)) != RVM_SUCCESS)
489 {
490 printf("\n%d: ERROR: alloc end_trans, code: %s\n",
491 id,rvm_return(ret));
492 CODA_ASSERT(rvm_false);
493 }
494
495 /* put the block on the allocated list */
496 CRITICAL(alloc_list_lock, /* begin alloc list crit sec */
497 {
498 (void)move_list_ent(NULL,&alloc_list,(list_entry_t *)block);
499 }); /* end alloc list crit sec */
500
501 }
502 /* deallocator function */
do_free(id)503 static void do_free(id)
504 int id; /* thread id */
505 {
506 int err; /* rds error return */
507 block_t *block; /* allocated block descriptor */
508
509 CRITICAL(alloc_list_lock, /* begin alloc list crit sec */
510 {
511 /* select a random entry */
512 if ((block=pick_random()) == NULL)
513 {
514 /* exit if list empty */
515 mutex_unlock(&alloc_list_lock);
516 return;
517 }
518
519 /* unlink the block */
520 (void)move_list_ent(&alloc_list,NULL,(list_entry_t *)block);
521 }); /* end alloc list crit sec */
522
523 /* check sum */
524 test_chk_sum(block);
525
526 /* free the selected block */
527 rds_free(block->ptr, 0, &err);
528 if (err != SUCCESS)
529 {
530 if (err > SUCCESS)
531 printf("\n%d: rds_free = %s\n", id,
532 /* rvm_return((rvm_return_t *)err)); */
533 rvm_return((rvm_return_t)err));
534 else
535 printf("\n%d: rds_free = %d\n", id, err);
536 CODA_ASSERT(rvm_false);
537 }
538
539 /* deallocate list entry */
540 free(block);
541 }
542 /* rvm_chk_range test */
test_chk_range(tid,addr,len,id)543 static void test_chk_range(tid,addr,len,id)
544 rvm_tid_t *tid;
545 char *addr;
546 rvm_length_t len;
547 int id; /* thread id */
548 {
549 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
550 rvm_return_t ret; /* rvm return code */
551 /* test if range is declared in tid */
552 if ((ret = rvm_chk_range(tid,addr,len))
553 != RVM_SUCCESS)
554 {
555 printf("\n%d: ERROR: modify chk_range, code: %s\n",
556 id,rvm_return(ret));
557 CODA_ASSERT(rvm_false);
558 }
559
560 /* modify range and re-test: should fail */
561 if ((ret = rvm_chk_range(tid,addr,len+1))
562 != RVM_ENO_RANGE)
563 {
564 printf("\n%d: ERROR: modify chk_range, code: %s\n",
565 id,rvm_return(ret));
566 CODA_ASSERT(rvm_false);
567 }
568
569 if ((ret = rvm_chk_range(tid,addr+1,len))
570 != RVM_ENO_RANGE)
571 {
572 printf("\n%d: ERROR: modify chk_range, code: %s\n",
573 id,rvm_return(ret));
574 CODA_ASSERT(rvm_false);
575 }
576 #endif /* VERSION_TEST */
577 }
578 /* block modifier transaction */
do_trans(block,range_list,do_flush,id)579 static void do_trans(block,range_list,do_flush,id)
580 block_t *block; /* block descriptor */
581 block_t *range_list; /* list of modification ranges */
582 rvm_bool_t do_flush;
583 int id; /* thread id */
584 {
585 int start,finish,temp,i,j;
586 int n_ranges;
587 block_t *range;
588 char *save_area = NULL;
589 char new_val;
590 rvm_bool_t do_abort = rvm_false;
591 rvm_tid_t tid;
592 rvm_mode_t start_mode = no_restore;
593 rvm_mode_t commit_mode = no_flush;
594 rvm_return_t ret; /* rvm error return */
595
596 /* choose number of ranges and whether to abort */
597 n_ranges = random() % max_ranges;
598 if ((random() % 100) < abort_frac)
599 {
600 do_abort = rvm_true;
601 save_area = malloc(block->size);
602 CODA_ASSERT(save_area != NULL);
603 memcpy(save_area, block->ptr, block->size);
604 start_mode = restore;
605 }
606 else
607 if ((random() % 100) < restore_frac)
608 start_mode = restore; /* force test of existing data buffers */
609
610 /* prepare a transaction */
611 rvm_init_tid(&tid);
612 if ((ret=rvm_begin_transaction(&tid,start_mode))
613 != RVM_SUCCESS)
614 {
615 printf("\n%d: ERROR: modify begin_trans, code: %s\n",
616 id,rvm_return(ret));
617 CODA_ASSERT(rvm_false);
618 }
619 /* pick random ranges and modifications */
620 for (j=0; j<n_ranges; j++)
621 {
622 /* select a random range within the recoverable block */
623 range = (block_t *)malloc(sizeof(block_t));
624 CODA_ASSERT(range != NULL);
625 init_list_ent(&range->links);
626 start = random() % block->size;
627 temp = finish = random() % block->size;
628 if (start > finish)
629 {
630 finish = start;
631 start = temp;
632 }
633 range->ptr = &block->ptr[start];
634 range->size = finish-start+1;
635 if (range->size > max_mod_size)
636 range->size = random() % max_mod_size;
637 move_list_ent(NULL,range_list,range);
638
639 /* tell RVM */
640 if ((ret=rvm_set_range(&tid,range->ptr,range->size))
641 != RVM_SUCCESS)
642 {
643 printf("\n%d: ERROR: modify set_range, code: %s\n",
644 id,rvm_return(ret));
645 CODA_ASSERT(rvm_false);
646 }
647 /* see if range should be checked */
648 if ((random() % 100) < chk_range_frac)
649 test_chk_range(&tid,range->ptr,range->size,id);
650
651 /* set the selected range to random values */
652 new_val = random() % 256;
653 for (i=0; i<range->size; i++)
654 block->ptr[start+i] = new_val;
655 }
656
657 /* commit or abort the changes */
658 if (do_abort)
659 {
660 if ((ret=rvm_abort_transaction(&tid)) != RVM_SUCCESS)
661 {
662 printf("\n%d: ERROR: modify abort_trans, code: %s\n",
663 id,rvm_return(ret));
664 CODA_ASSERT(rvm_false);
665 }
666
667 /* check restoration */
668 for (i=0; i<block->size; i++)
669 if (save_area[i] != block->ptr[i])
670 {
671 printf("\n%d: modified region improperly restored by abort %p[%d]\n", id, block->ptr, i);
672 CODA_ASSERT(rvm_false);
673 }
674 free(save_area);
675 }
676 else
677 {
678 if (do_flush) commit_mode = flush;
679 if ((ret=rvm_end_transaction(&tid,commit_mode)) != RVM_SUCCESS)
680 {
681 printf("\n%d: ERROR: modify end_trans, code: %s\n",
682 id,rvm_return(ret));
683 CODA_ASSERT(rvm_false);
684 }
685 }
686 }
687 /* block modifier */
do_modify(id)688 static void do_modify(id)
689 int id; /* thread id */
690 {
691 int n_trans; /* number of transactions per block */
692 block_t *block; /* block descriptor */
693 block_t range_list; /* list of modification ranges */
694 block_t *range;
695 rvm_bool_t do_flush;
696
697 /* select a random entry */
698 CRITICAL(alloc_list_lock, /* begin alloc list crit sec */
699 {
700 if ((block=pick_random()) != NULL)
701 /* unlink the block */
702 (void)move_list_ent(&alloc_list,NULL,(list_entry_t *)block);
703 }); /* end alloc list crit sec */
704 if (block == NULL) return; /* exit if list empty */
705 test_chk_sum(block); /* test for damage */
706
707 /* pick random number of transactions; modify block */
708 n_trans = random() % max_trans;
709 init_list_head(&range_list);
710
711 /* execute the transactions */
712 while (n_trans-- >= 0)
713 {
714 do_flush = (rvm_bool_t)((random() % 100) < flush_frac);
715 do_trans(block,&range_list,do_flush,id);
716
717 /* insert marker between transactions */
718 range = (block_t *)malloc(sizeof(block_t));
719 CODA_ASSERT(range != NULL);
720 init_list_ent(&range->links);
721 range->size = n_trans+1;
722 range->ptr = NULL;
723 move_list_ent(NULL,&range_list,range);
724 cthread_yield();
725 }
726
727 /* resum block and kill range list */
728 block->chksum = check_sum(block->ptr,block->size);
729 while (range_list.links.nextentry->is_header != rvm_true)
730 {
731 range = (block_t *)move_list_ent(&range_list,NULL,NULL);
732 free(range);
733 }
734 /* put the block back on the allocated list */
735 CRITICAL(alloc_list_lock, /* begin alloc list crit sec */
736 {
737 (void)move_list_ent(NULL,&alloc_list,(list_entry_t *)block);
738 }); /* end alloc list crit sec */
739 }
740 /* region checker for chk_vm */
chk_region(seg_file,region)741 static rvm_bool_t chk_region(seg_file,region)
742 FILE *seg_file;
743 int region; /* index of region */
744 {
745 int j;
746 int c;
747 char *vm;
748 rvm_length_t reg_pos; /* region position */
749 int io_ret;
750
751 /* set up read of region data */
752 reg_pos = RVM_OFFSET_TO_LENGTH(RegionDefs[region].offset);
753 if ((io_ret=fseek(seg_file,reg_pos,0)) != 0)
754 {
755 printf("\n? Can't seek to %lu in segment file, ret = %d\n",
756 reg_pos, io_ret);
757 CODA_ASSERT(rvm_false);
758 }
759
760 /* scan and check loop */
761 vm = RegionDefs[region].vmaddr;
762 for (j=0; j < RegionDefs[region].length; j++)
763 {
764 /* scan file */
765 c = getc(seg_file);
766 if (c == EOF)
767 {
768 printf("\n? EOF encountered while reading segment; "
769 "offset = %lu\n", reg_pos);
770 CODA_ASSERT(rvm_false);
771 }
772 #if 0
773 /* CL */
774 printf("j: %6d; vm:0x%x; region%d:0x%x; reg_pos:%d\n",
775 j, (vm[j] & 255), region, (c & 255), reg_pos);
776 #endif
777 /* check the data against vm */
778 if ((char)c != vm[j])
779 {
780 printf("\n? Error: mapped data doesn't match:\n");
781 printf(" vm[%d] = 0x%x\n",j,(vm[j] & 255));
782 printf(" region%d[%d] = 0x%x\n",region,j,
783 (c & 255));
784 printf(" region offset = %lu\n",reg_pos);
785 CODA_ASSERT(rvm_false);
786 return rvm_false;
787 }
788 reg_pos++;
789 }
790
791 return rvm_true;
792 }
793 /* vm <==> disk comparator */
chk_vm()794 static rvm_bool_t chk_vm()
795 {
796 rvm_return_t ret;
797 FILE *seg_file;
798 int i;
799 int io_ret;
800 rvm_statistics_t *stats;
801 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
802 rvm_query_t *query;
803 #endif /* VERSION_TEST */
804 rvm_return_t retval;
805 rvm_length_t n_recs;
806 rvm_length_t tot_recs;
807
808 if ((stats=rvm_malloc_statistics()) == NULL)
809 {
810 printf("\n? rvm_malloc_statistics failed\n");
811 CODA_ASSERT(rvm_false);
812 }
813 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
814 if ((query=rvm_malloc_query()) == NULL)
815 {
816 printf("\n? rvm_malloc_query failed\n");
817 CODA_ASSERT(rvm_false);
818 }
819 if ((retval=RVM_QUERY(query,NULL)) != RVM_SUCCESS)
820 {
821 printf("\n? rvm_query failed, code: %s\n",
822 rvm_return(ret));
823 CODA_ASSERT(rvm_false);
824 }
825 #endif /* VERSION_TEST */
826 printf("\nChecking segment consistency...\n");
827 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
828 printf(" log head = %d\n",RVM_OFFSET_TO_LENGTH(query->log_head));
829 #endif /* VERSION_TEST */
830
831 /* check vm heap if required */
832 #ifdef RVM_USELWP
833 #ifdef HAS_PLUMBER
834 if (chk_alloc != 0)
835 CheckAllocs("Checking heap before truncation");
836 #endif
837 #endif /* RVM_USELWP */
838
839 /* truncate to sync segement with vm */
840 if ((ret=rvm_truncate()) != RVM_SUCCESS)
841 {
842 printf("\n? rvm_truncate failed, code: %s\n",
843 rvm_return(ret));
844 CODA_ASSERT(rvm_false);
845 }
846
847 /* re-check vm heap if required */
848 #ifdef RVM_USELWP
849 #ifdef HAS_PLUMBER
850 if (chk_alloc != 0)
851 CheckAllocs("Checking heap after truncation");
852 #endif
853 #endif /* RVM_USELWP */
854
855 /* get current state */
856 if ((retval=RVM_STATISTICS(stats)) != RVM_SUCCESS)
857 {
858 printf("\n? rvm_statistics failed, code: %s\n",
859 rvm_return(retval));
860 CODA_ASSERT(rvm_false);
861 }
862 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
863 if ((retval=RVM_QUERY(query,NULL)) != RVM_SUCCESS)
864 {
865 printf("\n? rvm_query failed, code: %s\n",
866 rvm_return(retval));
867 CODA_ASSERT(rvm_false);
868 }
869 #endif /* VERSION_TEST */
870
871 /* record log data */
872 n_recs = stats->n_flush_commit + stats->n_no_flush_commit
873 + stats->n_split + stats->n_special + stats->n_wrap;
874 tot_recs = n_recs+stats->tot_flush_commit+stats->tot_no_flush_commit
875 + stats->tot_split + stats->tot_special + stats->tot_wrap;
876 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
877 printf(" log tail = %d, records written = %d\n",
878 RVM_OFFSET_TO_LENGTH(query->log_tail),tot_recs);
879 printf(" number tree nodes = %d, tree depth = %d\n",
880 query->n_nodes,query->max_depth);
881 #else
882 printf(" records written = %lu\n",tot_recs);
883 #endif /* VERSION_TEST */
884
885 /* open segment file read-only */
886 if ((seg_file = fopen(DataFileName,"rb")) == NULL)
887 {
888 printf("\n? Error opening segment file\n");
889 printf(" errno = %d\n",errno);
890 CODA_ASSERT(rvm_false);
891 }
892 /* check all mapped regions against segment file */
893 for (i=0; i<NRegionDefs; i++)
894 {
895 if (!chk_region(seg_file,i))
896 CODA_ASSERT(rvm_false);
897 }
898
899 /* all's well -- close file & release the other threads */
900 io_ret = fclose(seg_file);
901 if (io_ret)
902 {
903 printf("\n? Error closing segment file\n");
904 printf(" ret = %d, errno = %d\n",ret,errno);
905 CODA_ASSERT(rvm_false);
906 }
907 printf(" memory and segment agree!\n");
908
909 /* reset time */
910 if (gettimeofday(&init_time,NULL) < 0)
911 {
912 perror("? Error getting time of day");
913 CODA_ASSERT(rvm_false);
914 }
915
916 rvm_free_statistics(stats);
917 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
918 rvm_free_query(query);
919 #endif /* VERSION_TEST */
920 return rvm_true;
921 }
922
chk_time()923 static rvm_bool_t chk_time()
924 {
925 struct timeval time;
926
927 /* get current time */
928 if (gettimeofday(&time,NULL) < 0)
929 {
930 perror("? Error getting time of day");
931 return rvm_false;
932 }
933
934 /* print time */
935 printf(" time: %s", ctime(&time.tv_sec));
936 printf(" number of test operations: %d\n", max_op_cnt);
937 printf(" elapsed time: %ld sec.\n", time.tv_sec-init_time.tv_sec);
938
939 init_time = time; /* update loop start time */
940 return rvm_true;
941 }
942
943 /* moby range test */
chk_moby()944 static rvm_bool_t chk_moby()
945 {
946 rvm_length_t length; /* range length */
947 char *start; /* starting offset for range */
948 rvm_length_t temp;
949 int i;
950 char *vm_save; /* data save area for test range */
951 rvm_tid_t tid; /* transaction identifier */
952 rvm_return_t ret; /* rvm error return */
953
954 /* choose a large size for moby range */
955 length = random() % max_moby_size;
956
957 /* pick a starting point for mods */
958 temp = RegionDefs[0].length - length;
959 start = RVM_ADD_LENGTH_TO_ADDR(RegionDefs[0].vmaddr,
960 (random() % temp));
961
962 /* announce test */
963 printf("\nLarge range modification\n addr: %p\n length: %lu\n",
964 start,length);
965
966 /* get a buffer and save vm */
967 if ((vm_save = malloc(length)) == NULL)
968 {
969 printf("? Error: can't allocate buffer for moby test\n");
970 CODA_ASSERT(rvm_false);
971 }
972 memcpy(vm_save, start, length);
973
974 /* set up transaction for moby modification */
975 rvm_init_tid(&tid);
976 if ((ret=rvm_begin_transaction(&tid,no_restore))
977 != RVM_SUCCESS)
978 {
979 printf("? ERROR: chk_moby begin_trans 1, code: %s\n",
980 rvm_return(ret));
981 CODA_ASSERT(rvm_false);
982 }
983 if ((ret=rvm_set_range(&tid,start,length)) != RVM_SUCCESS)
984 {
985 printf("? ERROR: chk_moby set_range 1, code: %s\n",
986 rvm_return(ret));
987 CODA_ASSERT(rvm_false);
988 }
989 /* store random trash in test range & commit */
990 for (i=0; i<length; i++)
991 start[i] = (char)(random() % 256);
992 if ((ret=rvm_end_transaction(&tid,flush)) != RVM_SUCCESS)
993 {
994 printf("? ERROR: chk_moby end_trans 1, code: %s\n",
995 rvm_return(ret));
996 CODA_ASSERT(rvm_false);
997 }
998
999 /* check the results and restore the test range contents */
1000 if (chk_vm() == rvm_false) return rvm_false;
1001 printf("\n Restoring original data\n");
1002 if ((ret=rvm_begin_transaction(&tid,no_restore))
1003 != RVM_SUCCESS)
1004 {
1005 printf("? ERROR: chk_moby begin_trans 2, code: %s\n",
1006 rvm_return(ret));
1007 CODA_ASSERT(rvm_false);
1008 }
1009 if ((ret=rvm_set_range(&tid,start,length)) != RVM_SUCCESS)
1010 {
1011 printf("? ERROR: chk_moby set_range 2, code: %s\n",
1012 rvm_return(ret));
1013 CODA_ASSERT(rvm_false);
1014 }
1015 memcpy(start, vm_save, length);
1016 if ((ret=rvm_end_transaction(&tid,flush)) != RVM_SUCCESS)
1017 {
1018 printf("? ERROR: chk_moby end_trans 2, code: %s\n",
1019 rvm_return(ret));
1020 CODA_ASSERT(rvm_false);
1021 }
1022
1023 free(vm_save);
1024 return rvm_true;
1025 }
1026 /* test monitor */
monitor()1027 static void monitor()
1028 {
1029
1030 mutex_lock(&chk_lock); /* begin chk_lock crit sec */
1031 if (chk_block)
1032 {
1033 /* block while check is done */
1034 blk_cnt++;
1035 condition_signal(&chk_code);
1036 while (chk_block)
1037 condition_wait(&blk_code,&chk_lock);
1038 }
1039
1040 /* count operations and become chk thread if at threshold */
1041 if ((op_cnt-- ) == 0)
1042 {
1043 /* block other worker threads and truncate */
1044 chk_block = rvm_true;
1045 if (nthreads > 1)
1046 while (blk_cnt != (nthreads-1))
1047 condition_wait(&chk_code,&chk_lock);
1048
1049 /* do monitoring tests */
1050 printf("\nEnd test cycle %5d\n",cycle);
1051 if (time_tests) /* timestamp the loop */
1052 if (!chk_time()) goto err_exit;
1053 if (moby_test) /* test large range */
1054 if (!chk_moby()) goto err_exit;
1055 if (vm_test) /* compare vm with segment */
1056 if (!chk_vm()) goto err_exit;
1057
1058 chk_block = rvm_false;
1059 blk_cnt = 0;
1060 op_cnt = max_op_cnt;
1061 if (((cycle++) >= max_cycles) && (max_cycles != -1))
1062 Terminate = rvm_true;
1063 condition_broadcast(&blk_code);
1064 }
1065 goto exit;
1066
1067 err_exit:
1068 Terminate = rvm_true;
1069 exit:
1070 mutex_unlock(&chk_lock); /* end chk_lock crit sec */
1071 return;
1072 }
1073 /* testing thread function */
worker(void * idp)1074 static void worker(void *idp)
1075 {
1076 int id = *(int *)idp;
1077
1078 CRITICAL(init_lock,
1079 printf("Worker thread %d running...\n\n",id);
1080 condition_signal(&init_cv); /* wake up main thread */
1081 );
1082
1083 while (!Terminate)
1084 {
1085 monitor(); /* do monitoring functions */
1086
1087 last[id] = 1;
1088 do_malloc(id); /* allocate a recoverable heap block */
1089 cthread_yield();
1090
1091 last[id] = 2;
1092 do_free(id); /* free a recoverable heap block */
1093 cthread_yield();
1094
1095 last[id] = 3;
1096 do_modify(id); /* modify a recoverable heap block */
1097
1098 cthread_yield();
1099 }
1100
1101 /* signal termination */
1102 if (--nthreads == 0)
1103 condition_signal(&thread_exit_code);
1104 cthread_exit(0);
1105 return;
1106 }
1107 /* string name lookup: accepts minimum substring for match */
lookup_str_name(str,str_vec,ambig_str)1108 static int lookup_str_name(str,str_vec,ambig_str)
1109 char *str; /* name to lookup */
1110 str_name_entry_t *str_vec; /* defining vector */
1111 char *ambig_str; /* ambiguous name type */
1112 {
1113 int i = 0; /* loop counter */
1114 int str_index = (int)UNKNOWN; /* string index in vector */
1115
1116 while (str_vec[i].str_name[0] != '\0')
1117 {
1118 /* test if name string starts with str */
1119 if (strstr(str_vec[i].str_name,str) ==
1120 str_vec[i].str_name)
1121 {
1122 /* yes, candidate found -- test further */
1123 if (strcmp(str_vec[i].str_name,str) == 0)
1124 return i; /* exact match, select this name */
1125 if (str_index == (int)UNKNOWN)
1126 str_index = i; /* substring match, remember name */
1127 else
1128 { /* error: ambigous name */
1129 fprintf(stderr,"? %s: ambiguous %s: %s or %s?\n",
1130 str,
1131 ambig_str,
1132 str_vec[i].str_name,
1133 str_vec[str_index].str_name);
1134 return (int)UNKNOWN;
1135 }
1136 }
1137 i++;
1138 }
1139
1140 /* see if name not found */
1141 if (str_index == (int)UNKNOWN)
1142 fprintf(stderr,"? %s: %s not found\n",str,ambig_str);
1143
1144 return str_index;
1145 }
1146 /* scanner utilities */
1147
1148 /* cmd line cursor incrementor */
1149 #define incr_cur(_i) cmd_cur = &cmd_cur[_i]
1150
1151 /* tests for end of line characters */
1152 #define end_line(c) (((c) == '\0') || ((c) == '\n'))
1153 #define scan_stop(c) (end_line(c) || ((c) == '#'))
1154
skip_white(ptr)1155 static void skip_white(ptr)
1156 char **ptr;
1157 {
1158 while (isspace(**ptr))
1159 (*ptr)++;
1160 }
1161
1162 /* string scanner */
scan_str(str,len)1163 static int scan_str(str,len)
1164 char *str; /* ptr to string buffer */
1165 int len; /* maximum length */
1166 {
1167 int indx = 0;
1168
1169 skip_white(&cmd_cur);
1170 while (!scan_stop(*cmd_cur) && (!isspace(*cmd_cur))
1171 && (indx < len))
1172 str[indx++] = *(cmd_cur++);
1173
1174 str[indx] = '\0';
1175
1176 return indx; /* return length */
1177 }
1178 /* integer scanner & range checker */
scan_int(low_range,high_range,default_val,name_str,err_str)1179 static int scan_int(low_range,high_range,default_val,name_str,err_str)
1180 int low_range;
1181 int high_range;
1182 int default_val;
1183 char *name_str;
1184 char *err_str;
1185 {
1186 int val;
1187
1188 /* be sure there's something there */
1189 skip_white(&cmd_cur);
1190 if (scan_stop(*cmd_cur))
1191 {
1192 printf("? No parameter given for %s\n",name_str);
1193 return 0;
1194 }
1195
1196 /* scan as interger */
1197 val = strtol(cmd_cur,&cmd_cur,0);
1198
1199 /* check range */
1200 #if 0
1201 /* I guess this code fragment is wrong, under this, when (low_range != 0)
1202 * val will be return no matter whatever value it is. More reasonable
1203 * behaviour should be returning val only when
1204 * (either low_range or high_range is non-zero) AND
1205 * (val fall within range) -- clement
1206 */
1207 if ((low_range != 0) || (high_range != 0)
1208 && ((val >= low_range) && (val <= high_range)))
1209 return val;
1210 #endif
1211 if ( ((low_range != 0) || (high_range != 0))
1212 && ((val >= low_range) && (val <= high_range)) )
1213 return val ;
1214
1215 /* out of range - print message, return default */
1216 printf("? Warning: %d is out of range %d: %d for %s\n",val,
1217 low_range,high_range,name_str);
1218 printf(" %d assigned as default\n",default_val);
1219
1220 return default_val;
1221 }
1222 /* read prompted line from terminal */
read_prompt_line(prompt,null_ok)1223 static char *read_prompt_line(prompt,null_ok)
1224 char *prompt; /* prompt string */
1225 rvm_bool_t null_ok; /* true if null input ok */
1226 {
1227
1228 /* read from input stream if nothing left in command line */
1229 skip_white(&cmd_cur);
1230 if (scan_stop(*cmd_cur) && (! null_ok))
1231 while (rvm_true)
1232 {
1233 /* prompt if required */
1234 cmd_line[0] = '\0';
1235 if (prompt != NULL)
1236 printf("%s ",prompt);
1237
1238 /* get line and check termination conditions */
1239 cmd_cur = fgets(cmd_line,CMD_MAX,para_file);
1240 if (cmd_cur == NULL)
1241 {
1242 if (feof(para_file))
1243 {
1244 printf("\n? Error: EOF reported from parameter file !!\n");
1245 exit(1);
1246 }
1247 return NULL; /* error */
1248 }
1249 if ((null_ok) || (cmd_line[0] != '\0'))
1250 return cmd_cur=cmd_line;
1251 }
1252 return NULL;
1253
1254 }
1255
1256
1257 /* display test parameters */
1258
show_test_parms()1259 static void show_test_parms()
1260 {
1261 int priority;
1262
1263 printf("\nCurrent Test Parameters:\n\n");
1264
1265 printf(" Log file: %s\n",LogFileName);
1266 printf(" Data file: %s\n",DataFileName);
1267 printf(" Data file length: %lu\n",
1268 RVM_OFFSET_TO_LENGTH(DataLen));
1269 printf(" Number of operations/cycle: %d\n",max_op_cnt);
1270 printf(" Maximum number of transactions/operation: %d\n",max_trans);
1271 printf(" Maximum number of ranges/transaction: %d\n",max_ranges);
1272 printf(" Maximum modification range size: %d\n",max_mod_size);
1273 printf(" Maximum big modification range size: %d\n",max_moby_size);
1274 printf(" Maximum allocation block size: %d\n",
1275 max_block_size);
1276 printf(" Number of preallocated blocks: %d\n",
1277 num_pre_alloc);
1278 if (pre_alloc_trunc)
1279 printf(" Truncate after preallocation: true\n");
1280 else
1281 printf(" Truncate after preallocation: false\n");
1282
1283 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1284 printf(" %% ranges to check: %d\n",chk_range_frac);
1285 #endif /* VERSION_TEST */
1286 printf(" %% transactions to abort: %d\n",abort_frac);
1287 printf(" %% transactions to commit with flush: %d\n",flush_frac);
1288 printf(" %% transactions started with restore: %d\n",restore_frac);
1289
1290 printf("\n");
1291 if (max_cycles == -1)
1292 printf(" Number of test cycles: unlimited\n");
1293 else
1294 printf(" Number of test cycles: %d\n",
1295 max_cycles);
1296 printf(" Number of worker threads: %d\n",nthreads);
1297 #ifdef PRIO_PROCESS
1298 priority = getpriority(PRIO_PROCESS,0);
1299 #else
1300 priority = -1;
1301 #endif
1302 printf(" Execution priority: %d\n",priority);
1303 printf(" Random seed: %d\n",seed);
1304 printf(" Allocator check level: %d\n",chk_alloc);
1305 if (PlumberFileName[0] != '\0')
1306 printf(" Plumber file: %s\n",PlumberFileName);
1307
1308 /* print test options */
1309 printf(" Test options: ");
1310 if (moby_test)
1311 printf("big_range ");
1312 if (time_tests)
1313 printf("time_tests ");
1314 if (vm_test)
1315 printf("chk_vm ");
1316 printf("\n");
1317
1318 /* print optimizations */
1319 printf("\n RVM optimizations: ");
1320 if (optimizations == 0)
1321 printf("none");
1322 if ((optimizations & RVM_COALESCE_RANGES) != 0)
1323 printf("coalesce_ranges ");
1324 if ((optimizations & RVM_COALESCE_TRANS) != 0)
1325 printf("coalesce_trans ");
1326 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1327 if ((optimizations & RVM_INCR_TRUNCATION) != 0)
1328 printf("incr_truncation ");
1329 #endif /* VERSION_TEST */
1330 printf("\n");
1331 printf(" RVM truncation threshold: %d%%\n",
1332 trunc_frac);
1333 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1334 printf(" RVM epoch truncation threshold: %d%%\n",
1335 epoch_trunc_frac);
1336 printf(" RVM incremental truncation time slice: %d msec.\n",
1337 incr_trunc_time);
1338 #endif /* VERSION_TEST */
1339 printf(" RVM recovery buffer length: %lu\n",rec_buf_len);
1340 printf(" RVM flush buffer length: %lu\n",flush_buf_len);
1341 printf(" RVM max. read length: %lu\n",max_read_len);
1342 if (chk_sum_sw)
1343 printf(" RVM check sum flag: true\n");
1344 else
1345 printf(" RVM check sum flag: false\n");
1346 if (no_yield_sw)
1347 printf(" RVM no yield flag: true\n");
1348 else
1349 printf(" RVM no yield flag: false\n");
1350 if (vm_protect_sw)
1351 printf(" RVM vm protect flag: true\n");
1352 else
1353 printf(" RVM vm protect flag: false\n");
1354 if (do_private_map)
1355 printf(" RVM private map: true\n");
1356 else
1357 printf(" RVM private map: false\n");
1358 if (show_brk)
1359 printf(" Show break point: true\n");
1360 else
1361 printf(" Show break point: false\n");
1362 printf("\n");
1363 }
1364 /* get data file name and size */
set_data_file()1365 static void set_data_file()
1366 {
1367 int len;
1368 struct stat sbuf;
1369
1370 while (rvm_true)
1371 {
1372 read_prompt_line(" Enter data file name: ",rvm_false);
1373 skip_white(&cmd_cur);
1374 len = scan_str(DataFileName,MAXPATHLEN);
1375 if (len != 0) break;
1376 printf("\n? Data file name must be specified\n");
1377 }
1378
1379 /* get length of segment if partition specified */
1380 if (stat(DataFileName, &sbuf) < 0)
1381 {
1382 char *errstr = NULL;
1383 #ifdef HAVE_STRERROR
1384 errstr = strerror(errno);
1385 #endif
1386 printf("%s\n", errstr != NULL ? errstr : "Cannot stat data file");
1387 DataFileName[0] = '\000';
1388 return;
1389 }
1390 switch (sbuf.st_mode & S_IFMT)
1391 {
1392 #ifdef S_IFSOCK
1393 case S_IFSOCK:
1394 #endif
1395 case S_IFDIR:
1396 #ifdef S_IFLNK
1397 case S_IFLNK:
1398 #endif
1399 /* LINUX use the same block device for raw control */
1400 #ifndef __linux__
1401 case S_IFBLK:
1402 #endif
1403 printf("Illegal file type!\n");
1404 DataFileName[0] = '\0';
1405 return;
1406
1407 /* LINUX use the same block device for raw control */
1408 #ifdef __linux__
1409 case S_IFBLK:
1410 #endif
1411 case S_IFCHR:
1412 while (rvm_true)
1413 {
1414 read_prompt_line("Enter the length of device: ",rvm_false);
1415 len = scan_int(512,2000000000,0,"DataLen",
1416 "? Bad data device length\n");
1417 if (len != 0) break;
1418 }
1419 DataLen = RVM_MK_OFFSET(0,len);
1420 return;
1421
1422 default:
1423 DataLen = RVM_MK_OFFSET(0,sbuf.st_size); /* Normal files. */
1424 return;
1425 }
1426 }
1427 /* get log file name */
set_log_file()1428 static void set_log_file()
1429 {
1430 int len;
1431
1432 while (rvm_true)
1433 {
1434 read_prompt_line(" Enter log file name: ",rvm_false);
1435 skip_white(&cmd_cur);
1436 len = scan_str(LogFileName,MAXPATHLEN);
1437 if (len != 0) break;
1438 printf("\n? Log file name must be specified\n");
1439 }
1440 }
1441
1442 /* set execution priority */
set_priority()1443 static void set_priority()
1444 {
1445 int priority;
1446 int err;
1447
1448 priority = scan_int(0,20,0,"scheduling priority",
1449 "? Bad scheduling priority");
1450
1451 #ifdef PRIO_PROCESS
1452 err = setpriority(PRIO_PROCESS,0,priority);
1453 #else
1454 err = 0;
1455 #endif
1456 if (err != 0)
1457 printf("? Error setting process priority, err = %d\n",err);
1458
1459 }
1460 /* option flags */
1461 #define MAX_FLAGS 15 /* maximum number of flag codes */
1462
1463 static str_name_entry_t flag_vec[MAX_FLAGS] = /* flag codes vector */
1464 {
1465 {"all_optimizations",ALL_KEY}, /* enable all optimizations */
1466 {"none",NONE_KEY}, /* no optimizations */
1467 {"coalesce_ranges",RANGES_KEY}, /* enable range coalesce */
1468 {"rvm_coalesce_ranges",RANGES_KEY}, /* enable range coalesce */
1469 {"ranges",RANGES_KEY}, /* enable range coalesce */
1470 {"coalesce_trans",TRANS_KEY}, /* enable transaction coalesce */
1471 {"rvm_coalesce_trans",TRANS_KEY}, /* enable transaction coalesce */
1472 {"trans",TRANS_KEY}, /* enable transaction coalesce */
1473
1474 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1475 {"rvm_incr_truncation",INCR_KEY}, /* enable incr truncation */
1476 {"incr",INCR_KEY}, /* enable incr truncation */
1477 {"incr_truncation",INCR_KEY}, /* enable incr truncation */
1478
1479 #endif /* VERSION_TEST */
1480 {"",(key_id_t)NULL} /* end mark, do not delete */
1481 };
1482 /* set rvm_options flags */
set_flags()1483 static void set_flags()
1484 {
1485 char string[80]; /* flag code name string */
1486 int i;
1487
1488 optimizations = 0;
1489
1490 /* scan loop */
1491 while (rvm_true)
1492 {
1493 /* see if done */
1494 skip_white(&cmd_cur);
1495 if (scan_stop(*cmd_cur))
1496 return;
1497
1498 /* scan and lookup flag code */
1499 (void)scan_str(string,80);
1500 i = lookup_str_name(string,flag_vec,"option flag");
1501 if (i == (int)UNKNOWN) /* error */
1502 {
1503 *cmd_cur = '\0';
1504 return;
1505 }
1506
1507 /* process code */
1508 switch (flag_vec[i].key)
1509 {
1510 case ALL_KEY:
1511 optimizations |= RVM_ALL_OPTIMIZATIONS;
1512 continue;
1513 case NONE_KEY:
1514 optimizations = 0;
1515 continue;
1516 case RANGES_KEY:
1517 optimizations |= RVM_COALESCE_RANGES;
1518 continue;
1519 case TRANS_KEY:
1520 optimizations |= RVM_COALESCE_TRANS;
1521 continue;
1522 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1523 case INCR_KEY:
1524 optimizations |= RVM_INCR_TRUNCATION;
1525 continue;
1526 #endif /* VERSION_TEST */
1527 default:
1528 continue;
1529 }
1530 }
1531 }
1532 /* plumber support */
setup_plumber_file()1533 static void setup_plumber_file()
1534 {
1535 int len;
1536
1537 while (rvm_true)
1538 {
1539 read_prompt_line(" Enter plumber file name: ",rvm_false);
1540 skip_white(&cmd_cur);
1541 len = scan_str(PlumberFileName,MAXPATHLEN);
1542 if (len != 0) break;
1543 printf("\n? Plumber file name must be specified\n");
1544 }
1545
1546 /* try to open file if really can use plumber */
1547 #ifdef RVM_USELWP
1548 #ifdef HAS_PLUMBER
1549 PlumberFile = fopen(PlumberFileName,"w");
1550 if (PlumberFile == NULL)
1551 printf("? File %s could not be opened, errno = %d\n",
1552 PlumberFileName,errno);
1553 else
1554 fclose(PlumberFile);
1555 #endif
1556 #else /* RVM_USELWP */
1557 printf("W Plumber not available with Cthreads\n");
1558 #endif /* RVM_USELWP */
1559 }
1560
1561 #ifdef DEBUG_GDB
1562 /* call function (to be used from GDB) */
call_plumber()1563 void call_plumber()
1564 {
1565 #ifdef RVM_USELWP
1566 #ifdef HAS_PLUMBER
1567 PlumberFile = fopen(PlumberFileName,"w");
1568 if (PlumberFile == NULL)
1569 printf("? File %s could not be opened, errno = %d\n",
1570 PlumberFileName,errno);
1571 plumber(PlumberFile);
1572 fclose(PlumberFile);
1573 #endif
1574 #else /* RVM_USELWP */
1575 printf("? Plumber not available with Cthreads\n");
1576 #endif /* RVM_USELWP */
1577 }
1578 #endif /* DEBUG_GDB */
1579 /* print break point and limit */
show_break()1580 static void show_break()
1581 {
1582 rvm_length_t cur_brk;
1583 #ifdef RLIMIT_DATA
1584 struct rlimit rlp;
1585 #endif
1586
1587 /* get current break point */
1588 errno = 0;
1589 if ((cur_brk=(rvm_length_t)sbrk(0)) == -1)
1590 {
1591 printf("\n? Error getting current break point\n");
1592 printf(" errno = %d\n",errno);
1593 CODA_ASSERT(rvm_false);
1594 }
1595
1596 /* get system maximum */
1597 errno = 0;
1598 #ifdef RLIMIT_DATA
1599 if (getrlimit(RLIMIT_DATA,&rlp) < 0)
1600 {
1601 printf("\n? Error getting data segment limit\n");
1602 printf(" errno = %d\n",errno);
1603 CODA_ASSERT(rvm_false);
1604 }
1605
1606 /* print the limits */
1607 printf("\nCurrent break point: 0x%lx\n",
1608 RVM_ROUND_LENGTH_UP_TO_PAGE_SIZE(cur_brk+5*RVM_PAGE_SIZE));
1609 printf("Maximum data segment length: 0x%lx\n\n",rlp.rlim_max);
1610 #endif
1611 exit(0);
1612 }
1613 /* command dispatch */
1614 #define MAX_CMDS 50 /* maximum number of commands */
1615
1616 static str_name_entry_t cmd_vec[MAX_CMDS] = /* command codes vector */
1617 {
1618 {"abort_frac",ABORT_KEY}, /* set abort fraction */
1619 {"all_tests",ALL_KEY}, /* do all test options */
1620 {"block_size",BLOCK_SIZE_KEY}, /* set maximum allocation block size */
1621 {"mod_size",MOD_SIZE_KEY}, /* set maximum modification size */
1622 {"log_file",LOG_KEY}, /* set log file */
1623 {"data_file",DATA_KEY}, /* set data file */
1624 {"restore_frac",RESTORE_KEY}, /* set restore fraction */
1625 {"flush_buf",FLUSH_BUF_KEY}, /* set flush buffer length */
1626 {"flush_frac",FLUSH_KEY}, /* set flush fraction */
1627 {"check_alloc",CHK_ALLOC_KEY}, /* enable allocation checking */
1628 {"chk_sum",CHK_SUM_KEY}, /* set rvm_chk_sum */
1629 {"chk_vm",VM_KEY}, /* test vm againt segment */
1630 {"time_tests",TIME_KEY}, /* time the test cycles */
1631 {"ranges",RANGES_KEY}, /* max number of ranges/trans */
1632 {"trans",TRANS_KEY}, /* max number of trans/modify */
1633 {"cycles",CYCLES_KEY}, /* number of cycles */
1634 {"operations",OPS_KEY}, /* number of operations/cycle */
1635 {"ops",OPS_KEY}, /* number of operations/cycle */
1636 {"optimizations",OPT_KEY}, /* set optimizations */
1637 {"opts",OPT_KEY}, /* set optimizations */
1638 {"show_parmeters",PARMS_KEY}, /* show test parameters */
1639 {"parmeters",PARMS_KEY}, /* show test parameters */
1640 {"parms",PARMS_KEY}, /* show test parameters */
1641 {"priority",PRIORITY_KEY}, /* set tests priority */
1642 {"read_length",MAX_READ_KEY}, /* set maximum read length */
1643 {"rec_buf",REC_BUF_KEY}, /* set recovery buffer length */
1644 {"run",RUN_KEY}, /* start tests */
1645 {"seed",SEED_KEY}, /* random num gen seed */
1646 {"threads",THREADS_KEY}, /* number of threads */
1647 {"truncate_frac",TRUNC_KEY}, /* set truncation threshold */
1648 {"big_range",MOBY_KEY}, /* test moby ranges */
1649 {"max_big_range",MOBY_MAX_KEY}, /* set maximum moby range size */
1650 {"quit",QUIT_KEY}, /* quit test program */
1651 {"plumber",PLUMBER_KEY}, /* plumber file setup */
1652 {"pre_allocate",PRE_ALLOC_KEY}, /* number blocks preallocated */
1653 {"pre_allocate_trunc",PRE_ALLOC_TRUNC_KEY}, /* truncate
1654 after preallocation */
1655 {"show_break_point",BRK_KEY}, /* print break point */
1656 {"break_point",BRK_KEY}, /* print break point */
1657 /* version dependent commands */
1658 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1659 {"epoch_truncate_frac",EPOCH_TRUNC_KEY}, /* set epoch trunc threshold */
1660 {"incr_trunc_time",INCR_TRUNC_TIME_KEY}, /* set incr trunc
1661 time slice */
1662 {"chk_range_frac",CHK_RANGE_KEY}, /* set % of ranges to check */
1663 {"no_yield",NO_YIELD_KEY}, /* set no yield mode */
1664 {"vm_protect",VM_PROT_KEY}, /* setvm buffer protect mode */
1665 #endif /* VERSION_TEST */
1666 {"map_private",VM_MAP_PRIV}, /* option RVM_MAP_PRIVATE */
1667 {"",(key_id_t)NULL} /* end mark, do not delete */
1668 };
1669
main(argc,argv)1670 int main(argc, argv)
1671 int argc;
1672 char **argv;
1673 {
1674 rvm_options_t *options; /* options descriptor ptr */
1675 rvm_return_t ret;
1676 char *addr, string[80];
1677 int err, i;
1678
1679 if (argc == 2) { /* input parameters from file */
1680 para_file = fopen(argv[1], "r");
1681 if (! para_file) {
1682 fprintf(stderr, "open parameter files failed. Basher not started\n");
1683 exit(-1);
1684 }
1685 } else {
1686 para_file = stdin;
1687 }
1688
1689 /* initializations */
1690 cthread_init();
1691 cmd_line[0] = '\0';
1692 cmd_cur=cmd_line;
1693 chk_block = rvm_false;
1694 chk_sum_sw = rvm_false;
1695 no_yield_sw = rvm_false;
1696 vm_protect_sw = rvm_false;
1697 show_brk = rvm_false;
1698 do_private_map = rvm_false;
1699 blk_cnt = 0;
1700 mutex_init(&init_lock);
1701 condition_init(&init_cv);
1702 mutex_init(&alloc_list_lock);
1703 init_list_head(&alloc_list);
1704 mutex_init(&chk_lock);
1705 condition_init(&blk_code);
1706 condition_init(&chk_code);
1707 mutex_init(&thread_lock);
1708 condition_init(&thread_exit_code);
1709 LogFileName[0] = '\0';
1710 DataFileName[0] = '\0';
1711 PlumberFileName[0] = '\0';
1712 cycle = 1;
1713
1714 /* set defaults */
1715 max_cycles = CYCLES_DEFAULT;
1716 max_op_cnt = OP_CNT_DEFAULT;
1717 max_trans = TRANS_DEFAULT;
1718 max_ranges = RANGES_DEFAULT;
1719 max_block_size = BLOCK_SIZE_DEFAULT;
1720 max_mod_size = MOD_SIZE_DEFAULT;
1721 max_moby_size = MOBY_MOD_SIZE_DEFAULT;
1722 num_pre_alloc = PRE_ALLOC_DEFAULT;
1723 nthreads = THREADS_DEFAULT;
1724 flush_frac = FLUSH_DEFAULT;
1725 restore_frac = RESTORE_DEFAULT;
1726 abort_frac = ABORT_DEFAULT;
1727 optimizations = RVM_ALL_OPTIMIZATIONS;
1728 trunc_frac = TRUNCATE;
1729 seed = SEED_DEFAULT;
1730 chk_alloc = CHK_ALLOC_DEFAULT;
1731 max_read_len = MAX_READ_LEN;
1732 flush_buf_len = FLUSH_BUF_LEN;
1733 rec_buf_len = RECOVERY_BUF_LEN;
1734 pre_alloc_trunc = rvm_false;
1735 /* version specific defaults */
1736 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1737 epoch_trunc_frac = EPOCH_TRUNCATE;
1738 incr_trunc_time = INCR_TRUNC_TIME;
1739 chk_range_frac = CHK_RANGE_DEFAULT;
1740 #endif /* VERSION_TEST */
1741
1742 /* scan test commands */
1743 while (rvm_true)
1744 {
1745 read_prompt_line("*",rvm_false);
1746
1747 /* ignore comment lines */
1748 skip_white(&cmd_cur);
1749 if (*cmd_cur == '#')
1750 {
1751 *cmd_cur = '\0';
1752 continue;
1753 }
1754
1755 /* scan command name */
1756 (void)scan_str(string,80);
1757 i = lookup_str_name(string,cmd_vec,"command");
1758 if (i == (int)UNKNOWN) /* error */
1759 {
1760 *cmd_cur = '\0';
1761 continue;
1762 }
1763 /* dispatch commands */
1764 switch (cmd_vec[i].key)
1765 {
1766 case LOG_KEY: /* get name of log file */
1767 set_log_file();
1768 continue;
1769 case DATA_KEY: /* get name of data file */
1770 set_data_file();
1771 continue;
1772 case SEED_KEY: /* set random number seed */
1773 seed = scan_int(0,100000000,SEED_DEFAULT,"seed",
1774 "? Bad seed");
1775 srandom(seed);
1776 continue;
1777 case THREADS_KEY: /* get number of threads to run */
1778 nthreads = scan_int(1,1000,THREADS_DEFAULT,"thread",
1779 "? Bad thread count");
1780 continue;
1781 case OPS_KEY: /* set operation count */
1782 max_op_cnt = scan_int(1,10000,OP_CNT_DEFAULT,"operations",
1783 "? Bad operation count");
1784 continue;
1785 case CYCLES_KEY: /* set number of test cycles */
1786 max_cycles = scan_int(1,1000000000,CYCLES_DEFAULT,"cycles",
1787 "? Bad cycle count");
1788 continue;
1789 case VM_KEY: /* test vm against segment */
1790 vm_test = rvm_true;
1791 continue;
1792 case TIME_KEY: /* time stamp the test cycles */
1793 time_tests = rvm_true;
1794 continue;
1795 case MOBY_KEY: /* test very large ranges */
1796 moby_test = rvm_true;
1797 continue;
1798 case MOBY_MAX_KEY:
1799 max_moby_size = scan_int(0,10000000,SEED_DEFAULT,"big range size",
1800 "? Bad large modification size");
1801 continue;
1802 case ALL_KEY: /* do all test options */
1803 vm_test = rvm_true;
1804 time_tests = rvm_true;
1805 moby_test = rvm_true;
1806 continue;
1807 case ABORT_KEY: /* set abort fraction */
1808 abort_frac = scan_int(0,100,ABORT_DEFAULT,"abort fraction",
1809 "? Bad abort percentage");
1810 continue;
1811 case RESTORE_KEY: /* set restore fraction */
1812 restore_frac = scan_int(0,100,RESTORE_DEFAULT,
1813 "restore fraction",
1814 "? Bad restore percentage");
1815 continue;
1816 case FLUSH_KEY: /* set flush fraction */
1817 flush_frac = scan_int(0,100,FLUSH_DEFAULT,"flush fraction",
1818 "? Bad flush percentage");
1819 continue;
1820 case TRUNC_KEY: /* set truncation fraction */
1821 trunc_frac = scan_int(0,100,TRUNCATE,
1822 "truncation fraction",
1823 "? Bad truncation percentage");
1824 continue;
1825 case RANGES_KEY: /* set max number ranges/trans */
1826 max_ranges = scan_int(0,1000000,RANGES_DEFAULT,
1827 "max ranges",
1828 "? Bad maximum number of ranges");
1829 continue;
1830 case TRANS_KEY: /* set max number trans/modify */
1831 max_trans = scan_int(0,100000,TRANS_DEFAULT,"max trans",
1832 "? Bad maximum number of transactions");
1833 continue;
1834 case PARMS_KEY: /* print test parameters */
1835 show_test_parms();
1836 continue;
1837 case PRE_ALLOC_KEY: /* number of blocks to preallocate */
1838 num_pre_alloc = scan_int(1,100000,PRE_ALLOC_DEFAULT,
1839 "pre_alloc",
1840 "? Bad block preallocation count");
1841 continue;
1842 case PRE_ALLOC_TRUNC_KEY: /* truncate after preallocation */
1843 pre_alloc_trunc = rvm_true;
1844 continue;
1845 case RUN_KEY:
1846 printf("\n");
1847 break;
1848 case PRIORITY_KEY: /* set execution priority */
1849 set_priority();
1850 continue;
1851 case QUIT_KEY: /* exit program */
1852 exit(0);
1853 case OPT_KEY: /* set optimization flags */
1854 set_flags();
1855 continue;
1856 case NO_YIELD_KEY: /* set no_yield option */
1857 no_yield_sw = rvm_true;
1858 continue;
1859 case REC_BUF_KEY:
1860 rec_buf_len = scan_int(MIN_RECOVERY_BUF_LEN,1000*RVM_PAGE_SIZE,
1861 RECOVERY_BUF_LEN,"rec_buf",
1862 "? Bad recovery buffer length");
1863 continue;
1864 case FLUSH_BUF_KEY:
1865 flush_buf_len = scan_int(MIN_FLUSH_BUF_LEN,1000*RVM_PAGE_SIZE,
1866 FLUSH_BUF_LEN,"flush_buf",
1867 "? Bad flush buffer length");
1868 continue;
1869 case BLOCK_SIZE_KEY: /* set max allocation block size */
1870 max_block_size = scan_int(sizeof(rvm_length_t),100000,
1871 BLOCK_SIZE_DEFAULT,"block size",
1872 "? Bad maximum allocation size");
1873 continue;
1874 case MOD_SIZE_KEY: /* set max modification range size */
1875 max_mod_size = scan_int(1,10000000,MOD_SIZE_DEFAULT,
1876 "mod size",
1877 "? Bad maximum modification size");
1878 continue;
1879 case MAX_READ_KEY: /* set maximum read length */
1880 max_read_len = scan_int(RVM_PAGE_SIZE,1000*RVM_PAGE_SIZE,
1881 MAX_READ_LEN,"read_length",
1882 "? Bad maximum read length");
1883 continue;
1884 case BRK_KEY: /* show break point */
1885 show_brk = rvm_true;
1886 continue;
1887 /* version specific commands */
1888 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1889 case CHK_SUM_KEY: /* set rvm_chk_sum switch */
1890 chk_sum_sw = rvm_true;
1891 continue;
1892 case CHK_RANGE_KEY: /* set range check fraction */
1893 chk_range_frac = scan_int(0,100,CHK_RANGE_DEFAULT,
1894 "chk_range_frac",
1895 "? Bad chk_range fraction");
1896 continue;
1897 case VM_PROT_KEY: /* set vm protection option */
1898 vm_protect_sw = rvm_true;
1899 continue;
1900 case INCR_TRUNC_TIME_KEY: /* set incr trunc time slice */
1901 incr_trunc_time = scan_int(0,1000000,INCR_TRUNC_TIME,
1902 "incr trunc time slice",
1903 "? Bad time slice size");
1904 continue;
1905 case EPOCH_TRUNC_KEY: /* set epoch truncation fraction */
1906 epoch_trunc_frac = scan_int(trunc_frac,100,EPOCH_TRUNCATE,
1907 "epoch truncation fraction",
1908 "? Bad epoch truncation percentage");
1909 continue;
1910 #endif /* VERSION_TEST */
1911
1912 /* LWP specific commands */
1913 case CHK_ALLOC_KEY: /* get allocator check level */
1914 chk_alloc = scan_int(0,5,CHK_ALLOC_DEFAULT,
1915 "check_alloc",
1916 "? Bad allocation checker level");
1917 #ifndef RVM_USELWP
1918 printf("W Allocation checking not available with Cthreads\n");
1919 #endif /* RVM_USELWP */
1920 continue;
1921 case PLUMBER_KEY: /* open plumber file */
1922 setup_plumber_file();
1923 #ifndef RVM_USELWP
1924 printf("W Allocation checking not available with Cthreads\n");
1925 #endif /* RVM_USELWP */
1926 continue;
1927
1928 case VM_MAP_PRIV: /* Map private ... */
1929 do_private_map = rvm_true;
1930 continue;
1931
1932 default: CODA_ASSERT(rvm_false);
1933 }
1934 /* check that all necessary parameters have been speced */
1935 if (strlen(LogFileName) == 0)
1936 {
1937 printf("\n? Log file name must be specified\n");
1938 continue;
1939 }
1940 if ((strlen(DataFileName) == 0) && (show_brk == rvm_false))
1941 {
1942 printf("\n? Data file name must be specified\n");
1943 continue;
1944 }
1945 break;
1946 }
1947
1948 /* Check for good data. */
1949 if (RVM_OFFSET_TO_LENGTH(DataLen) < max_moby_size)
1950 {
1951 fprintf (stderr, "Basher: Maximum big modification range size too big.\n");
1952 exit(-1);
1953 }
1954
1955 /* set LWP options */
1956 #ifdef RVM_USELWP
1957 #ifdef HAS_PLUMBER
1958 SetMallocCheckLevel(chk_alloc);
1959 #endif
1960 #elif !defined(RVM_USEPT)
1961 if (nthreads > 1) {
1962 fprintf(stderr, "Nonthreaded basher, ignoring request for multiple threads\n");
1963 nthreads = 1;
1964 }
1965 #endif
1966
1967 /* esatblish RVM options */
1968 options = rvm_malloc_options();
1969 options->log_dev = LogFileName;
1970 options->flags &= ~RVM_ALL_OPTIMIZATIONS;
1971 options->flags |= optimizations;
1972 if (do_private_map)
1973 options->flags |= RVM_MAP_PRIVATE;
1974 options->truncate = trunc_frac;
1975 options->flush_buf_len = flush_buf_len;
1976 options->recovery_buf_len = rec_buf_len;
1977 options->max_read_len = max_read_len;
1978
1979 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1980 options->epoch_truncate = epoch_trunc_frac;
1981 options->incr_trunc_time = incr_trunc_time;
1982 if (chk_sum_sw)
1983 options->flags |= RVM_CHK_SUM;
1984 if (no_yield_sw)
1985 options->flags |= RVM_NO_YIELD;
1986 if (chk_range_frac != 0)
1987 options->flags |= RVM_CHK_RANGE;
1988 if (vm_protect_sw)
1989 options->flags |= RVM_VM_PROTECT;
1990 #endif /* VERSION_TEST */
1991 /* initialize RVM */
1992 ret = RVM_INIT(options);
1993 if (ret != RVM_SUCCESS)
1994 {
1995 printf("? rvm_initialize failed, code: %s\n",rvm_return(ret));
1996 exit(-1);
1997 }
1998 else
1999 printf("rvm_initialize succeeded.\n");
2000 /* print break point if requested */
2001 if (show_brk) show_break();
2002
2003 /* Load the data segment */
2004 rds_testsw = rvm_true;
2005 rds_load_heap(DataFileName, DataLen, &addr, &err);
2006 if (err == SUCCESS)
2007 printf("rds_start_heap successful\n");
2008 else
2009 {
2010 if (err > SUCCESS)
2011 printf("rds_start_heap = %s\n",
2012 /* rvm_return((rvm_return_t *)err)); XXX BOGUS JET */
2013 rvm_return((rvm_return_t)err));
2014 else
2015 printf("rds_start_heap = %d\n", err);
2016 CODA_ASSERT(rvm_false);
2017 }
2018
2019 /* preload alloc_list */
2020 printf("Preallocating test blocks\n");
2021 for (i=num_pre_alloc; i>=0; i--)
2022 do_malloc(0);
2023 if (pre_alloc_trunc)
2024 {
2025 ret = rvm_truncate();
2026 if (ret != RVM_SUCCESS)
2027 {
2028 printf("? rvm_truncate failed, code: %s\n",
2029 rvm_return(ret));
2030 CODA_ASSERT(rvm_false);
2031 }
2032 }
2033
2034 /* get current time */
2035 if (gettimeofday(&init_time,NULL) < 0)
2036 {
2037 perror("? Error getting time of day");
2038 CODA_ASSERT(rvm_false);
2039 }
2040 if (time_tests)
2041 printf("\nTests started: %s\n",ctime(&init_time.tv_sec));
2042
2043 /* start test run with input parameters */
2044 op_cnt = max_op_cnt;
2045 threads = (cthread_t *)malloc(sizeof(cthread_t) * nthreads);
2046 last = (int *)malloc(sizeof(int)*nthreads);
2047
2048 /* fork the testing threads and run the tests */
2049 if (nthreads == 1)
2050 {
2051 int arg = 0;
2052 last[0] = 0;
2053 worker(&arg);
2054 }
2055 else
2056 {
2057 for (i = 0; i < nthreads; i++)
2058 CRITICAL(init_lock,
2059 last[i] = 0;
2060 threads[i] = cthread_fork(worker, &i);
2061 condition_wait(&init_cv, &init_lock);
2062 );
2063
2064 /* wait for all threads to terminate */
2065 CRITICAL(thread_lock, {
2066 while (nthreads > 0)
2067 condition_wait(&thread_exit_code,&thread_lock);
2068 });
2069 cthread_yield(); /* let the last one out */
2070 }
2071 printf("\n All threads have exited\n");
2072
2073 /* cleanup */
2074 if ((ret=rvm_terminate()) != RVM_SUCCESS)
2075 {
2076 printf("? rvm_terminate failed, code: %s\n",rvm_return(ret));
2077 CODA_ASSERT(rvm_false);
2078 }
2079 return 0;
2080 }
2081
2082