Bill Allombert on Thu, 29 Sep 2005 16:38:10 +0200 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Re: PARI and POSIX threads |
On Thu, Aug 18, 2005 at 05:04:09PM +0200, Bill Allombert wrote: > On Mon, Aug 15, 2005 at 11:24:58PM +0200, Philippe Elbaz-Vincent wrote: > > Hi, > > > > Is there a solution to this problem ? > > [is it technically doable to run several instances of PARI inside the same > > program ?] > > I am not sure the answer is known. > > What you can try is to mark avma, bot and top 'thread-local' using the > '__thread' keyword (assuming this is supported) and use > allocatemoremem() or switch_stack() to allocate a separate stack in each > threads. To copy objects between threads, clone them. > > We would be very interested to know if that can be made to work. Since the best way is to try, here a patch that seems to allow to run concurrent PARI threads assuming thread-local storage is supported: This: 1) add a THREAD macro that default to the empty string 2) mark avma,top and bot with THREAD (as a storage class). 3) add 2 public functions pari_thread_init() and pari_thread_close(). As such the patch does absolutly nothing until you compile PARI with -DTHREAD=__thread on a system that support thread-local storage. (You probably also want -D_REENTRANT). The simplest is to do: make clean make gp CC_FLAVOR=-DTHREAD=__thread make install Once you have installed the resulting library, you can try the attached example program thread.c. Here a commented version: #include <pari/pari.h> #include <pthread.h> void * mydet(void * arg) { GEN M=(GEN)arg; GEN F; pari_thread_init(8000000); // Initialize a local PARI stack for this // thread. F=gclone(det(M)); // compute the determinant using the local // stack // clone the result so we can free the // stack pari_thread_close(); // Free the PARI stack pthread_exit((void *)F); // End the thread and return F. return F; // spurious } void * myfactor(void * arg) //exactly the same as above. { GEN N=(GEN)arg; GEN F; pari_thread_init(4000000); F=gclone(factor(N)); pari_thread_close(); pthread_exit((void *)F); return F; } int main(void) { GEN M,N1,N2, F1,F2,D; pthread_t th1, th2, th3; pari_init(4000000,500000); //Initialise the main PARI stack //and global objects (gen_0, etc.) //We rely on the assumption that //the threads will not modify any //non-constant global objects. //(Pi,log2,etc.) N1=addis(gpowgs(gen_2,256),1); //do computation in the main PARI //stack N2=subis(gpowgs(gen_2,193),1); M=mathilbert(80); pthread_create(&th1,NULL,&myfactor,(void*)N1);//Start threads pthread_create(&th2,NULL,&myfactor,(void*)N2); pthread_create(&th3,NULL,&mydet,(void*)M); pthread_join(th1,(void*)&F1);//Wait until they terminate and get //theirs results pthread_join(th2,(void*)&F2); pthread_join(th3,(void*)&D); pariputsf("F1=%Z\nF2=%Z\nlog(D)=%Z\n",F1,F2,glog(D,3)); //display the results. return 0; } Example run on a quadri-opteron: $ gcc -I amd64/include -L amd64/lib -lpari -lgmp thread.c -O3 -othread -Wall -lpthread F1=[1238926361552897, 1; 93461639715357977769163558199606896584051237541638188580280321, 1] F2=[13821503, 1; 61654440233248340616559, 1; 14732265321145317331353282383, 1] log(D)=-8726.787756120586376 LD_LIBRARY_PATH=amd64/lib ./thread 12,18s user 0,16s system 264% cpu 4,668 total So we used 4,668s instead of 12,18s with a single thread, and more importantly we did not randomly crash and even the output is correct. Cheers, Bill
? amd64 ? patch ? thread ? thread.c Index: src/headers/paridecl.h =================================================================== RCS file: /home/cvs/pari/src/headers/paridecl.h,v retrieving revision 1.513 diff -u -r1.513 paridecl.h --- src/headers/paridecl.h 26 Sep 2005 15:00:15 -0000 1.513 +++ src/headers/paridecl.h 29 Sep 2005 13:42:42 -0000 @@ -1198,6 +1198,8 @@ void err_leave(void **v); GEN forcecopy(GEN x); void freeall(void); +void pari_thread_init(size_t parisize); +void pari_thread_close(void); GEN gcopy(GEN x); GEN gcopy_i(GEN x, long lx); GEN gerepile(pari_sp ltop, pari_sp lbot, GEN q); Index: src/headers/paristio.h =================================================================== RCS file: /home/cvs/pari/src/headers/paristio.h,v retrieving revision 1.30 diff -u -r1.30 paristio.h --- src/headers/paristio.h 6 Jul 2005 19:12:32 -0000 1.30 +++ src/headers/paristio.h 29 Sep 2005 13:42:42 -0000 @@ -74,7 +74,7 @@ #define TEXSTYLE_PAREN 2 #define TEXSTYLE_BREAK 4 -extern pari_sp avma,bot,top; +extern pari_sp THREAD avma,bot,top; #define DISABLE_MEMUSED (size_t)-1 extern size_t memused; extern byteptr diffptr; Index: src/headers/parisys.h =================================================================== RCS file: /home/cvs/pari/src/headers/parisys.h,v retrieving revision 1.10 diff -u -r1.10 parisys.h --- src/headers/parisys.h 1 Sep 2005 17:02:43 -0000 1.10 +++ src/headers/parisys.h 29 Sep 2005 13:42:42 -0000 @@ -57,6 +57,9 @@ # define INLINE_IS_STATIC # define INLINE static #endif +#ifndef THREAD +# define THREAD +#endif #if defined(_WIN32) || defined(__CYGWIN32__) /* ANSI C does not allow to longjmp() out of a signal handler, in particular, Index: src/language/init.c =================================================================== RCS file: /home/cvs/pari/src/language/init.c,v retrieving revision 1.272 diff -u -r1.272 init.c --- src/language/init.c 3 Sep 2005 16:36:12 -0000 1.272 +++ src/language/init.c 29 Sep 2005 13:42:42 -0000 @@ -48,7 +48,7 @@ ulong DEBUGFILES, DEBUGLEVEL, DEBUGMEM, compatible; ulong prec, precdl; ulong init_opts = INIT_JMPm | INIT_SIGm; -pari_sp bot = 0, top = 0, avma; +THREAD pari_sp bot = 0, top = 0, avma; size_t memused; gp_data *GP_DATA = NULL; @@ -638,6 +638,18 @@ { return gp_init_entrees(new_fun_set? pari_modules: pari_oldmodules, functions_hash, force); +} + +void +pari_thread_init(size_t parisize) +{ + init_stack(parisize); +} + +void +pari_thread_close(void) +{ + free((void *)bot); } /* initialize PARI data. You can call pari_addfunctions() first to add other
#include <pari/pari.h> #include <pthread.h> void * mydet(void * arg) { GEN M=(GEN)arg; GEN F; pari_thread_init(8000000); F=gclone(det(M)); pari_thread_close(); pthread_exit((void *)F); return F; } void * myfactor(void * arg) { GEN N=(GEN)arg; GEN F; pari_thread_init(4000000); F=gclone(factor(N)); pari_thread_close(); pthread_exit((void *)F); return F; } int main(void) { GEN M,N1,N2, F1,F2,D; pthread_t th1, th2, th3; pari_init(4000000,500000); N1=addis(gpowgs(gen_2,256),1); N2=subis(gpowgs(gen_2,193),1); M=mathilbert(80); pthread_create(&th1,NULL,&myfactor,(void*)N1); pthread_create(&th2,NULL,&myfactor,(void*)N2); pthread_create(&th3,NULL,&mydet,(void*)M); pthread_join(th1,(void*)&F1); pthread_join(th2,(void*)&F2); pthread_join(th3,(void*)&D); pariputsf("F1=%Z\nF2=%Z\nlog(D)=%Z\n",F1,F2,glog(D,3)); return 0; }