Newsgroups: comp.parallel From: Mats Brorsson Subject: Re: Splash2 on Solaris (macros needed) Organization: Department of Computer Engineering, Lund University Date: 2 Mar 1998 18:40:14 GMT Message-ID: <6deuee$elf$1@encore.ece.cmu.edu> Sure, I have included them as attachments. [sorry, but the posting software i use removes the attachments and creates one file. i've added in marks where to cut. -mike] These are for solaris threads. I have also included an assembler file with simple lock routine (spin-lock) imeplementations. These may be used instead of the solaris mutex routines if you are running on a multiprocessor. You then will have to change the XXLOCK macros. Good luck, Mats -- Mats Brorsson Department of Information Technology, Lund University http://www.it.lth.se/~matsbror -----------------8< ----- CUT HERE ----- 8< ----------------- define(ENDLAB,5283) dnl /* delay(,,) */ define(DELAY,`{ $1[$3].count[$2]++; XXUNLOCK($1[$3].lock) XXLOCK($1[$3].queue[$2]); }') /* continue(,,) */ define(CONTINUE,`{ if ($1[$3].count[$2] == 0) { XXUNLOCK($1[$3].lock) } else { ($1[$3].count[$2])--; XXUNLOCK($1[$3].queue[$2]); } goto `L'ENDLAB; }') /* menter(,) */ define(MENTER, `{ XXLOCK(($1[$2].lock)) }' ) /* mexit(,) */ define(MEXIT,`{ XXUNLOCK($1[$2].lock) `L'ENDLAB: ; define(`ENDLAB',eval(ENDLAB+1)) }') /* decvar(,,,) */ define(DECVAR, `struct $1TYP { XXDECLOCK(lock) ifelse(eval($2 > 0),1, int count[$2];,) ifelse(eval($2 > 0),1, XXDECLOCK(queue[$2]),) $4 } $1[$3];' ) /* moninit(,,) */ define(MONINIT, `{ int q_num; int i; for (i = 0; i < ifelse($3,,1,$3); i++){ ifelse(eval($2 > 0),1, for (q_num=0; q_num < $2; q_num++) { $1[i].count[q_num] = 0; XXLOCKINIT($1[i].queue[q_num]); XXLOCK($1[i].queue[q_num]); },,) XXLOCKINIT($1[i].lock) } } ') /* create() */ define(CREATE,`{ thread_t thread_id; if (thr_create(NULL, 0, ($1), NULL, THR_BOUND | THR_SUSPENDED, &thread_id) != 0) { perror(""); fprintf(stderr, "thr_create() failed on process %s", "$1"); exit(-1); } mutex_lock(&ANL_global._sys_lock); ANL_global.nproc++; if (ANL_global.idmap[0] != thread_id) { ANL_global.idmap[ANL_global.nproc] = thread_id; } mutex_unlock(&ANL_global._sys_lock); thr_continue(thread_id); } ') /* clock() */ define(CLOCK,` { $1 = MD_clock(); }') /* main_end() */ define(MAIN_END,` exit(0); ') /* main_env(,,)) */ define(MAIN_ENV,` unsigned long min_shared_address = 0xffffffff; unsigned long max_shared_address = 0; XXENV($1,$2,$3) #ifndef TYPE_ANL_GLOBAL_DATA #define TYPE_ANL_GLOBAL_DATA typedef volatile struct ANL_global_data { long nproc; long reference_time; thread_t *idmap; mutex_t _sys_lock; } ANL_global_type; #endif ANL_global_type ANL_global; void ANL_print(ANL_fmt, ANL_a, ANL_b, ANL_c, ANL_d, ANL_e, ANL_f, ANL_g, ANL_h, ANL_i) { mutex_lock(&ANL_global._sys_lock); printf((char *)ANL_fmt, ANL_a, ANL_b, ANL_c, ANL_d, ANL_e, ANL_f, ANL_g, ANL_h, ANL_i); fflush(stdout); mutex_unlock(&ANL_global._sys_lock); } void bcopy(char *s1, char *s2, int length) { int i; for (i = 0; i < length; i++) { s2[i] = s1[i]; } } unsigned int MD_clock() { unsigned int i; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); i = (unsigned int) (tp.tv_sec - ANL_global.reference_time); i *= 1000; i += (unsigned int) (tp.tv_usec / 1000); return i; } ') /* extern_env */ define(EXTERN_ENV,` XXENV #ifndef TYPE_ANL_GLOBAL_DATA #define TYPE_ANL_GLOBAL_DATA typedef volatile struct ANL_global_data { long nproc; long reference_time; thread_t *idmap; mutex_t _sys_lock; } ANL_global_type; #endif extern ANL_global_type ANL_global; extern unsigned int MD_clock(); ') /* extern_INITENV */ define(EXTERN_INITENV,` XXINITENV ') /* main_INITENV(,,) */ define(MAIN_INITENV,`{ ifelse($2,,,`define(`SH_MEM',$2)') define(`MAX_PROCS',`ifelse($1,,32,$1)') XXINITENV }') /* initenv() */ define(INITENV,`MAIN_INITENV(,$1)') /* who_am_i() */ define(WHO_AM_I,` { int id; int i; thread_t thread_id; thread_id = thr_self(); for (i=0; i<=ANL_global.nproc; i++) { if (ANL_global.idmap[i] == thread_id) { id = i; break; } } *$1 = id; }') /* char *g_malloc() */ define(G_MALLOC, `sh_mem_malloc($1);' ) define(WAIT_FOR_END,` { int i; for (i = 0; i < ($1); i++) thr_join((thread_t)0, NULL, NULL); }') /* xxenv(,,)) */ define(XXENV,` #ifndef ___XXENV #define ___XXENV #include #include #include extern void ANL_print(ANL_fmt, ANL_a, ANL_b, ANL_c, ANL_d, ANL_e, ANL_f, ANL_g, ANL_h, ANL_i); #define PRINT ANL_print extern void bcopy(char *s1, char *s2, int length); extern unsigned long min_shared_address; extern unsigned long max_shared_address; static char *sh_mem_malloc(int size) { char *allocated_addr = malloc(size); if (((unsigned long) allocated_addr) < min_shared_address) min_shared_address = (unsigned long) allocated_addr; if (((unsigned long) allocated_addr+size) > max_shared_address) max_shared_address = (unsigned long) allocated_addr+size; return allocated_addr; } #ifndef PAGE_SIZE #define PAGE_SIZE 4096 #endif define(`MAX_PROCS',`ifelse($1,,32,$1)') define(`SH_MEM',`ifelse($2,,1500000,$2)') define(`SR_BUFFS',`ifelse($3,,600,$3)') #endif ') define(XXINITENV,` #ifndef ___XXINITENV #define ___XXINITENV mutex_init(&ANL_global._sys_lock, USYNC_THREAD, NULL); ANL_global.nproc = 0; ANL_global.idmap = malloc(sizeof(thread_t)*MAX_PROCS); ANL_global.idmap[0] = thr_self(); /* next 2 should stay together -> used in MD_clock */ ANL_global.reference_time = 0; ANL_global.reference_time = MD_clock(); #endif ') define(xxxXXDECLOCK,` volatile int ($1[16]); ') define(xxxXXLOCKINIT,` { cm_unlock(&($1[8])); /* ($1[8]) = 0;*/ } ') define(xxxXXLOCK,` { cm_lock(&($1[8])); } ') define(xxxXXUNLOCK,` { cm_unlock(&($1[8])); } ') define(XXDECLOCK,` mutex_t ($1); ') define(XXLOCKINIT,` { if (mutex_init(&($1),USYNC_THREAD,NULL)) { char str[256]; sprintf(str,"mutex_init failed for xxlockinit"); perror(str); exit(-1); } } ') define(XXLOCK,` { mutex_lock(&($1)); } ') define(XXUNLOCK,` { mutex_unlock(&($1)); } ') /* * macros to support tracing the synchronization behavior of programs * written with the Argonne c.st.monmacs and c.st.smacs. There is a * separate trace output file for each thread. */ define(tRACE_VERBOSE, `1') define(sT_DEBUG, `1') ifdef(`tRACING_REFS', `1') /* constant for data structure sizes in synchronization trace */ /* may be overridden in mAIN_INITENV */ define(DEFAULT_MAX_LOCKS, `20000') /* ids for types of locks */ define(ST_MUTEX, `1000') define(ST_BAR_LOCK, `2100') define(ST_BAR_QUEUE, `2200') define(ST_GS_LOCK, `3100') define(ST_GS_QUEUE, `3200') define(ST_MUTEX_ARRAY, `4000') /* trace vars associated with each lock */ define(ST_LOCKVARS,` ') define(ST_INFO_INIT, `{ ifdef(`TRACE_VERBOSE', `{ printf("ST_INFO: name: %s, addr: 0x%x, type: %u\n", "$1", $3, $2); fflush(stdout); }') }' ) /* st_log( ) logs event with time stamp into threads event log buffer. event = op addr time. can use s_TRACE_LOG_ENTRY and s_TRACE_LOG_EXIT now. */ define(ST_LOG, `{ ifdef(`TRACE_VERBOSE', `{ int pid; WHO_AM_I(&pid); printf("pid: %d, st_log($1, 0x%x) at %u\n", pid, $2, MD_clock()); fflush(stdout); }') }' ) define(START_GATHER_STAT,` ') define(FINISH_GATHER_STAT,` ') -----------------8< ----- CUT HERE ----- 8< ----------------- /* barrier(,) */ define(BARRIER,`{ int *lockAddr; ST_LOG(ST_BAR_ENTER, lockAddr) MENTER($1,0) if ($1[0].count[0] < ($2 - 1)){ DELAY($1,0,0) ST_LOG(ST_BAR_EXIT, lockAddr) } else { ST_LOG(ST_BAR_EXIT_LAST, lockAddr) } CONTINUE($1,0,0) MEXIT($1,0) }') /* bardec() */ define(BARDEC, `DECVAR($1,1,1)' ) /* barinit() */ define(BARINIT,`{ MONINIT($1,1,1) ST_INFO_INIT($1, ST_BAR_LOCK, &($1[0].lock) ) ST_INFO_INIT($1, ST_BAR_QUEUE, &($1[0].queue[0]) ) ST_LOG(ST_BAR_INIT, (int *)&($1[0].lock)) }') define(GSSPEC, `int sub;' ) /* gsdec() */ define(GSDEC, `DECVAR($1,1,1,GSSPEC)' ) /* gsinit() */ define(GSINIT,`{ MONINIT($1,1,1) $1[0].sub = 0; }') /* getsub($1,$2,$3,$4,$5) */ define(GETSUB,`{ MENTER($1,0) if ($1[0].sub <= $3) { $2 = $1[0].sub; $1[0].sub += ifelse($5,,1,$5); } else { $2 = -1; if ($1[0].count[0] < ($4 - 1)) { DELAY($1,0,0) } else $1[0].sub = 0; CONTINUE($1,0,0) } MEXIT($1,0) }') /* nlockdec() */ define(LOCKDEC, `XXDECLOCK($1)' ) /* nlockinit() */ define(LOCKINIT,`{ XXLOCKINIT($1); }') /* nlock() */ define(LOCK,`{ XXLOCK($1); }') /* nunlock() */ define(UNLOCK, `{ XXUNLOCK($1); }') define(ALOCKDEC, `DECVAR($1,0,$2)' ) define(ALOCKINIT,`{ MONINIT($1,0,$2) }') define(ALOCK,`{ MENTER($1,$2) '}) define(AULOCK,`{ MEXIT($1,$2) }') define(ASPEC, ` int pgdone; int pbdone; ') define(ADEC, `DECVAR($1,1,1,ASPEC)') define(AINIT, `{ MONINIT($1,1,1) $1[0].pgdone = $1[0].pbdone = 0; }') define(ASKFOR, `{ MENTER($1,0) if (($1[0].pgdone == 0) && ($1[0].pbdone != 0)) { if ($1[0].count[0] < ($3 - 1)) { DELAY($1,0,0) } } else { $2 = -2; while (($1[0].pgdone == 0) && ($1[0].pbdone == 0)) { $4 if ($2 == 0) { CONTINUE($1,0,0) } else { if ($1[0].count[0] == ($3 - 1)) { $1[0].pbdone = 1; } else { DELAY($1,0,0) } } } } if ($1[0].pgdone != 0) { $2 = -1; CONTINUE($1,0,0) } else { $2 = $1[0].pbdone; if ($1[0].count[0] == 0) { $5 $1[0].pbdone = 0; } CONTINUE($1,0,0) } MEXIT($1,0) }') define(PROBEND, `{ MENTER($1,0) $1[0].pbdone = $2; MEXIT($1,0) }') define(PROGEND, `{ MENTER($1,0) $1[0].pgdone = 1; MAIN_END CONTINUE($1,0,0) MEXIT($1,0) }') define(PAUSEDEC, ` struct $1TYP { int flag; int count; XXDECLOCK(lock) XXDECLOCK(queue) } $1; ') define(PAUSEINIT, `{ $1.flag = 0; $1.count = 0; XXLOCKINIT($1.lock) XXLOCKINIT($1.queue) XXLOCK($1.queue); }') define(CLEARPAUSE, `{ XXLOCK($1.lock) $1.flag = 0; if ($1.count == 0) { XXUNLOCK($1.lock) } else { $1.count--; XXUNLOCK($1.queue) } }') define(SETPAUSE, `{ XXLOCK($1.lock) $1.flag = 1; if ($1.count == 0) { XXUNLOCK($1.lock) } else { $1.count--; XXUNLOCK($1.queue) } }') define(WAITPAUSE, `{ XXLOCK($1.lock) if ($1.flag == 0) { $1.count++; XXUNLOCK($1.lock) XXLOCK($1.queue) } if ($1.count == 0) { XXUNLOCK($1.lock) } else { $1.count--; XXUNLOCK($1.queue) } }') -- Articles to parallel@ctc.com (Administrative: bigrigg@cs.cmu.edu) Archive: http://www.hensa.ac.uk/parallel/internet/usenet/comp.parallel