John Cremona on Tue, 31 May 2022 15:37:28 +0200 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Re: parallel C code -- help needed |
On Tue, 31 May 2022 at 14:14, John Cremona <john.cremona@gmail.com> wrote: > > On Tue, 31 May 2022 at 13:34, Bill Allombert > <Bill.Allombert@math.u-bordeaux.fr> wrote: > > > > On Tue, May 31, 2022 at 09:44:49AM +0100, John Cremona wrote: > > > I have a C++ program which uses libpari in just one function, and I > > > want to parallelise the program using omp. I have done this > > > successfully with other programs not using libpari, so I think I have > > > the omp basics right (while being a novice in parallel programming). > > > My libpari was configured with --mt=pthread. > > > > This is an important point, see below. > > > > > A simplified version of the function looks like this before > > > parallelising, and this works fine (the array *ai passed has length > > > 5): > > > > > > long pari_sturm(long *ai, int pos_only=0, int neg_only=0) > > > // Return the number of real roots (default), number of positive real > > > // roots (if pos_only==1) or number of negative real roots (if > > > // neg_only==1) > > > { > > > long res; > > > pari_sp av = avma; > > > GEN g0 = stoi(ai[0]); > > > GEN g1 = stoi(ai[1]); > > > GEN g2 = stoi(ai[2]); > > > GEN g3 = stoi(ai[3]); > > > GEN g4 = stoi(ai[4]); > > > GEN f = mkpoln(5,g0,g1,g2,g3,g4); > > > f = gdiv(f,ggcd(f,derivpol(f))); > > > > > > if (pos_only) > > > res = sturmpart(f,gen_0,NULL); // #roots >=0 > > > else > > > { > > > if (neg_only) > > > res = sturmpart(f,NULL,gen_0); // #roots <=0 > > > else > > > res = sturm(f); // #roots > > > } > > > gerepileupto(av, stoi(0)); > > > return res; > > > } > > > > > > Now I run in 4 threads, set by inserting > > > #pragma omp parallel num_threads(4) > > > in a higher level function; each thread will call pari_sturm() many > > > times. Since pari_sturm() uses at least one global variable (avma) I > > > enclose the code in an omp critical block so it looks like > > > > > > long pari_sturm(long *ai, int pos_only=0, int neg_only=0) > > > { > > > long res; > > > #pragma omp critical(pari) > > > { > > > pari_sp av = avma; > > > GEN g0 = stoi(ai[0]); > > > <same as above> > > > gerepileupto(av, stoi(0)); > > > } > > > return res; > > > } > > > > > > but when I run it I get a segfault on the line "GEN g0 = stoi(ai[0]);" > > > > > Can this be made to work? > > > > Using a critical section to marshall access to the PARI stack could work > > but only with the non-TLS version of PARI! > > > > When using the TLS version of PARI (--enable-tls or --mt=pthread) each > > thread automatically get its own private (TLS) avma and stack, which > > need to be initialized when the thread starts. > > > > This is done by using pari_thread_alloc in the main thread and > > pari_thread_start/pari_thread_close in each secondary threads. > > > > The recommended way to use openmp with PARI is explained in the file > > examples/openmp.c and the appendix D. > > Thanks a lot Bill, I will try your suggestions. Fantastic, it now works perfectly. I just added 2 lines outside the parallel block to define the pari_thread object pth, and call pari_thread_alloc on each. Inside the parallel block I call pari_thread_start() at the beginning and pari_thread_close() at the end. And I removed the #pragma omp critical in the function which does the main pari work. Thanks, Bill! John > > John > > > > > Cheers, > > Bill.