FORM  4.3
parallel.c
Go to the documentation of this file.
1 
11 /* #[ License : */
12 /*
13  * Copyright (C) 1984-2022 J.A.M. Vermaseren
14  * When using this file you are requested to refer to the publication
15  * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
16  * This is considered a matter of courtesy as the development was paid
17  * for by FOM the Dutch physics granting agency and we would like to
18  * be able to track its scientific use to convince FOM of its value
19  * for the community.
20  *
21  * This file is part of FORM.
22  *
23  * FORM is free software: you can redistribute it and/or modify it under the
24  * terms of the GNU General Public License as published by the Free Software
25  * Foundation, either version 3 of the License, or (at your option) any later
26  * version.
27  *
28  * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
29  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
31  * details.
32  *
33  * You should have received a copy of the GNU General Public License along
34  * with FORM. If not, see <http://www.gnu.org/licenses/>.
35  */
36 /* #] License : */
37 /*
38  #[ includes :
39 */
40 #include "form3.h"
41 #include "vector.h"
42 
43 /*
44 #define PF_DEBUG_BCAST_LONG
45 #define PF_DEBUG_BCAST_BUF
46 #define PF_DEBUG_BCAST_PREDOLLAR
47 #define PF_DEBUG_BCAST_RHSEXPR
48 #define PF_DEBUG_BCAST_DOLLAR
49 #define PF_DEBUG_BCAST_PREVAR
50 #define PF_DEBUG_BCAST_CBUF
51 #define PF_DEBUG_BCAST_EXPRFLAGS
52 #define PF_DEBUG_REDUCE_DOLLAR
53 */
54 
55 /* mpi.c */
56 LONG PF_RealTime(int);
57 int PF_LibInit(int*, char***);
58 int PF_LibTerminate(int);
59 int PF_Probe(int*);
60 int PF_RecvWbuf(WORD*,LONG*,int*);
61 int PF_IRecvRbuf(PF_BUFFER*,int,int);
62 int PF_WaitRbuf(PF_BUFFER *,int,LONG *);
63 int PF_RawSend(int dest, void *buf, LONG l, int tag);
64 LONG PF_RawRecv(int *src,void *buf,LONG thesize,int *tag);
65 int PF_RawProbe(int *src, int *tag, int *bytesize);
66 
67 /* Private functions */
68 
69 static int PF_WaitAllSlaves(void);
70 
71 static void PF_PackRedefinedPreVars(void);
72 static void PF_UnpackRedefinedPreVars(void);
73 
74 static int PF_Wait4MasterIP(int tag);
75 static int PF_DoOneExpr(void);
76 static int PF_ReadMaster(void);/*reads directly to its scratch!*/
77 static int PF_Slave2MasterIP(int src);/*both master and slave*/
78 static int PF_Master2SlaveIP(int dest, EXPRESSIONS e);
79 static int PF_WalkThrough(WORD *t, LONG l, LONG chunk, LONG *count);
80 static int PF_SendChunkIP(FILEHANDLE *curfile, POSITION *position, int to, LONG thesize);
81 static int PF_RecvChunkIP(FILEHANDLE *curfile, int from, LONG thesize);
82 
83 static void PF_ReceiveErrorMessage(int src, int tag);
84 static void PF_CatchErrorMessages(int *src, int *tag);
85 static void PF_CatchErrorMessagesForAll(void);
86 static int PF_ProbeWithCatchingErrorMessages(int *src);
87 
88 /* Variables */
89 
90 PARALLELVARS PF;
91 #ifdef MPI2
92  WORD *PF_shared_buff;
93 #endif
94 
95 static LONG PF_goutterms; /* (master) Total out terms at PF_EndSort(), used in PF_Statistics(). */
96 static POSITION PF_exprsize; /* (master) The size of the expression at PF_EndSort(), used in PF_Processor(). */
97 
98 /*
99  This will work well only under Linux, see
100  #ifdef PF_WITH_SCHED_YIELD
101  below in PF_WaitAllSlaves().
102 */
103 #ifdef PF_WITH_SCHED_YIELD
104  #include <sched.h>
105 #endif
106 
107 #ifdef PF_WITHLOG
108  #define PRINTFBUF(TEXT,TERM,SIZE) { UBYTE lbuf[24]; if(PF.log){ WORD iii;\
109  NumToStr(lbuf,AC.CModule); \
110  fprintf(stderr,"[%d|%s] %s : ",PF.me,lbuf,(char*)TEXT);\
111  if(TERM){ fprintf(stderr,"[%d] ",(int)(*TERM));\
112  if((SIZE)<500 && (SIZE)>0) for(iii=1;iii<(SIZE);iii++)\
113  fprintf(stderr,"%d ",TERM[iii]); }\
114  fprintf(stderr,"\n");\
115  fflush(stderr); } }
116 #else
117  #define PRINTFBUF(TEXT,TERM,SIZE) {}
118 #endif
119 
124 #define SWAP(x, y) \
125  do { \
126  char swap_tmp__[sizeof(x) == sizeof(y) ? (int)sizeof(x) : -1]; \
127  memcpy(swap_tmp__, &y, sizeof(x)); \
128  memcpy(&y, &x, sizeof(x)); \
129  memcpy(&x, swap_tmp__, sizeof(x)); \
130  } while (0)
131 
135 #define PACK_LONG(p, n) \
136  do { \
137  *(p)++ = (UWORD)((ULONG)(n) & (ULONG)WORDMASK); \
138  *(p)++ = (UWORD)(((ULONG)(n) >> BITSINWORD) & (ULONG)WORDMASK); \
139  } while (0)
140 
144 #define UNPACK_LONG(p, n) \
145  do { \
146  (n) = (LONG)((((ULONG)(p)[1] & (ULONG)WORDMASK) << BITSINWORD) | ((ULONG)(p)[0] & (ULONG)WORDMASK)); \
147  (p) += 2; \
148  } while (0)
149 
153 #define CHECK(condition) _CHECK(condition, __FILE__, __LINE__)
154 #define _CHECK(condition, file, line) __CHECK(condition, file, line)
155 #define __CHECK(condition, file, line) \
156  do { \
157  if ( !(condition) ) { \
158  Error0("Fatal error at " file ":" #line); \
159  Terminate(-1); \
160  } \
161  } while (0)
162 
163 /*
164  * For debugging.
165  */
166 #define DBGOUT(lv1, lv2, a) do { if ( lv1 >= lv2 ) { printf a; fflush(stdout); } } while (0)
167 
168 /* (AN.ninterms of master) == max(AN.ninterms of slaves) == sum(PF_linterms of slaves) at EndSort(). */
169 #define DBGOUT_NINTERMS(lv, a)
170 /* #define DBGOUT_NINTERMS(lv, a) DBGOUT(1, lv, a) */
171 
172 /*
173  #] includes :
174  #[ statistics :
175  #[ variables : (should be part of a struct?)
176 */
177 static LONG PF_linterms; /* local interms on this proces: PF_Proces */
178 #define PF_STATS_SIZE 5
179 static LONG **PF_stats = NULL;/* space for collecting statistics of all procs */
180 static LONG PF_laststat; /* last realtime when statistics were printed */
181 static LONG PF_statsinterval;/* timeinterval for printing statistics */
182 /*
183  #] variables :
184  #[ PF_Statistics :
185 */
186 
195 static int PF_Statistics(LONG **stats, int proc)
196 {
197  GETIDENTITY
198  LONG real, cpu;
199  WORD rpart, cpart;
200  int i, j;
201 
202  if ( AT.SS == AM.S0 && PF.me == MASTER ) {
203  real = PF_RealTime(PF_TIME); rpart = (WORD)(real%100); real /= 100;
204 
205  if ( PF_stats == NULL ) {
206  PF_stats = (LONG**)Malloc1(PF.numtasks*sizeof(LONG*),"PF_stats 1");
207  for ( i = 0; i < PF.numtasks; i++ ) {
208  PF_stats[i] = (LONG*)Malloc1(PF_STATS_SIZE*sizeof(LONG),"PF_stats 2");
209  for ( j = 0; j < PF_STATS_SIZE; j++ ) PF_stats[i][j] = 0;
210  }
211  }
212  if ( proc > 0 ) for ( i = 0; i < PF_STATS_SIZE; i++ ) PF_stats[proc][i] = stats[0][i];
213 
214  if ( real >= PF_laststat + PF_statsinterval || proc == 0 ) {
215  LONG sum[PF_STATS_SIZE];
216 
217  for ( i = 0; i < PF_STATS_SIZE; i++ ) sum[i] = 0;
218  sum[0] = cpu = TimeCPU(1);
219  cpart = (WORD)(cpu%1000);
220  cpu /= 1000;
221  cpart /= 10;
222  if ( AC.OldParallelStats ) MesPrint("");
223  if ( proc > 0 && AC.StatsFlag && AC.OldParallelStats ) {
224  MesPrint("proc CPU in gen left byte");
225  MesPrint("%3d : %7l.%2i %10l",0,cpu,cpart,AN.ninterms);
226  }
227  else if ( AC.StatsFlag && AC.OldParallelStats ) {
228  MesPrint("proc CPU in gen out byte");
229  MesPrint("%3d : %7l.%2i %10l %10l %10l",0,cpu,cpart,AN.ninterms,0,PF_goutterms);
230  }
231 
232  for ( i = 1; i < PF.numtasks; i++ ) {
233  cpart = (WORD)(PF_stats[i][0]%1000);
234  cpu = PF_stats[i][0] / 1000;
235  cpart /= 10;
236  if ( AC.StatsFlag && AC.OldParallelStats )
237  MesPrint("%3d : %7l.%2i %10l %10l %10l",i,cpu,cpart,
238  PF_stats[i][2],PF_stats[i][3],PF_stats[i][4]);
239  for ( j = 0; j < PF_STATS_SIZE; j++ ) sum[j] += PF_stats[i][j];
240  }
241  cpart = (WORD)(sum[0]%1000);
242  cpu = sum[0] / 1000;
243  cpart /= 10;
244  if ( AC.StatsFlag && AC.OldParallelStats ) {
245  MesPrint("Sum = %7l.%2i %10l %10l %10l",cpu,cpart,sum[2],sum[3],sum[4]);
246  MesPrint("Real = %7l.%2i %20s (%l) %16s",
247  real,rpart,AC.Commercial,AC.CModule,EXPRNAME(AR.CurExpr));
248  MesPrint("");
249  }
250  PF_laststat = real;
251  }
252  }
253  return(0);
254 }
255 /*
256  #] PF_Statistics :
257  #] statistics :
258  #[ sort.c :
259  #[ sort variables :
260 */
261 
265 typedef struct NoDe {
266  struct NoDe *left;
267  struct NoDe *rght;
268  int lloser;
269  int rloser;
270  int lsrc;
271  int rsrc;
272 } NODE;
273 
274 /*
275  should/could be put in one struct
276 */
277 static NODE *PF_root; /* root of tree of losers */
278 static WORD PF_loser; /* this is the last loser */
279 static WORD **PF_term; /* these point to the active terms */
280 static WORD **PF_newcpos; /* new coeffs of merged terms */
281 static WORD *PF_newclen; /* length of new coefficients */
282 
283 /*
284  preliminary: could also write somewhere else?
285 */
286 
287 static WORD *PF_WorkSpace; /* used in PF_EndSort() */
288 static UWORD *PF_ScratchSpace; /* used in PF_GetLoser() */
289 
290 /*
291  #] sort variables :
292  #[ PF_AllocBuf :
293 */
294 
311 static PF_BUFFER *PF_AllocBuf(int nbufs, LONG bsize, WORD free)
312 {
313  PF_BUFFER *buf;
314  UBYTE *p, *stop;
315  LONG allocsize;
316  int i;
317 
318  allocsize =
319  (LONG)(sizeof(PF_BUFFER) + 4*nbufs*sizeof(WORD*) + (nbufs-free)*bsize);
320 
321  allocsize +=
322  (LONG)( nbufs * ( 2 * sizeof(MPI_Status)
323  + sizeof(MPI_Request)
324  + sizeof(MPI_Datatype)
325  ) );
326  allocsize += (LONG)( nbufs * 3 * sizeof(int) );
327 
328  if ( ( buf = (PF_BUFFER*)Malloc1(allocsize,"PF_AllocBuf") ) == NULL ) return(NULL);
329 
330  p = ((UBYTE *)buf) + sizeof(PF_BUFFER);
331  stop = ((UBYTE *)buf) + allocsize;
332 
333  buf->numbufs = nbufs;
334  buf->active = 0;
335 
336  buf->buff = (WORD**)p; p += buf->numbufs*sizeof(WORD*);
337  buf->fill = (WORD**)p; p += buf->numbufs*sizeof(WORD*);
338  buf->full = (WORD**)p; p += buf->numbufs*sizeof(WORD*);
339  buf->stop = (WORD**)p; p += buf->numbufs*sizeof(WORD*);
340  buf->status = (MPI_Status *)p; p += buf->numbufs*sizeof(MPI_Status);
341  buf->retstat = (MPI_Status *)p; p += buf->numbufs*sizeof(MPI_Status);
342  buf->request = (MPI_Request *)p; p += buf->numbufs*sizeof(MPI_Request);
343  buf->type = (MPI_Datatype *)p; p += buf->numbufs*sizeof(MPI_Datatype);
344  buf->index = (int *)p; p += buf->numbufs*sizeof(int);
345 
346  for ( i = 0; i < buf->numbufs; i++ ) buf->request[i] = MPI_REQUEST_NULL;
347  buf->tag = (int *)p; p += buf->numbufs*sizeof(int);
348  buf->from = (int *)p; p += buf->numbufs*sizeof(int);
349 /*
350  and finally the real bufferspace
351 */
352  for ( i = free; i < buf->numbufs; i++ ) {
353  buf->buff[i] = (WORD*)p; p += bsize;
354  buf->stop[i] = (WORD*)p;
355  buf->fill[i] = buf->full[i] = buf->buff[i];
356  }
357  if ( p != stop ) {
358  MesPrint("Error in PF_AllocBuf p = %x stop = %x\n",p,stop);
359  return(NULL);
360  }
361  return(buf);
362 }
363 
364 /*
365  #] PF_AllocBuf :
366  #[ PF_InitTree :
367 */
368 
380 static int PF_InitTree(void)
381 {
382  GETIDENTITY
383  PF_BUFFER **rbuf = PF.rbufs;
384  UBYTE *p, *stop;
385  int numrbufs,numtasks = PF.numtasks;
386  int i, j, src, numnodes;
387  int numslaves = numtasks - 1;
388  LONG size;
389 /*
390  #[ the buffers : for the new coefficients and the terms
391  we need one for each slave
392 */
393  if ( PF_term == NULL ) {
394  size = 2*numtasks*sizeof(WORD*) + sizeof(WORD)*
395  ( numtasks*(1 + AM.MaxTal) + (AM.MaxTer/sizeof(WORD)+1) + 2*(AM.MaxTal+2));
396 
397  PF_term = (WORD **)Malloc1(size,"PF_term");
398  stop = ((UBYTE*)PF_term) + size;
399  p = ((UBYTE*)PF_term) + numtasks*sizeof(WORD*);
400 
401  PF_newcpos = (WORD **)p; p += sizeof(WORD*) * numtasks;
402  PF_newclen = (WORD *)p; p += sizeof(WORD) * numtasks;
403  for ( i = 0; i < numtasks; i++ ) {
404  PF_newcpos[i] = (WORD *)p; p += sizeof(WORD)*AM.MaxTal;
405  PF_newclen[i] = 0;
406  }
407  PF_WorkSpace = (WORD *)p; p += AM.MaxTer+sizeof(WORD);
408  PF_ScratchSpace = (UWORD*)p; p += 2*(AM.MaxTal+2)*sizeof(UWORD);
409 
410  if ( p != stop ) { MesPrint("error in PF_InitTree"); return(-1); }
411  }
412 /*
413  #] the buffers :
414  #[ the receive buffers :
415 */
416  numrbufs = PF.numrbufs;
417 /*
418  this is the size we have in the combined sortbufs for one slave
419 */
420  size = (AT.SS->sTop2 - AT.SS->lBuffer - 1)/(PF.numtasks - 1);
421 
422  if ( rbuf == NULL ) {
423  if ( ( rbuf = (PF_BUFFER**)Malloc1(numtasks*sizeof(PF_BUFFER*), "Master: rbufs") ) == NULL ) return(-1);
424  if ( (rbuf[0] = PF_AllocBuf(1,0,1) ) == NULL ) return(-1);
425  for ( i = 1; i < numtasks; i++ ) {
426  if (!(rbuf[i] = PF_AllocBuf(numrbufs,sizeof(WORD)*size,1))) return(-1);
427  }
428  }
429  rbuf[0]->buff[0] = AT.SS->lBuffer;
430  rbuf[0]->full[0] = rbuf[0]->fill[0] = rbuf[0]->buff[0];
431  rbuf[0]->stop[0] = rbuf[1]->buff[0] = rbuf[0]->buff[0] + 1;
432  rbuf[1]->full[0] = rbuf[1]->fill[0] = rbuf[1]->buff[0];
433  for ( i = 2; i < numtasks; i++ ) {
434  rbuf[i-1]->stop[0] = rbuf[i]->buff[0] = rbuf[i-1]->buff[0] + size;
435  rbuf[i]->full[0] = rbuf[i]->fill[0] = rbuf[i]->buff[0];
436  }
437  rbuf[numtasks-1]->stop[0] = rbuf[numtasks-1]->buff[0] + size;
438 
439  for ( i = 1; i < numtasks; i++ ) {
440  for ( j = 0; j < rbuf[i]->numbufs; j++ ) {
441  rbuf[i]->full[j] = rbuf[i]->fill[j] = rbuf[i]->buff[j] + AM.MaxTer/sizeof(WORD) + 2;
442  }
443  PF_term[i] = rbuf[i]->fill[rbuf[i]->active];
444  *PF_term[i] = 0;
445  PF_IRecvRbuf(rbuf[i],rbuf[i]->active,i);
446  }
447  rbuf[0]->active = 0;
448  PF_term[0] = rbuf[0]->buff[0];
449  PF_term[0][0] = 0; /* PF_term[0] is used for a zero term. */
450  PF.rbufs = rbuf;
451 /*
452  #] the receive buffers :
453  #[ the actual tree :
454 
455  calculate number of nodes in mergetree and allocate space for them
456 */
457  if ( numslaves < 3 ) numnodes = 1;
458  else {
459  numnodes = 2;
460  while ( numnodes < numslaves ) numnodes *= 2;
461  numnodes -= 1;
462  }
463 
464  if ( PF_root == NULL )
465  if ( ( PF_root = (NODE*)Malloc1(sizeof(NODE)*numnodes,"nodes in mergtree") ) == NULL )
466  return(-1);
467 /*
468  then initialize all the nodes
469 */
470  src = 1;
471  for ( i = 0; i < numnodes; i++ ) {
472  if ( 2*(i+1) <= numnodes ) {
473  PF_root[i].left = &(PF_root[2*(i+1)-1]);
474  PF_root[i].lsrc = 0;
475  }
476  else {
477  PF_root[i].left = 0;
478  if ( src < numtasks ) PF_root[i].lsrc = src++;
479  else PF_root[i].lsrc = 0;
480  }
481  PF_root[i].lloser = 0;
482  }
483  for ( i = 0; i < numnodes; i++ ) {
484  if ( 2*(i+1)+1 <= numnodes ) {
485  PF_root[i].rght = &(PF_root[2*(i+1)]);
486  PF_root[i].rsrc = 0;
487  }
488  else {
489  PF_root[i].rght = 0;
490  if (src<numtasks) PF_root[i].rsrc = src++;
491  else PF_root[i].rsrc = 0;
492  }
493  PF_root[i].rloser = 0;
494  }
495 /*
496  #] the actual tree :
497 */
498  return(numnodes);
499 }
500 
501 /*
502  #] PF_InitTree :
503  #[ PF_PutIn :
504 */
505 
524 static WORD *PF_PutIn(int src)
525 {
526  int tag;
527  WORD im, r;
528  WORD *m1, *m2;
529  LONG size;
530  PF_BUFFER *rbuf = PF.rbufs[src];
531  int a = rbuf->active;
532  int next = a+1 >= rbuf->numbufs ? 0 : a+1 ;
533  WORD *lastterm = PF_term[src];
534  WORD *term = rbuf->fill[a];
535 
536  if ( src <= 0 ) return(PF_term[0]);
537 
538  if ( rbuf->full[a] == rbuf->buff[a] + AM.MaxTer/sizeof(WORD) + 2 ) {
539 /*
540  very first term from this src
541 */
542  tag = PF_WaitRbuf(rbuf,a,&size);
543  rbuf->full[a] += size;
544  if ( tag == PF_ENDBUFFER_MSGTAG ) *rbuf->full[a]++ = 0;
545  else if ( rbuf->numbufs > 1 ) {
546 /*
547  post a nonblock. recv. for the next buffer
548 */
549  rbuf->full[next] = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 2;
550  size = (LONG)(rbuf->stop[next] - rbuf->full[next]);
551  PF_IRecvRbuf(rbuf,next,src);
552  }
553  }
554  if ( *term == 0 && term != rbuf->full[a] ) return(PF_term[0]);
555 /*
556  exception is for rare cases when the terms fitted exactly into buffer
557 */
558  if ( term + *term > rbuf->full[a] || term + 1 >= rbuf->full[a] ) {
559 newterms:
560  m1 = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 1;
561  if ( *term < 0 || term == rbuf->full[a] ) {
562 /*
563  copy term and lastterm to the new buffer, so that they end at m1
564 */
565  m2 = rbuf->full[a] - 1;
566  while ( m2 >= term ) *m1-- = *m2--;
567  rbuf->fill[next] = term = m1 + 1;
568  m2 = lastterm + *lastterm - 1;
569  while ( m2 >= lastterm ) *m1-- = *m2--;
570  lastterm = m1 + 1;
571  }
572  else {
573 /*
574  copy beginning of term to the next buffer so that it ends at m1
575 */
576  m2 = rbuf->full[a] - 1;
577  while ( m2 >= term ) *m1-- = *m2--;
578  rbuf->fill[next] = term = m1 + 1;
579  }
580  if ( rbuf->numbufs == 1 ) {
581  rbuf->full[a] = rbuf->buff[a] + AM.MaxTer/sizeof(WORD) + 2;
582  size = (LONG)(rbuf->stop[a] - rbuf->full[a]);
583  PF_IRecvRbuf(rbuf,a,src);
584  }
585 /*
586  wait for new terms in the next buffer
587 */
588  rbuf->full[next] = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 2;
589  tag = PF_WaitRbuf(rbuf,next,&size);
590  rbuf->full[next] += size;
591  if ( tag == PF_ENDBUFFER_MSGTAG ) {
592  *rbuf->full[next]++ = 0;
593  }
594  else if ( rbuf->numbufs > 1 ) {
595 /*
596  post a nonblock. recv. for active buffer, it is not needed anymore
597 */
598  rbuf->full[a] = rbuf->buff[a] + AM.MaxTer/sizeof(WORD) + 2;
599  size = (LONG)(rbuf->stop[a] - rbuf->full[a]);
600  PF_IRecvRbuf(rbuf,a,src);
601  }
602 /*
603  now savely make next buffer active
604 */
605  a = rbuf->active = next;
606  }
607 
608  if ( *term < 0 ) {
609 /*
610  We need to decompress the term
611 */
612  im = *term;
613  r = term[1] - im + 1;
614  m1 = term + 2;
615  m2 = lastterm - im + 1;
616  while ( ++im <= 0 ) *--m1 = *--m2;
617  *--m1 = r;
618  rbuf->fill[a] = term = m1;
619  if ( term + *term > rbuf->full[a] ) goto newterms;
620  }
621  rbuf->fill[a] += *term;
622  return(term);
623 }
624 
625 /*
626  #] PF_PutIn :
627  #[ PF_GetLoser :
628 */
629 
648 static int PF_GetLoser(NODE *n)
649 {
650  GETIDENTITY
651  WORD comp;
652 
653  if ( PF_loser == 0 ) {
654 /*
655  this is for the right initialization of the tree only
656 */
657  if ( n->left ) n->lloser = PF_GetLoser(n->left);
658  else {
659  n->lloser = n->lsrc;
660  if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0) n->lloser = 0;
661  }
662  PF_loser = 0;
663  if ( n->rght ) n->rloser = PF_GetLoser(n->rght);
664  else{
665  n->rloser = n->rsrc;
666  if ( *(PF_term[n->rsrc] = PF_PutIn(n->rsrc)) == 0 ) n->rloser = 0;
667  }
668  PF_loser = 0;
669  }
670  else if ( PF_loser == n->lloser ) {
671  if ( n->left ) n->lloser = PF_GetLoser(n->left);
672  else {
673  n->lloser = n->lsrc;
674  if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0 ) n->lloser = 0;
675  }
676  }
677  else if ( PF_loser == n->rloser ) {
678 newright:
679  if ( n->rght ) n->rloser = PF_GetLoser(n->rght);
680  else {
681  n->rloser = n->rsrc;
682  if ( *(PF_term[n->rsrc] = PF_PutIn(n->rsrc)) == 0 ) n->rloser = 0;
683  }
684  }
685  if ( n->lloser > 0 && n->rloser > 0 ) {
686  comp = CompareTerms(PF_term[n->lloser],PF_term[n->rloser],(WORD)0);
687  if ( comp > 0 ) return(n->lloser);
688  else if (comp < 0 ) return(n->rloser);
689  else {
690 /*
691  #[ terms are equal :
692 */
693  WORD *lcpos, *rcpos;
694  UWORD *newcpos;
695  WORD lclen, rclen, newclen, newnlen;
696  SORTING *S = AT.SS;
697 
698  if ( S->PolyWise ) {
699 /*
700  #[ Here we work with PolyFun :
701 */
702  WORD *tt1, *w;
703  WORD r1,r2;
704  WORD *ml = PF_term[n->lloser];
705  WORD *mr = PF_term[n->rloser];
706 
707  if ( ( r1 = (int)*PF_term[n->lloser] ) <= 0 ) r1 = 20;
708  if ( ( r2 = (int)*PF_term[n->rloser] ) <= 0 ) r2 = 20;
709  tt1 = ml;
710  ml += S->PolyWise;
711  mr += S->PolyWise;
712  if ( S->PolyFlag == 2 ) {
713  w = poly_ratfun_add(BHEAD ml,mr);
714  if ( *tt1 + w[1] - ml[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
715  MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
716  Terminate(-1);
717  }
718  AT.WorkPointer = w;
719  }
720  else {
721  w = AT.WorkPointer;
722  if ( w + ml[1] + mr[1] > AT.WorkTop ) {
723  MesPrint("A WorkSpace of %10l is too small",AM.WorkSize);
724  Terminate(-1);
725  }
726  AddArgs(BHEAD ml,mr,w);
727  }
728  r1 = w[1];
729  if ( r1 <= FUNHEAD || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) ) {
730  goto cancelled;
731  }
732  if ( r1 == ml[1] ) {
733  NCOPY(ml,w,r1);
734  }
735  else if ( r1 < ml[1] ) {
736  r2 = ml[1] - r1;
737  mr = w + r1;
738  ml += ml[1];
739  while ( --r1 >= 0 ) *--ml = *--mr;
740  mr = ml - r2;
741  r1 = S->PolyWise;
742  while ( --r1 >= 0 ) *--ml = *--mr;
743  *ml -= r2;
744  PF_term[n->lloser] = ml;
745  }
746  else {
747  r2 = r1 - ml[1];
748  if ( r2 > 2*AM.MaxTal )
749  MesPrint("warning: new term in polyfun is large");
750  mr = tt1 - r2;
751  r1 = S->PolyWise;
752  ml = tt1;
753  *ml += r2;
754  PF_term[n->lloser] = mr;
755  NCOPY(mr,ml,r1);
756  r1 = w[1];
757  NCOPY(mr,w,r1);
758  }
759  PF_newclen[n->rloser] = 0;
760  PF_loser = n->rloser;
761  goto newright;
762 /*
763  #] Here we work with PolyFun :
764 */
765  }
766  if ( ( lclen = PF_newclen[n->lloser] ) != 0 ) lcpos = PF_newcpos[n->lloser];
767  else {
768  lcpos = PF_term[n->lloser];
769  lclen = *(lcpos += *lcpos - 1);
770  lcpos -= ABS(lclen) - 1;
771  }
772  if ( ( rclen = PF_newclen[n->rloser] ) != 0 ) rcpos = PF_newcpos[n->rloser];
773  else {
774  rcpos = PF_term[n->rloser];
775  rclen = *(rcpos += *rcpos - 1);
776  rcpos -= ABS(rclen) -1;
777  }
778  lclen = ( (lclen > 0) ? (lclen-1) : (lclen+1) ) >> 1;
779  rclen = ( (rclen > 0) ? (rclen-1) : (rclen+1) ) >> 1;
780  newcpos = PF_ScratchSpace;
781  if ( AddRat(BHEAD (UWORD *)lcpos,lclen,(UWORD *)rcpos,rclen,newcpos,&newnlen) ) return(-1);
782  if ( AN.ncmod != 0 ) {
783  if ( ( AC.modmode & POSNEG ) != 0 ) {
784  NormalModulus(newcpos,&newnlen);
785  }
786  if ( BigLong(newcpos,newnlen,(UWORD *)AC.cmod,ABS(AN.ncmod)) >=0 ) {
787  WORD ii;
788  SubPLon(newcpos,newnlen,(UWORD *)AC.cmod,ABS(AN.ncmod),newcpos,&newnlen);
789  newcpos[newnlen] = 1;
790  for ( ii = 1; ii < newnlen; ii++ ) newcpos[newnlen+ii] = 0;
791  }
792  }
793  if ( newnlen == 0 ) {
794 /*
795  terms cancel, get loser of left subtree and then of right subtree
796 */
797 cancelled:
798  PF_loser = n->lloser;
799  PF_newclen[n->lloser] = 0;
800  if ( n->left ) n->lloser = PF_GetLoser(n->left);
801  else {
802  n->lloser = n->lsrc;
803  if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0 ) n->lloser = 0;
804  }
805  PF_loser = n->rloser;
806  PF_newclen[n->rloser] = 0;
807  goto newright;
808  }
809  else {
810 /*
811  keep the left term and get the loser of right subtree
812 */
813  newnlen *= 2;
814  newclen = ( newnlen > 0 ) ? ( newnlen + 1 ) : ( newnlen - 1 );
815  if ( newnlen < 0 ) newnlen = -newnlen;
816  PF_newclen[n->lloser] = newclen;
817  lcpos = PF_newcpos[n->lloser];
818  if ( newclen < 0 ) newclen = -newclen;
819  while ( newclen-- ) *lcpos++ = *newcpos++;
820  PF_loser = n->rloser;
821  PF_newclen[n->rloser] = 0;
822  goto newright;
823  }
824 /*
825  #] terms are equal :
826 */
827  }
828  }
829  if (n->lloser > 0) return(n->lloser);
830  if (n->rloser > 0) return(n->rloser);
831  return(0);
832 }
833 /*
834  #] PF_GetLoser :
835  #[ PF_EndSort :
836 */
837 
864 int PF_EndSort(void)
865 {
866  GETIDENTITY
867  FILEHANDLE *fout = AR.outfile;
868  PF_BUFFER *sbuf=PF.sbuf;
869  SORTING *S = AT.SS;
870  WORD *outterm,*pp;
871  LONG size, noutterms;
872  POSITION position, oldposition;
873  WORD i,cc;
874  int oldgzipCompress;
875 
876  if ( AT.SS != AT.S0 || !PF.parallel ) return 0;
877 
878  if ( PF.me != MASTER ) {
879 /*
880  #[ the slaves have to initialize their sendbuffer :
881 
882  this is a slave and it's PObuffer should be the minimum of the
883  sortiosize on the master and the POsize of our file.
884  First save the original PObuffer and POstop of the outfile
885 */
886  size = (S->sTop2 - S->lBuffer - 1)/(PF.numtasks - 1);
887  size -= (AM.MaxTer/sizeof(WORD) + 2);
888  if ( fout->POsize < (LONG)(size*sizeof(WORD)) ) size = fout->POsize/sizeof(WORD);
889  if ( sbuf == NULL ) {
890  if ( (sbuf = PF_AllocBuf(PF.numsbufs, size*sizeof(WORD), 1)) == NULL ) return -1;
891  sbuf->active = 0;
892  PF.sbuf = sbuf;
893  }
894  sbuf->buff[0] = fout->PObuffer;
895  sbuf->stop[0] = fout->PObuffer+size;
896  if ( sbuf->stop[0] > fout->POstop ) return -1;
897  for ( i = 0; i < PF.numsbufs; i++ )
898  sbuf->fill[i] = sbuf->full[i] = sbuf->buff[i];
899 
900  fout->PObuffer = sbuf->buff[sbuf->active];
901  fout->POstop = sbuf->stop[sbuf->active];
902  fout->POsize = size*sizeof(WORD);
903  fout->POfill = fout->POfull = fout->PObuffer;
904 /*
905  #] the slaves have to initialize their sendbuffer :
906 */
907  return(0);
908  }
909 /*
910  this waits for all slaves to be ready to send terms back
911 */
912  PF_WaitAllSlaves(); /* Note, the returned value should be 0 on success. */
913 /*
914  Now collect the terms of all slaves and merge them.
915  PF_GetLoser gives the position of the smallest term, which is the real
916  work. The smallest term needs to be copied to the outbuf: use PutOut.
917 */
918  PF_InitTree();
919  if ( AR.PolyFun == 0 ) { S->PolyFlag = 0; }
920  else if ( AR.PolyFunType == 1 ) { S->PolyFlag = 1; }
921  else if ( AR.PolyFunType == 2 ) {
922  if ( AR.PolyFunExp == 2
923  || AR.PolyFunExp == 3 ) S->PolyFlag = 1;
924  else S->PolyFlag = 2;
925  }
926  *AR.CompressPointer = 0;
927  SeekScratch(fout, &position);
928  oldposition = position;
929  oldgzipCompress = AR.gzipCompress;
930  AR.gzipCompress = 0;
931 
932  noutterms = 0;
933 
934  while ( PF_loser >= 0 ) {
935  if ( (PF_loser = PF_GetLoser(PF_root)) == 0 ) break;
936  outterm = PF_term[PF_loser];
937  noutterms++;
938 
939  if ( PF_newclen[PF_loser] != 0 ) {
940 /*
941  #[ this is only when new coeff was too long :
942 */
943  outterm = PF_WorkSpace;
944  pp = PF_term[PF_loser];
945  cc = *pp;
946  while ( cc-- ) *outterm++ = *pp++;
947  outterm = (outterm[-1] > 0) ? outterm-outterm[-1] : outterm+outterm[-1];
948  if ( PF_newclen[PF_loser] > 0 ) cc = (WORD)PF_newclen[PF_loser] - 1;
949  else cc = -(WORD)PF_newclen[PF_loser] - 1;
950  pp = PF_newcpos[PF_loser];
951  while ( cc-- ) *outterm++ = *pp++;
952  *outterm++ = PF_newclen[PF_loser];
953  *PF_WorkSpace = outterm - PF_WorkSpace;
954  outterm = PF_WorkSpace;
955  *PF_newcpos[PF_loser] = 0;
956  PF_newclen[PF_loser] = 0;
957 /*
958  #] this is only when new coeff was too long :
959 */
960  }
961  PRINTFBUF("PF_EndSort to PutOut: ",outterm,*outterm);
962  PutOut(BHEAD outterm,&position,fout,1);
963  }
964  if ( FlushOut(&position,fout,0) ) {
965  AR.gzipCompress = oldgzipCompress;
966  return(-1);
967  }
968  S->TermsLeft = PF_goutterms = noutterms;
969  DIFPOS(PF_exprsize, position, oldposition);
970  AR.gzipCompress = oldgzipCompress;
971  return(1);
972 }
973 
974 /*
975  #] PF_EndSort :
976  #] sort.c :
977  #[ proces.c :
978  #[ variables :
979 */
980 
981 static WORD *PF_CurrentBracket;
982 
983 /*
984  #] variables :
985  #[ PF_GetTerm :
986 */
987 
1006 static WORD PF_GetTerm(WORD *term)
1007 {
1008  GETIDENTITY
1009  FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
1010  WORD i;
1011  WORD *next, *np, *last, *lp = 0, *nextstop, *tp=term;
1012 
1013  /* Only on the slaves. */
1014 
1015  AN.deferskipped = 0;
1016  if ( fi->POfill >= fi->POfull || fi->POfull == fi->PObuffer ) {
1017 ReceiveNew:
1018  {
1019 /*
1020  #[ receive new terms from master :
1021 */
1022  int src = MASTER, tag;
1023  int follow = 0;
1024  LONG size,cpu,space = 0;
1025 
1026  if ( PF.log ) {
1027  fprintf(stderr,"[%d] Starting to send to Master\n",PF.me);
1028  fflush(stderr);
1029  }
1030 
1031  cpu = TimeCPU(1);
1032  PF_PreparePack();
1033  PF_Pack(&cpu ,1,PF_LONG);
1034  PF_Pack(&space ,1,PF_LONG);
1035  PF_Pack(&PF_linterms ,1,PF_LONG);
1036  PF_Pack(&(AM.S0->GenTerms) ,1,PF_LONG);
1037  PF_Pack(&(AM.S0->TermsLeft),1,PF_LONG);
1038  PF_Pack(&follow ,1,PF_INT );
1039 
1040  if ( PF.log ) {
1041  fprintf(stderr,"[%d] Now sending with tag = %d\n",PF.me,PF_READY_MSGTAG);
1042  fflush(stderr);
1043  }
1044 
1045  PF_Send(MASTER, PF_READY_MSGTAG);
1046 
1047  if ( PF.log ) {
1048  fprintf(stderr,"[%d] returning from send\n",PF.me);
1049  fflush(stderr);
1050  }
1051 
1052  size = fi->POstop - fi->PObuffer - 1;
1053 #ifdef AbsolutelyExtra
1054  PF_Receive(MASTER,PF_ANY_MSGTAG,&src,&tag);
1055 #ifdef MPI2
1056  if ( tag == PF_TERM_MSGTAG ) {
1057  PF_Unpack(&size, 1, PF_LONG);
1058  if ( PF_Put_target(src) == 0 ) {
1059  printf("PF_Put_target error ...\n");
1060  }
1061  }
1062  else {
1063  PF_RecvWbuf(fi->PObuffer,&size,&src);
1064  }
1065 #else
1066  PF_RecvWbuf(fi->PObuffer,&size,&src);
1067 #endif
1068 #endif
1069  tag=PF_RecvWbuf(fi->PObuffer,&size,&src);
1070 
1071  fi->POfill = fi->PObuffer;
1072  /* Get AN.ninterms which sits in the first 2 WORDs. */
1073  {
1074  LONG ninterms;
1075  UNPACK_LONG(fi->POfill, ninterms);
1076  if ( fi->POfill < fi->POfull ) {
1077  DBGOUT_NINTERMS(2, ("PF.me=%d AN.ninterms=%d PF_linterms=%d ninterms=%d GET\n", (int)PF.me, (int)AN.ninterms, (int)PF_linterms, (int)ninterms));
1078  AN.ninterms = ninterms - 1;
1079  } else {
1080  DBGOUT_NINTERMS(2, ("PF.me=%d AN.ninterms=%d PF_linterms=%d ninterms=%d GETEND\n", (int)PF.me, (int)AN.ninterms, (int)PF_linterms, (int)ninterms));
1081  }
1082  }
1083  fi->POfull = fi->PObuffer + size;
1084  if ( tag == PF_ENDSORT_MSGTAG ) *fi->POfull++ = 0;
1085 /*
1086  #] receive new terms from master :
1087 */
1088  }
1089  if ( PF_CurrentBracket ) *PF_CurrentBracket = 0;
1090  }
1091  if ( *fi->POfill == 0 ) {
1092  fi->POfill = fi->POfull = fi->PObuffer;
1093  *term = 0;
1094  goto RegRet;
1095  }
1096  if ( AR.DeferFlag ) {
1097  if ( !PF_CurrentBracket ) {
1098 /*
1099  #[ alloc space :
1100 */
1101  PF_CurrentBracket =
1102  (WORD*)Malloc1(AM.MaxTer,"PF_CurrentBracket");
1103  *PF_CurrentBracket = 0;
1104 /*
1105  #] alloc space :
1106 */
1107  }
1108  while ( *PF_CurrentBracket ) { /* "for each term in the buffer" */
1109 /*
1110  #[ test : bracket & skip if it's equal to the last in PF_CurrentBracket
1111 */
1112  next = fi->POfill;
1113  nextstop = next + *next; nextstop -= ABS(nextstop[-1]);
1114  next++;
1115  last = PF_CurrentBracket+1;
1116  while ( next < nextstop ) {
1117 /*
1118  scan the next term and PF_CurrentBracket
1119 */
1120  if ( *last == HAAKJE && *next == HAAKJE ) {
1121 /*
1122  the part outside brackets is equal => skip this term
1123 */
1124  PRINTFBUF("PF_GetTerm skips",fi->POfill,*fi->POfill);
1125  break;
1126  }
1127 /*
1128  check if the current subterms are equal
1129 */
1130  np = next; next += next[1];
1131  lp = last; last += last[1];
1132  while ( np < next ) if ( *lp++ != *np++ ) goto strip;
1133  }
1134 /*
1135  go on to next term
1136 */
1137  fi->POfill += *fi->POfill;
1138  AN.deferskipped++;
1139 /*
1140  the usual checks
1141 */
1142  if ( fi->POfill >= fi->POfull || fi->POfull == fi->PObuffer )
1143  goto ReceiveNew;
1144  if ( *fi->POfill == 0 ) {
1145  fi->POfill = fi->POfull = fi->PObuffer;
1146  *term = 0;
1147  goto RegRet;
1148  }
1149 /*
1150  #] test :
1151 */
1152  }
1153 /*
1154  #[ copy :
1155 
1156  this term to CurrentBracket and the part outside of bracket
1157  to WorkSpace at term
1158 */
1159 strip:
1160  next = fi->POfill;
1161  nextstop = next + *next; nextstop -= ABS(nextstop[-1]);
1162  next++;
1163  tp++;
1164  lp = PF_CurrentBracket + 1;
1165  while ( next < nextstop ) {
1166  if ( *next == HAAKJE ) {
1167  fi->POfill += *fi->POfill;
1168  while ( next < fi->POfill ) *lp++ = *next++;
1169  *PF_CurrentBracket = lp - PF_CurrentBracket;
1170  *lp = 0;
1171  *tp++ = 1;
1172  *tp++ = 1;
1173  *tp++ = 3;
1174  *term = WORDDIF(tp,term);
1175  PRINTFBUF("PF_GetTerm new brack",PF_CurrentBracket,*PF_CurrentBracket);
1176  PRINTFBUF("PF_GetTerm POfill",fi->POfill,*fi->POfill);
1177  goto RegRet;
1178  }
1179  np = next; next += next[1];
1180  while ( np < next ) *tp++ = *lp++ = *np++;
1181  }
1182  tp = term;
1183 /*
1184  #] copy :
1185 */
1186  }
1187 
1188  i = *fi->POfill;
1189  while ( i-- ) *tp++ = *fi->POfill++;
1190 RegRet:
1191  PRINTFBUF("PF_GetTerm returns",term,*term);
1192  return(*term);
1193 }
1194 
1195 /*
1196  #] PF_GetTerm :
1197  #[ PF_Deferred :
1198 */
1199 
1208 WORD PF_Deferred(WORD *term, WORD level)
1209 {
1210  GETIDENTITY
1211  WORD *bra, *bstop;
1212  WORD *tstart;
1213  FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
1214  WORD *next = fi->POfill;
1215  WORD *termout = AT.WorkPointer;
1216  WORD *oldwork = AT.WorkPointer;
1217 
1218  AT.WorkPointer = (WORD *)((UBYTE *)(AT.WorkPointer) + AM.MaxTer);
1219  AR.DeferFlag = 0;
1220 
1221  PRINTFBUF("PF_Deferred (Term) ",term,*term);
1222  PRINTFBUF("PF_Deferred (Bracket)",PF_CurrentBracket,*PF_CurrentBracket);
1223 
1224  bra = bstop = PF_CurrentBracket;
1225  if ( *bstop > 0 ) {
1226  bstop += *bstop;
1227  bstop -= ABS(bstop[-1]);
1228  }
1229  bra++;
1230  while ( *bra != HAAKJE && bra < bstop ) bra += bra[1];
1231  if ( bra >= bstop ) { /* No deferred action! */
1232  AT.WorkPointer = term + *term;
1233  if ( Generator(BHEAD term,level) ) goto DefCall;
1234  AR.DeferFlag = 1;
1235  AT.WorkPointer = oldwork;
1236  return(0);
1237  }
1238  bstop = bra;
1239  tstart = bra + bra[1];
1240  bra = PF_CurrentBracket;
1241  tstart--;
1242  *tstart = bra + *bra - tstart;
1243  bra++;
1244 /*
1245  Status of affairs:
1246  First bracket content starts at tstart.
1247  Next term starts at next.
1248  The outside of the bracket runs from bra = PF_CurrentBracket to bstop.
1249 */
1250  for(;;) {
1251  if ( InsertTerm(BHEAD term,0,AM.rbufnum,tstart,termout,0) < 0 ) {
1252  goto DefCall;
1253  }
1254 /*
1255  call Generator with new composed term
1256 */
1257  AT.WorkPointer = termout + *termout;
1258  if ( Generator(BHEAD termout,level) ) goto DefCall;
1259  AT.WorkPointer = termout;
1260  tstart = next + 1;
1261  if ( tstart >= fi->POfull ) goto ThatsIt;
1262  next += *next;
1263 /*
1264  compare with current bracket
1265 */
1266  while ( bra <= bstop ) {
1267  if ( *bra != *tstart ) goto ThatsIt;
1268  bra++; tstart++;
1269  }
1270 /*
1271  now bra and tstart should both be a HAAKJE
1272 */
1273  bra--; tstart--;
1274  if ( *bra != HAAKJE || *tstart != HAAKJE ) goto ThatsIt;
1275  tstart += tstart[1];
1276  tstart--;
1277  *tstart = next - tstart;
1278  bra = PF_CurrentBracket + 1;
1279  }
1280 
1281 ThatsIt:
1282 /*
1283  AT.WorkPointer = oldwork;
1284 */
1285  AR.DeferFlag = 1;
1286  return(0);
1287 DefCall:
1288  MesCall("PF_Deferred");
1289  SETERROR(-1);
1290 }
1291 
1292 /*
1293  #] PF_Deferred :
1294  #[ PF_Wait4Slave :
1295 */
1296 
1297 static LONG **PF_W4Sstats = 0;
1298 
1305 static int PF_Wait4Slave(int src)
1306 {
1307  int j, tag, next;
1308 
1309  tag = PF_ANY_MSGTAG;
1310  PF_CatchErrorMessages(&src, &tag);
1311  PF_Receive(src, tag, &next, &tag);
1312 
1313  if ( tag != PF_READY_MSGTAG ) {
1314  MesPrint("[%d] PF_Wait4Slave: received MSGTAG %d",(WORD)PF.me,(WORD)tag);
1315  return(-1);
1316  }
1317  if ( PF_W4Sstats == 0 ) {
1318  PF_W4Sstats = (LONG**)Malloc1(sizeof(LONG*),"");
1319  PF_W4Sstats[0] = (LONG*)Malloc1(PF_STATS_SIZE*sizeof(LONG),"");
1320  }
1321  PF_Unpack(PF_W4Sstats[0],PF_STATS_SIZE,PF_LONG);
1322  PF_Statistics(PF_W4Sstats,next);
1323 
1324  PF_Unpack(&j,1,PF_INT);
1325 
1326  if ( j ) {
1327 /*
1328  actions depending on rest of information in last message
1329 */
1330  }
1331  return(next);
1332 }
1333 
1334 /*
1335  #] PF_Wait4Slave :
1336  #[ PF_Wait4SlaveIP :
1337 */
1338 /*
1339  array of expression numbers for PF_InParallel processor.
1340  Each time the master sends expression "i" to the slave
1341  "next" it sets partodoexr[next]=i:
1342 */
1343 static WORD *partodoexr=NULL;
1344 
1352 static int PF_Wait4SlaveIP(int *src)
1353 {
1354  int j,tag,next;
1355 
1356  tag = PF_ANY_MSGTAG;
1357  PF_CatchErrorMessages(src, &tag);
1358  PF_Receive(*src, tag, &next, &tag);
1359  *src=tag;
1360  if ( PF_W4Sstats == 0 ) {
1361  PF_W4Sstats = (LONG**)Malloc1(sizeof(LONG*),"");
1362  PF_W4Sstats[0] = (LONG*)Malloc1(PF_STATS_SIZE*sizeof(LONG),"");
1363  }
1364 
1365  PF_Unpack(PF_W4Sstats[0],PF_STATS_SIZE,PF_LONG);
1366  if ( tag == PF_DATA_MSGTAG )
1367  AR.CurExpr = partodoexr[next];
1368  PF_Statistics(PF_W4Sstats,next);
1369 
1370  PF_Unpack(&j,1,PF_INT);
1371 
1372  if ( j ) {
1373  /* actions depending on rest of information in last message */
1374  }
1375 
1376  return(next);
1377 }
1378 /*
1379  #] PF_Wait4SlaveIP :
1380  #[ PF_WaitAllSlaves :
1381 */
1382 
1391 static int PF_WaitAllSlaves(void)
1392 {
1393  int i, readySlaves, tag, next = PF_ANY_SOURCE;
1394  UBYTE *has_sent = 0;
1395 
1396  has_sent = (UBYTE*)Malloc1(sizeof(UBYTE)*(PF.numtasks + 1),"PF_WaitAllSlaves");
1397  for ( i = 0; i < PF.numtasks; i++ ) has_sent[i] = 0;
1398 
1399  for ( readySlaves = 1; readySlaves < PF.numtasks; ) {
1400  if ( next != PF_ANY_SOURCE) { /*Go to the next slave:*/
1401  do{ /*Note, here readySlaves<PF.numtasks, so this loop can't be infinite*/
1402  if ( ++next >= PF.numtasks ) next = 1;
1403  } while ( has_sent[next] == 1 );
1404  }
1405 /*
1406  Here PF_ProbeWithCatchingErrorMessages() is BLOCKING function if next = PF_ANY_SOURCE:
1407 */
1408  tag = PF_ProbeWithCatchingErrorMessages(&next);
1409 /*
1410  Here next != PF_ANY_SOURCE
1411 */
1412  switch ( tag ) {
1413  case PF_BUFFER_MSGTAG:
1414  case PF_ENDBUFFER_MSGTAG:
1415 /*
1416  Slaves are ready to send their results back
1417 */
1418  if ( has_sent[next] == 0 ) {
1419  has_sent[next] = 1;
1420  readySlaves++;
1421  }
1422  else { /*error?*/
1423  fprintf(stderr,"ERROR next=%d tag=%d\n",next,tag);
1424  }
1425 /*
1426  Note, we do NOT read results here! Messages from these slaves will be read
1427  only after all slaves are ready, further in caller function
1428 */
1429  break;
1430  case 0:
1431 /*
1432  The slave is not ready. Just go to the next slave.
1433  It may appear that there are no more ready slaves, and the master
1434  will wait them in infinite loop. Stupid situation - the master can
1435  receive buffers from ready slaves!
1436 */
1437 #ifdef PF_WITH_SCHED_YIELD
1438 /*
1439  Relinquish the processor:
1440 */
1441  sched_yield();
1442 #endif
1443  break;
1444  case PF_DATA_MSGTAG:
1445  tag=next;
1446  next=PF_Wait4SlaveIP(&tag);
1447 /*
1448  tag must be == PF_DATA_MSGTAG!
1449 */
1450  PF_Statistics(PF_stats,0);
1451  PF_Slave2MasterIP(next);
1452  PF_Master2SlaveIP(next,NULL);
1453  if ( has_sent[next] == 0 ) {
1454  has_sent[next]=1;
1455  readySlaves++;
1456  }else{
1457  /*error?*/
1458  fprintf(stderr,"ERROR next=%d tag=%d\n",next,tag);
1459  }/*if ( has_sent[next] == 0 )*/
1460  break;
1461  case PF_EMPTY_MSGTAG:
1462  tag=next;
1463  next=PF_Wait4SlaveIP(&tag);
1464 /*
1465  tag must be == PF_EMPTY_MSGTAG!
1466 */
1467  PF_Master2SlaveIP(next,NULL);
1468  if ( has_sent[next] == 0 ) {
1469  has_sent[next]=1;
1470  readySlaves++;
1471  }else{
1472  /*error?*/
1473  fprintf(stderr,"ERROR next=%d tag=%d\n",next,tag);
1474  }/*if ( has_sent[next] == 0 )*/
1475  break;
1476  case PF_READY_MSGTAG:
1477 /*
1478  idle slave
1479  May be only PF_READY_MSGTAG:
1480 */
1481  next = PF_Wait4Slave(next);
1482  if ( next == -1 ) return(next); /*Cannot be!*/
1483  if ( has_sent[0] == 0 ) { /*Send the last chunk to the slave*/
1484  PF.sbuf->active = 0;
1485  has_sent[0] = 1;
1486  }
1487  else {
1488 /*
1489  Last chunk was sent, so just send to slave ENDSORT
1490  AN.ninterms must be sent because the slave expects it:
1491 */
1492  PACK_LONG(PF.sbuf->fill[next], AN.ninterms);
1493 /*
1494  This will tell to the slave that there are no more terms:
1495 */
1496  *(PF.sbuf->fill[next])++ = 0;
1497  PF.sbuf->active = next;
1498  }
1499 /*
1500  Send ENDSORT
1501 */
1502  PF_ISendSbuf(next,PF_ENDSORT_MSGTAG);
1503  break;
1504  default:
1505 /*
1506  Error?
1507  Indicates the error. This will force exit from the main loop:
1508 */
1509  MesPrint("!!!Unexpected MPI message src=%d tag=%d.", next, tag);
1510  readySlaves = PF.numtasks+1;
1511  break;
1512  }
1513  }
1514 
1515  if ( has_sent ) M_free(has_sent,"PF_WaitAllSlaves");
1516 /*
1517  0 on sucess (exit from the main loop by loop condition), or -1 if fails
1518  (exit from the main loop since readySlaves=PF.numtasks+1):
1519 */
1520  return(PF.numtasks-readySlaves);
1521 }
1522 
1523 /*
1524  #] PF_WaitAllSlaves :
1525  #[ PF_Processor :
1526 */
1527 
1540 int PF_Processor(EXPRESSIONS e, WORD i, WORD LastExpression)
1541 {
1542  GETIDENTITY
1543  WORD *term = AT.WorkPointer;
1544  LONG dd = 0;
1545  PF_BUFFER *sb = PF.sbuf;
1546  WORD j, *s, next;
1547  LONG size, cpu;
1548  POSITION position;
1549  int k, src, tag;
1550  FILEHANDLE *oldoutfile = AR.outfile;
1551 
1552 #ifdef MPI2
1553  if ( PF_shared_buff == NULL ) {
1554  if ( PF_SMWin_Init() == 0 ) {
1555  MesPrint("PF_SMWin_Init error");
1556  exit(-1);
1557  }
1558  }
1559 #endif
1560 
1561  if ( ( (WORD *)(((UBYTE *)(AT.WorkPointer)) + AM.MaxTer ) ) > AT.WorkTop ) return(MesWork());
1562 
1563  /* For redefine statements. */
1564  if ( AC.numpfirstnum > 0 ) {
1565  for ( j = 0; j < AC.numpfirstnum; j++ ) {
1566  AC.inputnumbers[j] = -1;
1567  }
1568  }
1569 
1570  if ( AC.mparallelflag != PARALLELFLAG ) return(0);
1571 
1572  if ( PF.me == MASTER ) {
1573 /*
1574  #[ Master:
1575  #[ write prototype to outfile:
1576 */
1577  WORD oldBracketOn = AR.BracketOn;
1578  WORD *oldBrackBuf = AT.BrackBuf;
1579  WORD oldbracketindexflag = AT.bracketindexflag;
1580 
1581  LONG maxinterms; /* the maximum number of terms in the bucket */
1582  int cmaxinterms; /* a variable controling the transition of maxinterms */
1583  LONG termsinbucket; /* the number of filled terms in the bucket */
1584  LONG ProcessBucketSize = AC.mProcessBucketSize;
1585 
1586  if ( PF.log && AC.CModule >= PF.log )
1587  MesPrint("[%d] working on expression %s in module %l",PF.me,EXPRNAME(i),AC.CModule);
1588  if ( GetTerm(BHEAD term) <= 0 ) {
1589  MesPrint("[%d] Expression %d has problems in scratchfile",PF.me,i);
1590  return(-1);
1591  }
1592  term[3] = i;
1593  if ( AR.outtohide ) {
1594  SeekScratch(AR.hidefile,&position);
1595  e->onfile = position;
1596  if ( PutOut(BHEAD term,&position,AR.hidefile,0) < 0 ) return(-1);
1597  }
1598  else {
1599  SeekScratch(AR.outfile,&position);
1600  e->onfile = position;
1601  if ( PutOut(BHEAD term,&position,AR.outfile,0) < 0 ) return(-1);
1602  }
1603  AR.DeferFlag = 0; /* The master leave the brackets!!! */
1604  AR.Eside = RHSIDE;
1605  if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
1606  AR.BracketOn = 1;
1607  AT.BrackBuf = AM.BracketFactors;
1608  AT.bracketindexflag = 1;
1609  }
1610  if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
1611 /*
1612  #] write prototype to outfile:
1613  #[ initialize sendbuffer if necessary:
1614 
1615  the size of the sendbufs is:
1616  MIN(1/PF.numtasks*(AT.SS->sBufsize+AT.SS->lBufsize),AR.infile->POsize)
1617  No allocation for extra buffers necessary, just make sb->buf... point
1618  to the right places in the sortbuffers.
1619 */
1620  NewSort(BHEAD0); /* we need AT.SS to be set for this!!! */
1621  if ( sb == 0 || sb->buff[0] != AT.SS->lBuffer ) {
1622  size = (LONG)((AT.SS->sTop2 - AT.SS->lBuffer)/(PF.numtasks));
1623  if ( size > (LONG)(AR.infile->POsize/sizeof(WORD) - 1) )
1624  size = AR.infile->POsize/sizeof(WORD) - 1;
1625  if ( sb == 0 ) {
1626  if ( ( sb = PF_AllocBuf(PF.numtasks,size*sizeof(WORD),PF.numtasks) ) == NULL )
1627  return(-1);
1628  }
1629  sb->buff[0] = AT.SS->lBuffer;
1630  sb->full[0] = sb->fill[0] = sb->buff[0];
1631  for ( j = 1; j < PF.numtasks; j++ ) {
1632  sb->stop[j-1] = sb->buff[j] = sb->buff[j-1] + size;
1633  }
1634  sb->stop[PF.numtasks-1] = sb->buff[PF.numtasks-1] + size;
1635  PF.sbuf = sb;
1636  }
1637  for ( j = 0; j < PF.numtasks; j++ ) {
1638  sb->full[j] = sb->fill[j] = sb->buff[j];
1639  }
1640 /*
1641  #] initialize sendbuffer if necessary:
1642  #[ loop for all terms in infile:
1643 */
1644  /*
1645  * The initial value of maxinterms is determined by the user given
1646  * ProcessBucketSize and the number of terms in the current expression.
1647  * We make the initial maxinterms smaller, so that we get the all
1648  * workers busy as soon as possible.
1649  */
1650  maxinterms = ProcessBucketSize / 100;
1651  if ( maxinterms > e->counter / (PF.numtasks - 1) / 4 )
1652  maxinterms = e->counter / (PF.numtasks - 1) / 4;
1653  if ( maxinterms < 1 ) maxinterms = 1;
1654  cmaxinterms = 0;
1655  /*
1656  * Copy them always to sb->buff[0]. When that is full, wait for
1657  * the next slave to accept terms, exchange sb->buff[0] and
1658  * sb->buff[next], send sb->buff[next] to next slave and go on
1659  * filling the now empty sb->buff[0].
1660  */
1661  AN.ninterms = 0;
1662  termsinbucket = 0;
1663  PACK_LONG(sb->fill[0], 1);
1664  while ( GetTerm(BHEAD term) ) {
1665  AN.ninterms++; dd = AN.deferskipped;
1666  if ( AC.CollectFun && *term <= (LONG)(AM.MaxTer/(2*sizeof(WORD))) ) {
1667  if ( GetMoreTerms(term) < 0 ) {
1668  LowerSortLevel(); return(-1);
1669  }
1670  }
1671  PRINTFBUF("PF_Processor gets",term,*term);
1672  if ( termsinbucket >= maxinterms || sb->fill[0] + *term >= sb->stop[0] ) {
1673  next = PF_Wait4Slave(PF_ANY_SOURCE);
1674 
1675  sb->fill[next] = sb->fill[0];
1676  sb->full[next] = sb->full[0];
1677  SWAP(sb->stop[next], sb->stop[0]);
1678  SWAP(sb->buff[next], sb->buff[0]);
1679  sb->fill[0] = sb->full[0] = sb->buff[0];
1680  sb->active = next;
1681 
1682 #ifdef MPI2
1683  if ( PF_Put_origin(next) == 0 ) {
1684  printf("PF_Put_origin error...\n");
1685  }
1686 #else
1687  PF_ISendSbuf(next,PF_TERM_MSGTAG);
1688 #endif
1689  /* Initialize the next bucket. */
1690  termsinbucket = 0;
1691  PACK_LONG(sb->fill[0], AN.ninterms);
1692  /*
1693  * For the "slow startup". We double maxinterms up to ProcessBucketSize
1694  * after (houpefully) the all workers got some terms.
1695  */
1696  if ( cmaxinterms >= PF.numtasks - 2 ) {
1697  maxinterms *= 2;
1698  if ( maxinterms >= ProcessBucketSize ) {
1699  cmaxinterms = -1;
1700  maxinterms = ProcessBucketSize;
1701  }
1702  }
1703  else if ( cmaxinterms >= 0 ) {
1704  cmaxinterms++;
1705  }
1706  }
1707  j = *(s = term);
1708  NCOPY(sb->fill[0], s, j);
1709  termsinbucket++;
1710  }
1711  /* NOTE: The last chunk will be sent to a slave at EndSort() => PF_EndSort()
1712  * => PF_WaitAllSlaves(). */
1713  AN.ninterms += dd;
1714 /*
1715  #] loop for all terms in infile:
1716  #[ Clean up & EndSort:
1717 */
1718  if ( LastExpression ) {
1719  UpdateMaxSize();
1720  if ( AR.infile->handle >= 0 ) {
1721  CloseFile(AR.infile->handle);
1722  AR.infile->handle = -1;
1723  remove(AR.infile->name);
1724  PUTZERO(AR.infile->POposition);
1725  }
1726  AR.infile->POfill = AR.infile->POfull = AR.infile->PObuffer;
1727  }
1728  if ( AR.outtohide ) AR.outfile = AR.hidefile;
1729  PF.parallel = 1;
1730  if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) return(-1);
1731  PF.parallel = 0;
1732  if ( AR.outtohide ) {
1733  AR.outfile = oldoutfile;
1734  AR.hidefile->POfull = AR.hidefile->POfill;
1735  }
1736  UpdateMaxSize();
1737  AR.BracketOn = oldBracketOn;
1738  AT.BrackBuf = oldBrackBuf;
1739  if ( ( e->vflags & TOBEFACTORED ) != 0 )
1741  else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
1742  && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
1743  poly_unfactorize_expression(e);
1744  AT.bracketindexflag = oldbracketindexflag;
1745  AR.GetFile = 0;
1746  AR.outtohide = 0;
1747  /*
1748  * NOTE: e->numdummies, e->vflags and AR.exprflags will be updated
1749  * after gathering the information from all slaves.
1750  */
1751 /*
1752  #] Clean up & EndSort:
1753  #[ Collect (stats,prepro,...):
1754 */
1755  DBGOUT_NINTERMS(1, ("PF.me=%d AN.ninterms=%d ENDSORT\n", (int)PF.me, (int)AN.ninterms));
1756  PF_CatchErrorMessagesForAll();
1757  e->numdummies = 0;
1758  for ( k = 1; k < PF.numtasks; k++ ) {
1759  PF_LongSingleReceive(PF_ANY_SOURCE, PF_ENDSORT_MSGTAG, &src, &tag);
1760  PF_LongSingleUnpack(PF_stats[src], PF_STATS_SIZE, PF_LONG);
1761  {
1762  WORD numdummies, expchanged;
1763  PF_LongSingleUnpack(&numdummies, 1, PF_WORD);
1764  PF_LongSingleUnpack(&expchanged, 1, PF_WORD);
1765  if ( e->numdummies < numdummies ) e->numdummies = numdummies;
1766  AR.expchanged |= expchanged;
1767  }
1768  /* Now handle redefined preprocessor variables. */
1769  if ( AC.numpfirstnum > 0 ) PF_UnpackRedefinedPreVars();
1770  }
1771  if ( ! AC.OldParallelStats ) {
1772  /* Now we can calculate AT.SS->GenTerms from the statistics of the slaves. */
1773  LONG genterms = 0;
1774  for ( k = 1; k < PF.numtasks; k++ ) {
1775  genterms += PF_stats[k][3];
1776  }
1777  AT.SS->GenTerms = genterms;
1778  WriteStats(&PF_exprsize, 2);
1779  Expressions[AR.CurExpr].size = PF_exprsize;
1780  }
1781  PF_Statistics(PF_stats,0);
1782 /*
1783  #] Collect (stats,prepro,...):
1784  #[ Update flags :
1785 */
1786  if ( AM.S0->TermsLeft ) e->vflags &= ~ISZERO;
1787  else e->vflags |= ISZERO;
1788  if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
1789  if ( AM.S0->TermsLeft ) AR.expflags |= ISZERO;
1790  if ( AR.expchanged ) AR.expflags |= ISUNMODIFIED;
1791 /*
1792  #] Update flags :
1793  #] Master:
1794 */
1795  }
1796  else {
1797 /*
1798  #[ Slave :
1799 */
1800 /*
1801  #[ Generator Loop & EndSort :
1802 
1803  loop for all terms to get from master, call Generator for each of them
1804  then call EndSort and do cleanup (to be implemented)
1805 */
1806  WORD oldBracketOn = AR.BracketOn;
1807  WORD *oldBrackBuf = AT.BrackBuf;
1808  WORD oldbracketindexflag = AT.bracketindexflag;
1809 
1810  /* For redefine statements. */
1811  if ( AC.numpfirstnum > 0 ) {
1812  for ( j = 0; j < AC.numpfirstnum; j++ ) {
1813  AC.inputnumbers[j] = -1;
1814  }
1815  }
1816 
1817  SeekScratch(AR.outfile,&position);
1818  e->onfile = position;
1819  AR.DeferFlag = AC.ComDefer;
1820  AR.Eside = RHSIDE;
1821  if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
1822  AR.BracketOn = 1;
1823  AT.BrackBuf = AM.BracketFactors;
1824  AT.bracketindexflag = 1;
1825  }
1826  NewSort(BHEAD0);
1827  AR.MaxDum = AM.IndDum;
1828  AN.ninterms = 0;
1829  PF_linterms = 0;
1830  PF.parallel = 1;
1831 #ifdef MPI2
1832  AR.infile->POfull = AR.infile->POfill = AR.infile->PObuffer = PF_shared_buff;
1833 #endif
1834  {
1835  FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
1836  fi->POfull = fi->POfill = fi->PObuffer;
1837  }
1838  /* FIXME: AN.ninterms is still broken when AN.deferskipped is non-zero.
1839  * It still needs some work, also in PF_GetTerm(). (TU 30 Aug 2011) */
1840  while ( PF_GetTerm(term) ) {
1841  PF_linterms++; AN.ninterms++; dd = AN.deferskipped;
1842  AT.WorkPointer = term + *term;
1843  AN.RepPoint = AT.RepCount + 1;
1844  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1845  StoreTerm(BHEAD term);
1846  continue;
1847  }
1848  if ( AR.DeferFlag ) {
1849  AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
1850  }
1851  else {
1852  AN.IndDum = AM.IndDum;
1853  AR.CurDum = ReNumber(BHEAD term);
1854  }
1855  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1856  if ( AN.ncmod ) {
1857  if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1858  else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1859  }
1860  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1861  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1862  && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1863  PolyFunClean(BHEAD term);
1864  }
1865  if ( Generator(BHEAD term,0) ) {
1866  MesPrint("[%d] PF_Processor: Error in Generator",PF.me);
1867  LowerSortLevel(); return(-1);
1868  }
1869  PF_linterms += dd; AN.ninterms += dd;
1870  }
1871  PF_linterms += dd; AN.ninterms += dd;
1872  {
1873  /*
1874  * EndSort() overrides AR.outfile->PObuffer etc. (See also PF_EndSort()),
1875  * but it causes a problem because
1876  * (1) PF_EndSort() sets AR.outfile->PObuffer to a send-buffer.
1877  * (2) RevertScratch() clears AR.infile, but then swaps buffers of AR.infile
1878  * and AR.outfile.
1879  * (3) RHS expressions are stored to AR.infile->PObuffer.
1880  * (4) Again, PF_EndSort() sets AR.outfile->PObuffer, but now AR.outfile->PObuffer
1881  * == AR.infile->PObuffer because of (1) and (2).
1882  * (5) The result goes to AR.outfile. This breaks the RHS expressions,
1883  * which may be needed for the next expression.
1884  * Solution: backup & restore AR.outfile->PObuffer etc. (TU 14 Sep 2011)
1885  */
1886  FILEHANDLE *fout = AR.outfile;
1887  WORD *oldbuff = fout->PObuffer;
1888  WORD *oldstop = fout->POstop;
1889  LONG oldsize = fout->POsize;
1890  if ( EndSort(BHEAD AM.S0->sBuffer, 0) < 0 ) return -1;
1891  fout->PObuffer = oldbuff;
1892  fout->POstop = oldstop;
1893  fout->POsize = oldsize;
1894  fout->POfill = fout->POfull = fout->PObuffer;
1895  }
1896  AR.BracketOn = oldBracketOn;
1897  AT.BrackBuf = oldBrackBuf;
1898  AT.bracketindexflag = oldbracketindexflag;
1899 /*
1900  #] Generator Loop & EndSort :
1901  #[ Collect (stats,prepro...) :
1902 */
1903  DBGOUT_NINTERMS(1, ("PF.me=%d AN.ninterms=%d PF_linterms=%d ENDSORT\n", (int)PF.me, (int)AN.ninterms, (int)PF_linterms));
1905  cpu = TimeCPU(1);
1906  size = 0;
1907  PF_LongSinglePack(&cpu, 1, PF_LONG);
1908  PF_LongSinglePack(&size, 1, PF_LONG);
1909  PF_LongSinglePack(&PF_linterms, 1, PF_LONG);
1910  PF_LongSinglePack(&AM.S0->GenTerms, 1, PF_LONG);
1911  PF_LongSinglePack(&AM.S0->TermsLeft, 1, PF_LONG);
1912  {
1913  WORD numdummies = AR.MaxDum - AM.IndDum;
1914  PF_LongSinglePack(&numdummies, 1, PF_WORD);
1915  PF_LongSinglePack(&AR.expchanged, 1, PF_WORD);
1916  }
1917  /* Now handle redefined preprocessor variables. */
1918  if ( AC.numpfirstnum > 0 ) PF_PackRedefinedPreVars();
1919  PF_LongSingleSend(MASTER, PF_ENDSORT_MSGTAG);
1920 /*
1921  #] Collect (stats,prepro...) :
1922 
1923  This operation is moved to the beginning of each block, see PreProcessor
1924  in pre.c.
1925 
1926  #] Slave :
1927 */
1928  if ( PF.log ) {
1929  UBYTE lbuf[24];
1930  NumToStr(lbuf,AC.CModule);
1931  fprintf(stderr,"[%d|%s] Endsort,Collect,Broadcast done\n",PF.me,lbuf);
1932  fflush(stderr);
1933  }
1934  }
1935  return(0);
1936 }
1937 
1938 /*
1939  #] PF_Processor :
1940  #] proces.c :
1941  #[ startup :, prepro & compile
1942  #[ PF_Init :
1943 */
1944 
1953 int PF_Init(int *argc, char ***argv)
1954 {
1955 /*
1956  this should definitly be somewhere else ...
1957 */
1958  PF_CurrentBracket = 0;
1959 
1960  PF.numtasks = 0; /* number of tasks, is determined in PF_LibInit ! */
1961  PF.numsbufs = 2; /* might be changed by the environment variable on the master ! */
1962  PF.numrbufs = 2; /* might be changed by the environment variable on the master ! */
1963 
1964  PF_LibInit(argc,argv);
1965  PF_RealTime(PF_RESET);
1966 
1967  PF.log = 0;
1968  PF.parallel = 0;
1969  PF_statsinterval = 10;
1970  PF.rhsInParallel=1;
1971  PF.exprbufsize=4096;/*in WORDs*/
1972 
1973 #ifdef PF_WITHGETENV
1974  if ( PF.me == MASTER ) {
1975  char *c;
1976 /*
1977  get these from the environment at the moment sould be in setfile/tail
1978 */
1979  if ( ( c = getenv("PF_LOG") ) != 0 ) {
1980  if ( *c ) PF.log = (int)atoi(c);
1981  else PF.log = 1;
1982  fprintf(stderr,"[%d] changing PF.log to %d\n",PF.me,PF.log);
1983  fflush(stderr);
1984  }
1985  if ( ( c = (char*)getenv("PF_RBUFS") ) != 0 ) {
1986  PF.numrbufs = (int)atoi(c);
1987  fprintf(stderr,"[%d] changing numrbufs to: %d\n",PF.me,PF.numrbufs);
1988  fflush(stderr);
1989  }
1990  if ( ( c = (char*)getenv("PF_SBUFS") ) != 0 ) {
1991  PF.numsbufs = (int)atoi(c);
1992  fprintf(stderr,"[%d] changing numsbufs to: %d\n",PF.me,PF.numsbufs);
1993  fflush(stderr);
1994  }
1995  if ( PF.numsbufs > 10 ) PF.numsbufs = 10;
1996  if ( PF.numsbufs < 1 ) PF.numsbufs = 1;
1997  if ( PF.numrbufs > 2 ) PF.numrbufs = 2;
1998  if ( PF.numrbufs < 1 ) PF.numrbufs = 1;
1999 
2000  if ( ( c = getenv("PF_STATS") ) ) {
2001  UBYTE lbuf[24];
2002  PF_statsinterval = (int)atoi(c);
2003  NumToStr(lbuf,PF_statsinterval);
2004  fprintf(stderr,"[%d] changing PF_statsinterval to %s\n",PF.me,lbuf);
2005  fflush(stderr);
2006  if ( PF_statsinterval < 1 ) PF_statsinterval = 10;
2007  }
2008  }
2009 #endif
2010 /*
2011  #[ Broadcast settings from getenv: could also be done in PF_DoSetup
2012 */
2013  if ( PF.me == MASTER ) {
2014  PF_PreparePack();
2015  PF_Pack(&PF.log,1,PF_INT);
2016  PF_Pack(&PF.numrbufs,1,PF_WORD);
2017  PF_Pack(&PF.numsbufs,1,PF_WORD);
2018  }
2019  PF_Broadcast();
2020  if ( PF.me != MASTER ) {
2021  PF_Unpack(&PF.log,1,PF_INT);
2022  PF_Unpack(&PF.numrbufs,1,PF_WORD);
2023  PF_Unpack(&PF.numsbufs,1,PF_WORD);
2024  if ( PF.log ) {
2025  fprintf(stderr, "[%d] log=%d rbufs=%d sbufs=%d\n",
2026  PF.me, PF.log, PF.numrbufs, PF.numsbufs);
2027  fflush(stderr);
2028  }
2029  }
2030 /*
2031  #] Broadcast settings from getenv:
2032 */
2033  return(0);
2034 }
2035 /*
2036  #] PF_Init :
2037  #[ PF_Terminate :
2038 */
2039 
2047 int PF_Terminate(int errorcode)
2048 {
2049  return PF_LibTerminate(errorcode);
2050 }
2051 
2052 /*
2053  #] PF_Terminate :
2054  #[ PF_GetSlaveTimes :
2055 */
2056 
2064 {
2065  LONG slavetimes = 0;
2066  LONG t = PF.me == MASTER ? 0 : AM.SumTime + TimeCPU(1);
2067  MPI_Reduce(&t, &slavetimes, 1, PF_LONG, MPI_SUM, MASTER, PF_COMM);
2068  return slavetimes;
2069 }
2070 
2071 /*
2072  #] PF_GetSlaveTimes :
2073  #] startup :
2074  #[ PF_BroadcastNumber :
2075 */
2076 
2084 {
2085 #ifdef PF_DEBUG_BCAST_LONG
2086  if ( PF.me == MASTER ) {
2087  MesPrint(">> Broadcast LONG: %l", x);
2088  }
2089 #endif
2090  PF_Bcast(&x, sizeof(LONG));
2091  return x;
2092 }
2093 
2094 /*
2095  #] PF_BroadcastNumber :
2096  #[ PF_BroadcastBuffer :
2097 */
2098 
2110 void PF_BroadcastBuffer(WORD **buffer, LONG *length)
2111 {
2112  WORD *p;
2113  LONG rest;
2114 #ifdef PF_DEBUG_BCAST_BUF
2115  if ( PF.me == MASTER ) {
2116  MesPrint(">> Broadcast Buffer: length=%l", *length);
2117  }
2118 #endif
2119  /* Initialize the buffer on the slaves. */
2120  if ( PF.me != MASTER ) {
2121  *buffer = NULL;
2122  }
2123  /* Broadcast the length of the buffer. */
2124  *length = PF_BroadcastNumber(*length);
2125  if ( *length <= 0 ) return;
2126  /* Allocate the buffer on the slaves. */
2127  if ( PF.me != MASTER ) {
2128  *buffer = (WORD *)Malloc1(*length * sizeof(WORD), "PF_BroadcastBuffer");
2129  }
2130  /* Broadcast the data in the buffer. */
2131  p = *buffer;
2132  rest = *length;
2133  while ( rest > 0 ) {
2134  int l = rest < (LONG)PF.exprbufsize ? (int)rest : PF.exprbufsize;
2135  PF_Bcast(p, l * sizeof(WORD));
2136  p += l;
2137  rest -= l;
2138  }
2139 }
2140 
2141 /*
2142  #] PF_BroadcastBuffer :
2143  #[ PF_BroadcastString :
2144 */
2145 
2152 int PF_BroadcastString(UBYTE *str)
2153 {
2154  int clength = 0;
2155 /*
2156  If string does not fit to the PF_buffer, it
2157  will be split into chanks. Next chank is started at str+clength
2158 */
2159  UBYTE *cstr=str;
2160 /*
2161  Note, compilation is performed INDEPENDENTLY on AC.mparallelflag!
2162  No if ( AC.mparallelflag == PARALLELFLAG ) !!
2163 */
2164  do {
2165  cstr += clength; /*at each step for all slaves and master */
2166 
2167  if ( MASTER == PF.me ) { /*Pack str*/
2168 /*
2169  initialize buffers
2170 */
2171  if ( PF_PreparePack() != 0 ) Terminate(-1);
2172  if ( ( clength = PF_PackString(cstr) ) <0 ) Terminate(-1);
2173  }
2174  PF_Broadcast();
2175 
2176  if ( MASTER != PF.me ) {
2177 /*
2178  Slave - unpack received string
2179  For slaves buffers are initialised automatically.
2180 */
2181  if ( ( clength = PF_UnpackString(cstr) ) < 0 ) Terminate(-1);
2182  }
2183  } while ( cstr[clength-1] != '\0' );
2184  return (0);
2185 }
2186 
2187 /*
2188  #] PF_BroadcastString :
2189  #[ PF_BroadcastPreDollar :
2190 */
2191 
2207 int PF_BroadcastPreDollar(WORD **dbuffer, LONG *newsize, int *numterms)
2208 {
2209  int err = 0;
2210  LONG i;
2211 /*
2212  Note, compilation is performed INDEPENDENTLY on AC.mparallelflag!
2213  No if(AC.mparallelflag==PARALLELFLAG) !!
2214 */
2215  if ( MASTER == PF.me ) {
2216 /*
2217  The problem is that sometimes dollar variables are longer
2218  than PF_packbuf! So we split long expression into chunks.
2219  There are n filled chunks and one portially filled chunk:
2220 */
2221  LONG n = ((*newsize)+1)/PF_maxDollarChunkSize;
2222 /*
2223  ...and one more chunk for the rest; if the expression fits to
2224  the buffer without splitting, the latter will be the only one.
2225 
2226  PF_maxDollarChunkSize is the maximal number of items fitted to
2227  the buffer. It is calculated in PF_LibInit() in mpi.c.
2228  PF_maxDollarChunkSize is calculated for the first step, when
2229  two fields (numterms and newsize, see below) are already packed.
2230  For simplicity, this value is used also for all steps, in
2231  despite of it is a bit less than maximally available space.
2232 */
2233  WORD *thechunk = *dbuffer;
2234 
2235  err = PF_PreparePack(); /* initialize buffers */
2236  err |= PF_Pack(numterms,1,PF_INT);
2237  err |= PF_Pack(newsize,1,PF_LONG); /* pack the size */
2238 /*
2239  Pack and broadcast completely filled chunks.
2240  It may happen, this loop is not entered at all:
2241 */
2242  for ( i = 0; i < n; i++ ) {
2243  err |= PF_Pack(thechunk,PF_maxDollarChunkSize,PF_WORD);
2244  err |= PF_Broadcast();
2245  thechunk +=PF_maxDollarChunkSize;
2246  PF_PreparePack();
2247  }
2248 /*
2249  Pack and broadcast the rest:
2250 */
2251  if ( ( n = ( (*newsize)+1)%PF_maxDollarChunkSize ) != 0 ) {
2252  err |= PF_Pack(thechunk,n,PF_WORD);
2253  err |= PF_Broadcast();
2254  }
2255 #ifdef PF_DEBUG_BCAST_PREDOLLAR
2256  MesPrint(">> Broadcast PreDollar: newsize=%d numterms=%d", (int)*newsize, *numterms);
2257 #endif
2258  }
2259  if ( MASTER != PF.me ) { /* Slave - unpack received buffer */
2260  WORD *thechunk;
2261  LONG n, therest, thesize;
2262  err |= PF_Broadcast();
2263  err |=PF_Unpack(numterms,1,PF_INT);
2264  err |=PF_Unpack(newsize,1,PF_LONG);
2265 /*
2266  Now we know the buffer size.
2267 */
2268  thesize = (*newsize)+1;
2269 /*
2270  Evaluate the number of completely filled chunks. The last step must be
2271  treated separately, so -1:
2272 */
2273  n = (thesize/PF_maxDollarChunkSize) - 1;
2274 /*
2275  Note, here n can be <0, this is ok.
2276 */
2277  therest = thesize % PF_maxDollarChunkSize;
2278  thechunk = *dbuffer =
2279  (WORD*)Malloc1( thesize * sizeof(WORD),"$-buffer slave");
2280  if ( thechunk == NULL ) return(err|4);
2281 /*
2282  Unpack completely filled chunks and receive the next portion.
2283  It may happen, this loop is not entered at all:
2284 */
2285  for ( i = 0; i < n; i++ ) {
2286  err |= PF_Unpack(thechunk,PF_maxDollarChunkSize,PF_WORD);
2287  thechunk += PF_maxDollarChunkSize;
2288  err |= PF_Broadcast();
2289  }
2290 /*
2291  Now the last completely filled chunk:
2292 */
2293  if ( n >= 0 ) {
2294  err |= PF_Unpack(thechunk,PF_maxDollarChunkSize,PF_WORD);
2295  thechunk += PF_maxDollarChunkSize;
2296  if ( therest != 0 ) err |= PF_Broadcast();
2297  }
2298 /*
2299  Unpack the rest (it is already received!):
2300 */
2301  if ( therest != 0 ) err |= PF_Unpack(thechunk,therest,PF_WORD);
2302  }
2303  return (err);
2304 }
2305 
2306 /*
2307  #] PF_BroadcastPreDollar :
2308  #[ Synchronization of modified dollar variables :
2309  #[ Helper functions :
2310  #[ dollarlen :
2311 */
2312 
2316 static inline LONG dollarlen(const WORD *terms)
2317 {
2318  const WORD *p = terms;
2319  while ( *p ) p += *p;
2320  return p - terms; /* Not including the null terminator. */
2321 }
2322 
2323 /*
2324  #] dollarlen :
2325  #[ dollar_mod_type :
2326 */
2327 
2332 static inline WORD dollar_mod_type(WORD index)
2333 {
2334  int i;
2335  for ( i = 0; i < NumModOptdollars; i++ )
2336  if ( ModOptdollars[i].number == index ) break;
2337  if ( i >= NumModOptdollars ) return -1;
2338  return ModOptdollars[i].type;
2339 }
2340 
2341 
2342 /*
2343  #] dollar_mod_type :
2344  #] Helper functions :
2345  #[ PF_CollectModifiedDollars :
2346 */
2347 
2348 /*
2349  #[ dollar_to_be_collected :
2350 */
2351 
2356 static inline int dollar_to_be_collected(WORD index)
2357 {
2358  switch ( dollar_mod_type(index) ) {
2359  case MODSUM:
2360  case MODMAX:
2361  case MODMIN:
2362  return 1;
2363  default:
2364  return 0;
2365  }
2366 }
2367 
2368 /*
2369  #] dollar_to_be_collected :
2370  #[ copy_dollar :
2371 */
2372 
2377 static inline void copy_dollar(WORD index, WORD type, const WORD *where, LONG size)
2378 {
2379  DOLLARS d = Dollars + index;
2380 
2381  CleanDollarFactors(d);
2382 
2383  if ( type != DOLZERO && where != NULL && where != &AM.dollarzero && where[0] != 0 && size > 0 ) {
2384  if ( size > d->size || size < d->size / 4 ) { /* Reallocate if not enough or too much. */
2385  if ( d->where && d->where != &AM.dollarzero )
2386  M_free(d->where, "old content of dollar");
2387  d->where = Malloc1(sizeof(WORD) * size, "copy buffer to dollar");
2388  d->size = size;
2389  }
2390  d->type = type;
2391  WCOPY(d->where, where, size);
2392  }
2393  else {
2394  if ( d->where && d->where != &AM.dollarzero )
2395  M_free(d->where, "old content of dollar");
2396  d->type = DOLZERO;
2397  d->where = &AM.dollarzero;
2398  d->size = 0;
2399  }
2400 }
2401 
2402 /*
2403  #] copy_dollar :
2404  #[ compare_two_expressions :
2405 */
2406 
2411 static inline int compare_two_expressions(const WORD *e1, const WORD *e2)
2412 {
2413  GETIDENTITY
2414  /*
2415  * We consider the cases that
2416  * (1) the expression has no term,
2417  * (2) the expression has only one term and it is a number,
2418  * (3) otherwise.
2419  * Assume that the expressions are sorted and all terms are normalized.
2420  * The numerators of the coefficients must never be zero.
2421  *
2422  * Note that TwoExprCompare() is not adequate for our purpose
2423  * (as of 6 Aug. 2013), e.g., TwoExprCompare({0}, {4, 1, 1, -1}, LESS)
2424  * returns TRUE.
2425  */
2426  if ( e1[0] == 0 ) {
2427  if ( e2[0] == 0 ) {
2428  return(0);
2429  }
2430  else if ( e2[e2[0]] == 0 && e2[0] == ABS(e2[e2[0] - 1]) + 1 ) {
2431  if ( e2[e2[0] - 1] > 0 )
2432  return(-1);
2433  else
2434  return(+1);
2435  }
2436  }
2437  else if ( e1[e1[0]] == 0 && e1[0] == ABS(e1[e1[0] - 1]) + 1 ) {
2438  if ( e2[0] == 0 ) {
2439  if ( e1[e1[0] - 1] > 0 )
2440  return(+1);
2441  else
2442  return(-1);
2443  }
2444  else if ( e2[e2[0]] == 0 && e2[0] == ABS(e2[e2[0] - 1]) + 1 ) {
2445  return(CompCoef((WORD *)e1, (WORD *)e2));
2446  }
2447  }
2448  /* The expressions are not so simple. Define the order by each term. */
2449  while ( e1[0] && e2[0] ) {
2450  int c = CompareTerms((WORD *)e1, (WORD *)e2, 1);
2451  if ( c < 0 )
2452  return(-1);
2453  else if ( c > 0 )
2454  return(+1);
2455  e1 += e1[0];
2456  e2 += e2[0];
2457  }
2458  if ( e1[0] ) return(+1);
2459  if ( e2[0] ) return(-1);
2460  return(0);
2461 }
2462 
2463 /*
2464  #] compare_two_expressions :
2465  #[ Variables :
2466 */
2467 
2468 typedef struct {
2469  VectorStruct(WORD) buf;
2470  LONG size;
2471  WORD type;
2472  PADPOINTER(1,0,1,0);
2473 } dollar_buf;
2474 
2475 /* Buffers used to store data for each variable from each slave. */
2476 static Vector(dollar_buf, dollar_slave_bufs);
2477 
2478 /*
2479  #] Variables :
2480 */
2481 
2496 {
2497  int i, j, ndollars;
2498  /*
2499  * If the current module was executed in the sequential mode,
2500  * there are no modified module on the slaves.
2501  */
2502  if ( AC.mparallelflag != PARALLELFLAG && !AC.partodoflag ) return 0;
2503  /*
2504  * Count the number of (potentially) modified dollar variables, which we need to collect.
2505  * Here we need to collect all max/min/sum variables.
2506  */
2507  ndollars = 0;
2508  for ( i = 0; i < NumPotModdollars; i++ ) {
2509  WORD index = PotModdollars[i];
2510  if ( dollar_to_be_collected(index) ) ndollars++;
2511  }
2512  if ( ndollars == 0 ) return 0; /* No dollars to be collected. */
2513 
2514  if ( PF.me == MASTER ) {
2515 /*
2516  #[ Master :
2517 */
2518  int nslaves, nvars;
2519  /* Prepare receive buffers. We need ndollars*(PF.numtasks-1) buffers. */
2520  int nbufs = ndollars * (PF.numtasks - 1);
2521  VectorReserve(dollar_slave_bufs, nbufs);
2522  for ( i = VectorSize(dollar_slave_bufs); i < nbufs; i++ ) {
2523  VectorInit(VectorPtr(dollar_slave_bufs)[i].buf);
2524  }
2525  VectorSize(dollar_slave_bufs) = nbufs;
2526  /* Receive data from each slave. */
2527  for ( nslaves = 1; nslaves < PF.numtasks; nslaves++ ) {
2528  int src;
2529  PF_LongSingleReceive(PF_ANY_SOURCE, PF_DOLLAR_MSGTAG, &src, NULL);
2530  nvars = 0;
2531  for ( i = 0; i < NumPotModdollars; i++ ) {
2532  WORD index = PotModdollars[i];
2533  dollar_buf *b;
2534  if ( !dollar_to_be_collected(index) ) continue;
2535  b = &VectorPtr(dollar_slave_bufs)[(PF.numtasks - 1) * nvars + (src - 1)];
2536  PF_LongSingleUnpack(&b->type, 1, PF_WORD);
2537  if ( b->type != DOLZERO ) {
2538  LONG size;
2539  WORD *where;
2540  PF_LongSingleUnpack(&size, 1, PF_LONG);
2541  VectorReserve(b->buf, size + 1);
2542  where = VectorPtr(b->buf);
2543  PF_LongSingleUnpack(where, size, PF_WORD);
2544  where[size] = 0; /* The null terminator is needed. */
2545  b->size = size + 1; /* Including the null terminator. */
2546  /* Note that we don't collect factored stuff for max/min/sum variables. */
2547  }
2548  else {
2549  VectorReserve(b->buf, 1);
2550  VectorPtr(b->buf)[0] = 0;
2551  b->size = 0;
2552  }
2553  nvars++;
2554  }
2555  }
2556  /*
2557  * Combine received dollars. The FORM reference manual says maximum/minimum/sum
2558  * $-variables must have a numerical value, however, this routine should work also
2559  * for non-numerical cases, although the maximum/minimum value for non-numerical
2560  * terms has ambiguity.
2561  */
2562  nvars = 0;
2563  for ( i = 0; i < NumPotModdollars; i++ ) {
2564  WORD index = PotModdollars[i];
2565  WORD dtype;
2566  DOLLARS d;
2567  dollar_buf *b;
2568  if ( !dollar_to_be_collected(index) ) continue;
2569  d = Dollars + index;
2570  b = &VectorPtr(dollar_slave_bufs)[(PF.numtasks - 1) * nvars];
2571  dtype = dollar_mod_type(index);
2572  switch ( dtype ) {
2573  case MODMAX:
2574  case MODMIN: {
2575 /*
2576  #[ MODMAX & MODMIN :
2577 */
2578  int selected = 0;
2579  for ( j = 1; j < PF.numtasks - 1; j++ ) {
2580  int c = compare_two_expressions(VectorPtr(b[j].buf), VectorPtr(b[selected].buf));
2581  if ( (dtype == MODMAX && c > 0) || (dtype == MODMIN && c < 0) )
2582  selected = j;
2583  }
2584  b = b + selected;
2585  copy_dollar(index, b->type, VectorPtr(b->buf), b->size);
2586 /*
2587  #] MODMAX & MODMIN :
2588 */
2589  break;
2590  }
2591  case MODSUM: {
2592 /*
2593  #[ MODSUM :
2594 */
2595  GETIDENTITY
2596  int err = 0;
2597 
2598  CBUF *C = cbuf + AM.rbufnum;
2599  WORD *oldwork = AT.WorkPointer, *oldcterm = AN.cTerm;
2600  WORD olddefer = AR.DeferFlag, oldnumlhs = AR.Cnumlhs, oldnumrhs = C->numrhs;
2601 
2602  LONG size;
2603  WORD type, *dbuf;
2604 
2605  AN.cTerm = 0;
2606  AR.DeferFlag = 0;
2607 
2608  if ( ((WORD *)((UBYTE *)AT.WorkPointer + AM.MaxTer)) > AT.WorkTop ) {
2609  err = -1;
2610  goto cleanup;
2611  MesWork();
2612  }
2613 
2614  if ( NewSort(BHEAD0) ) {
2615  err = -1;
2616  goto cleanup;
2617  }
2618  if ( NewSort(BHEAD0) ) {
2619  LowerSortLevel();
2620  err = -1;
2621  goto cleanup;
2622  }
2623 
2624  /*
2625  * Sum up the original $-variable in the master and $-variables on all slaves.
2626  * Note that $-variables on the slaves are set to zero at the beginning of
2627  * the module (See also DoExecute()).
2628  */
2629  for ( j = 0; j < PF.numtasks; j++ ) {
2630  const WORD *r;
2631  for ( r = j == 0 ? Dollars[index].where : VectorPtr(b[j - 1].buf); *r; r += *r ) {
2632  WCOPY(AT.WorkPointer, r, *r);
2633  AT.WorkPointer += *r;
2634  AR.Cnumlhs = 0;
2635  if ( Generator(BHEAD oldwork, 0) ) {
2637  err = -1;
2638  goto cleanup;
2639  }
2640  AT.WorkPointer = oldwork;
2641  }
2642  }
2643 
2644  size = EndSort(BHEAD (WORD *)&dbuf, 2);
2645  if ( size < 0 ) {
2646  LowerSortLevel();
2647  err = -1;
2648  goto cleanup;
2649  }
2650  LowerSortLevel();
2651 
2652  /* Find special cases. */
2653  type = DOLTERMS;
2654  if ( dbuf[0] == 0 ) {
2655  type = DOLZERO;
2656  }
2657  else if ( dbuf[dbuf[0]] == 0 ) {
2658  const WORD *t = dbuf, *w;
2659  WORD n, nsize;
2660  n = *t;
2661  nsize = t[n - 1];
2662  if ( nsize < 0 ) nsize = -nsize;
2663  if ( nsize == n - 1 ) {
2664  nsize = (nsize - 1) / 2;
2665  w = t + 1 + nsize;
2666  if ( *w == 1 ) {
2667  w++; while ( w < t + n - 1 ) { if ( *w ) break; w++; }
2668  if ( w >= t + n - 1 ) type = DOLNUMBER;
2669  }
2670  else if ( n == 7 && t[6] == 3 && t[5] == 1 && t[4] == 1 && t[1] == INDEX && t[2] == 3 ) {
2671  type = DOLINDEX;
2672  d->index = t[3];
2673  }
2674  }
2675  }
2676  copy_dollar(index, type, dbuf, dollarlen(dbuf) + 1);
2677  M_free(dbuf, "temporary dollar buffer");
2678 cleanup:
2679  AR.Cnumlhs = oldnumlhs;
2680  C->numrhs = oldnumrhs;
2681  AR.DeferFlag = olddefer;
2682  AN.cTerm = oldcterm;
2683  AT.WorkPointer = oldwork;
2684 
2685  if ( err ) return err;
2686 /*
2687  #] MODSUM :
2688 */
2689  break;
2690  }
2691  }
2692  if ( d->type == DOLTERMS )
2693  cbuf[AM.dbufnum].CanCommu[index] = numcommute(d->where, &cbuf[AM.dbufnum].NumTerms[index]);
2694  cbuf[AM.dbufnum].rhs[index] = d->where;
2695  nvars++;
2696 #ifdef PF_DEBUG_REDUCE_DOLLAR
2697  MesPrint("<< Reduce $-var: %s", AC.dollarnames->namebuffer + d->name);
2698 #endif
2699  }
2700 /*
2701  #] Master :
2702 */
2703  }
2704  else {
2705 /*
2706  #[ Slave :
2707 */
2709  /* Pack each variable. */
2710  for ( i = 0; i < NumPotModdollars; i++ ) {
2711  WORD index = PotModdollars[i];
2712  DOLLARS d;
2713  if ( !dollar_to_be_collected(index) ) continue;
2714  d = Dollars + index;
2715  PF_LongSinglePack(&d->type, 1, PF_WORD);
2716  if ( d->type != DOLZERO ) {
2717  /*
2718  * NOTE: d->size is the allocated buffer size for d->where in WORDs.
2719  * So dollarlen(d->where) can be < d->size-1. (TU 15 Dec 2011)
2720  */
2721  LONG size = dollarlen(d->where);
2722  PF_LongSinglePack(&size, 1, PF_LONG);
2723  PF_LongSinglePack(d->where, size, PF_WORD);
2724  /* Note that we don't collect factored stuff for max/min/sum variables. */
2725  }
2726  }
2727  PF_LongSingleSend(MASTER, PF_DOLLAR_MSGTAG);
2728 /*
2729  #] Slave :
2730 */
2731  }
2732  return 0;
2733 }
2734 
2735 /*
2736  #] PF_CollectModifiedDollars :
2737  #[ PF_BroadcastModifiedDollars :
2738 */
2739 
2740 /*
2741  #[ dollar_to_be_broadcast :
2742 */
2743 
2748 static inline int dollar_to_be_broadcast(WORD index)
2749 {
2750  switch ( dollar_mod_type(index) ) {
2751  case MODLOCAL:
2752  return 0;
2753  default:
2754  return 1;
2755  }
2756 }
2757 
2758 /*
2759  #] dollar_to_be_broadcast :
2760 */
2761 
2775 {
2776  int i, j, ndollars;
2777  /*
2778  * Count the number of (potentially) modified dollar variables, which we need to broadcast.
2779  * Here we need to broadcast all non-local variables.
2780  */
2781  ndollars = 0;
2782  for ( i = 0; i < NumPotModdollars; i++ ) {
2783  WORD index = PotModdollars[i];
2784  if ( dollar_to_be_broadcast(index) ) ndollars++;
2785  }
2786  if ( ndollars == 0 ) return 0; /* No dollars to be broadcast. */
2787 
2788  if ( PF.me == MASTER ) {
2789 /*
2790  #[ Master :
2791 */
2793  /* Pack each variable. */
2794  for ( i = 0; i < NumPotModdollars; i++ ) {
2795  WORD index = PotModdollars[i];
2796  DOLLARS d;
2797  if ( !dollar_to_be_broadcast(index) ) continue;
2798  d = Dollars + index;
2799  PF_LongMultiPack(&d->type, 1, PF_WORD);
2800  if ( d->type != DOLZERO ) {
2801  /*
2802  * NOTE: d->size is the allocated buffer size for d->where in WORDs.
2803  * So dollarlen(d->where) can be < d->size-1. (TU 15 Dec 2011)
2804  */
2805  LONG size = dollarlen(d->where);
2806  PF_LongMultiPack(&size, 1, PF_LONG);
2807  PF_LongMultiPack(d->where, size, PF_WORD);
2808  /* ...and the factored stuff. */
2809  PF_LongMultiPack(&d->nfactors, 1, PF_WORD);
2810  if ( d->nfactors > 1 ) {
2811  for ( j = 0; j < d->nfactors; j++ ) {
2812  FACDOLLAR *f = &d->factors[j];
2813  PF_LongMultiPack(&f->type, 1, PF_WORD);
2814  PF_LongMultiPack(&f->size, 1, PF_LONG);
2815  if ( f->size > 0 )
2816  PF_LongMultiPack(f->where, f->size, PF_WORD);
2817  else
2818  PF_LongMultiPack(&f->value, 1, PF_WORD);
2819  }
2820  }
2821  }
2822 #ifdef PF_DEBUG_BCAST_DOLLAR
2823  MesPrint(">> Broadcast $-var: %s", AC.dollarnames->namebuffer + d->name);
2824 #endif
2825  }
2826 /*
2827  #] Master :
2828 */
2829  }
2830  if ( PF_LongMultiBroadcast() ) return -1;
2831  if ( PF.me != MASTER ) {
2832 /*
2833  #[ Slave :
2834 */
2835  for ( i = 0; i < NumPotModdollars; i++ ) {
2836  WORD index = PotModdollars[i];
2837  DOLLARS d;
2838  if ( !dollar_to_be_broadcast(index) ) continue;
2839  d = Dollars + index;
2840  /* Clear the contents of the dollar variable. */
2841  if ( d->where && d->where != &AM.dollarzero )
2842  M_free(d->where, "old content of dollar");
2843  d->where = &AM.dollarzero;
2844  d->size = 0;
2845  CleanDollarFactors(d);
2846  /* Unpack and store the contents. */
2847  PF_LongMultiUnpack(&d->type, 1, PF_WORD);
2848  if ( d->type != DOLZERO ) {
2849  LONG size;
2850  PF_LongMultiUnpack(&size, 1, PF_LONG);
2851  d->size = size + 1;
2852  d->where = (WORD *)Malloc1(sizeof(WORD) * d->size, "dollar content");
2853  PF_LongMultiUnpack(d->where, size, PF_WORD);
2854  d->where[size] = 0; /* The null terminator is needed. */
2855  /* ...and the factored stuff. */
2856  PF_LongMultiUnpack(&d->nfactors, 1, PF_WORD);
2857  if ( d->nfactors > 1 ) {
2858  d->factors = (FACDOLLAR *)Malloc1(sizeof(FACDOLLAR) * d->nfactors, "dollar factored stuff");
2859  for ( j = 0; j < d->nfactors; j++ ) {
2860  FACDOLLAR *f = &d->factors[j];
2861  PF_LongMultiUnpack(&f->type, 1, PF_WORD);
2862  PF_LongMultiUnpack(&f->size, 1, PF_LONG);
2863  if ( f->size > 0 ) {
2864  f->where = (WORD *)Malloc1(sizeof(WORD) * (f->size + 1), "dollar factor content");
2865  PF_LongMultiUnpack(f->where, f->size, PF_WORD);
2866  f->where[f->size] = 0; /* The null terminator is needed. */
2867  f->value = 0;
2868  }
2869  else {
2870  f->where = NULL;
2871  PF_LongMultiUnpack(&f->value, 1, PF_WORD);
2872  }
2873  }
2874  }
2875  }
2876  if ( d->type == DOLTERMS )
2877  cbuf[AM.dbufnum].CanCommu[index] = numcommute(d->where, &cbuf[AM.dbufnum].NumTerms[index]);
2878  cbuf[AM.dbufnum].rhs[index] = d->where;
2879  }
2880 /*
2881  #] Slave :
2882 */
2883  }
2884  return 0;
2885 }
2886 
2887 /*
2888  #] PF_BroadcastModifiedDollars :
2889  #] Synchronization of modified dollar variables :
2890  #[ Synchronization of redefined preprocessor variables :
2891  #[ Variables :
2892 */
2893 
2894 /* A buffer used in receivers. */
2895 static Vector(UBYTE, prevarbuf);
2896 
2897 /*
2898  #] Variables :
2899  #[ PF_PackRedefinedPreVars :
2900 */
2901 
2910 static void PF_PackRedefinedPreVars(void)
2911 {
2912  int i;
2913  /* First, pack the number of redefined preprocessor variables. */
2914  int nredefs = 0;
2915  for ( i = 0; i < AC.numpfirstnum; i++ )
2916  if ( AC.inputnumbers[i] >= 0 ) nredefs++;
2917  PF_LongSinglePack(&nredefs, 1, PF_INT);
2918  /* Then, pack each variable. */
2919  for ( i = 0; i < AC.numpfirstnum; i++ )
2920  if ( AC.inputnumbers[i] >= 0) {
2921  WORD index = AC.pfirstnum[i];
2922  UBYTE *value = PreVar[index].value;
2923  int bytes = strlen((char *)value);
2924  PF_LongSinglePack(&index, 1, PF_WORD);
2925  PF_LongSinglePack(&bytes, 1, PF_INT);
2926  PF_LongSinglePack(value, bytes, PF_BYTE);
2927  PF_LongSinglePack(&AC.inputnumbers[i], 1, PF_LONG);
2928  }
2929 }
2930 
2931 /*
2932  #] PF_PackRedefinedPreVars :
2933  #[ PF_UnpackRedefinedPreVars :
2934 */
2935 
2945 static void PF_UnpackRedefinedPreVars(void)
2946 {
2947  int i, j;
2948  /* Unpack the number of redefined preprocessor variables. */
2949  int nredefs;
2950  PF_LongSingleUnpack(&nredefs, 1, PF_INT);
2951  if ( nredefs > 0 ) {
2952  /* Then unpack each variable. */
2953  for ( i = 0; i < nredefs; i++ ) {
2954  WORD index;
2955  int bytes;
2956  UBYTE *value;
2957  LONG inputnumber;
2958  PF_LongSingleUnpack(&index, 1, PF_WORD);
2959  PF_LongSingleUnpack(&bytes, 1, PF_INT);
2960  VectorReserve(prevarbuf, bytes + 1);
2961  value = VectorPtr(prevarbuf);
2962  PF_LongSingleUnpack(value, bytes, PF_BYTE);
2963  value[bytes] = '\0'; /* The null terminator is needed. */
2964  PF_LongSingleUnpack(&inputnumber, 1, PF_LONG);
2965  /* Put this variable if it must be updated. */
2966  for ( j = 0; j < AC.numpfirstnum; j++ )
2967  if ( AC.pfirstnum[j] == index ) break;
2968  if ( AC.inputnumbers[j] < inputnumber ) {
2969  AC.inputnumbers[j] = inputnumber;
2970  PutPreVar(PreVar[index].name, value, NULL, 1);
2971  }
2972  }
2973  }
2974 }
2975 
2976 /*
2977  #] PF_UnpackRedefinedPreVars :
2978  #[ PF_BroadcastRedefinedPreVars :
2979 */
2980 
2992 {
2993  /*
2994  * NOTE: Because the compilation is performed on the all processes
2995  * independently on AC.mparallelflag, we always have to broadcast redefined
2996  * preprocessor variables from the master to the all slaves.
2997  */
2998  if ( PF.me == MASTER ) {
2999 /*
3000  #[ Master :
3001 */
3002  int i, nredefs;
3004  /* First, pack the number of redefined preprocessor variables. */
3005  nredefs = 0;
3006  for ( i = 0; i < AC.numpfirstnum; i++ )
3007  if ( AC.inputnumbers[i] >= 0 ) nredefs++;
3008  PF_LongMultiPack(&nredefs, 1, PF_INT);
3009  /* Then, pack each variable. */
3010  for ( i = 0; i < AC.numpfirstnum; i++ )
3011  if ( AC.inputnumbers[i] >= 0) {
3012  WORD index = AC.pfirstnum[i];
3013  UBYTE *value = PreVar[index].value;
3014  int bytes = strlen((char *)value);
3015  PF_LongMultiPack(&index, 1, PF_WORD);
3016  PF_LongMultiPack(&bytes, 1, PF_INT);
3017  PF_LongMultiPack(value, bytes, PF_BYTE);
3018 #ifdef PF_DEBUG_BCAST_PREVAR
3019  MesPrint(">> Broadcast PreVar: %s = \"%s\"", PreVar[index].name, value);
3020 #endif
3021  }
3022 /*
3023  #] Master :
3024 */
3025  }
3026  if ( PF_LongMultiBroadcast() ) return -1;
3027  if ( PF.me != MASTER ) {
3028 /*
3029  #[ Slave :
3030 */
3031  int i, nredefs;
3032  /* Unpack the number of redefined preprocessor variables. */
3033  PF_LongMultiUnpack(&nredefs, 1, PF_INT);
3034  if ( nredefs > 0 ) {
3035  /* Then unpack each variable and put it. */
3036  for ( i = 0; i < nredefs; i++ ) {
3037  WORD index;
3038  int bytes;
3039  UBYTE *value;
3040  PF_LongMultiUnpack(&index, 1, PF_WORD);
3041  PF_LongMultiUnpack(&bytes, 1, PF_INT);
3042  VectorReserve(prevarbuf, bytes + 1);
3043  value = VectorPtr(prevarbuf);
3044  PF_LongMultiUnpack(value, bytes, PF_BYTE);
3045  value[bytes] = '\0'; /* The null terminator is needed. */
3046  PutPreVar(PreVar[index].name, value, NULL, 1);
3047  }
3048  }
3049 /*
3050  #] Slave :
3051 */
3052  }
3053  return 0;
3054 }
3055 
3056 /*
3057  #] PF_BroadcastRedefinedPreVars :
3058  #] Synchronization of redefined preprocessor variables :
3059  #[ Preprocessor Inside instruction :
3060  #[ Variables :
3061 */
3062 
3063 /* Saved values of AC.RhsExprInModuleFlag, PotModdollars and AC.pfirstnum. */
3064 static WORD oldRhsExprInModuleFlag;
3065 static Vector(WORD, oldPotModdollars);
3066 static Vector(WORD, oldpfirstnum);
3067 
3068 /*
3069  #] Variables :
3070  #[ PF_StoreInsideInfo :
3071 */
3072 
3073 /*
3074  * Saves the current values of AC.RhsExprInModuleFlag, PotModdollars
3075  * and AC.pfirstnum.
3076  *
3077  * Called by DoInside().
3078  *
3079  * @return 0 if OK, nonzero on error.
3080  */
3081 int PF_StoreInsideInfo(void)
3082 {
3083  int i;
3084  oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
3085  VectorClear(oldPotModdollars);
3086  for ( i = 0; i < NumPotModdollars; i++ )
3087  VectorPushBack(oldPotModdollars, PotModdollars[i]);
3088  VectorClear(oldpfirstnum);
3089  for ( i = 0; i < AC.numpfirstnum; i++ )
3090  VectorPushBack(oldpfirstnum, AC.pfirstnum[i]);
3091  return 0;
3092 }
3093 
3094 /*
3095  #] PF_StoreInsideInfo :
3096  #[ PF_RestoreInsideInfo :
3097 */
3098 
3099 /*
3100  * Restores the saved values of AC.RhsExprInModuleFlag, PotModdollars
3101  * and AC.pfirstnum.
3102  *
3103  * Called by DoEndInside().
3104  *
3105  * @return 0 if OK, nonzero on error.
3106  */
3107 int PF_RestoreInsideInfo(void)
3108 {
3109  int i;
3110  AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
3111  NumPotModdollars = VectorSize(oldPotModdollars);
3112  for ( i = 0; i < NumPotModdollars; i++ )
3113  PotModdollars[i] = VectorPtr(oldPotModdollars)[i];
3114  AC.numpfirstnum = VectorSize(oldpfirstnum);
3115  for ( i = 0; i < AC.numpfirstnum; i++ )
3116  AC.pfirstnum[i] = VectorPtr(oldpfirstnum)[i];
3117  return 0;
3118 }
3119 
3120 /*
3121  #] PF_RestoreInsideInfo :
3122  #] Preprocessor Inside instruction :
3123  #[ PF_BroadcastCBuf :
3124 */
3125 
3133 int PF_BroadcastCBuf(int bufnum)
3134 {
3135  CBUF *C = cbuf + bufnum;
3136  int i;
3137  LONG l;
3138  if ( PF.me == MASTER ) {
3139 /*
3140  #[ Master :
3141 */
3143  /* Pack CBUF struct except pointers. */
3144  PF_LongMultiPack(&C->BufferSize, 1, PF_LONG);
3145  PF_LongMultiPack(&C->numlhs, 1, PF_INT);
3146  PF_LongMultiPack(&C->numrhs, 1, PF_INT);
3147  PF_LongMultiPack(&C->maxlhs, 1, PF_INT);
3148  PF_LongMultiPack(&C->maxrhs, 1, PF_INT);
3149  PF_LongMultiPack(&C->mnumlhs, 1, PF_INT);
3150  PF_LongMultiPack(&C->mnumrhs, 1, PF_INT);
3151  PF_LongMultiPack(&C->numtree, 1, PF_INT);
3152  PF_LongMultiPack(&C->rootnum, 1, PF_INT);
3153  PF_LongMultiPack(&C->MaxTreeSize, 1, PF_INT);
3154  /* Now pointers. Pointer, lhs and rhs are packed as offsets. We don't pack Top. */
3155  l = C->Pointer - C->Buffer;
3156  PF_LongMultiPack(&l, 1, PF_LONG);
3157  PF_LongMultiPack(C->Buffer, l, PF_WORD);
3158  for ( i = 0; i < C->numlhs + 1; i++ ) {
3159  l = C->lhs[i] - C->Buffer;
3160  PF_LongMultiPack(&l, 1, PF_LONG);
3161  }
3162  for ( i = 0; i < C->numrhs + 1; i++ ) {
3163  l = C->rhs[i] - C->Buffer;
3164  PF_LongMultiPack(&l, 1, PF_LONG);
3165  }
3166  PF_LongMultiPack(C->CanCommu, C->numrhs + 1, PF_LONG);
3167  PF_LongMultiPack(C->NumTerms, C->numrhs + 1, PF_LONG);
3168  PF_LongMultiPack(C->numdum, C->numrhs + 1, PF_WORD);
3169  PF_LongMultiPack(C->dimension, C->numrhs + 1, PF_WORD);
3170  if ( C->MaxTreeSize > 0 )
3171  PF_LongMultiPack(C->boomlijst, (C->numtree + 1) * (sizeof(COMPTREE) / sizeof(int)), PF_INT);
3172 #ifdef PF_DEBUG_BCAST_CBUF
3173  MesPrint(">> Broadcast CBuf %d", bufnum);
3174 #endif
3175 /*
3176  #] Master :
3177 */
3178  }
3179  if ( PF_LongMultiBroadcast() ) return -1;
3180  if ( PF.me != MASTER ) {
3181 /*
3182  #[ Slave :
3183 */
3184  /* First, free already allocated buffers. */
3185  finishcbuf(bufnum);
3186  /* Unpack CBUF struct except pointers. */
3187  PF_LongMultiUnpack(&C->BufferSize, 1, PF_LONG);
3188  PF_LongMultiUnpack(&C->numlhs, 1, PF_INT);
3189  PF_LongMultiUnpack(&C->numrhs, 1, PF_INT);
3190  PF_LongMultiUnpack(&C->maxlhs, 1, PF_INT);
3191  PF_LongMultiUnpack(&C->maxrhs, 1, PF_INT);
3192  PF_LongMultiUnpack(&C->mnumlhs, 1, PF_INT);
3193  PF_LongMultiUnpack(&C->mnumrhs, 1, PF_INT);
3194  PF_LongMultiUnpack(&C->numtree, 1, PF_INT);
3195  PF_LongMultiUnpack(&C->rootnum, 1, PF_INT);
3196  PF_LongMultiUnpack(&C->MaxTreeSize, 1, PF_INT);
3197  /* Allocate new buffers. */
3198  C->Buffer = (WORD *)Malloc1(C->BufferSize * sizeof(WORD), "compiler buffer");
3199  C->Top = C->Buffer + C->BufferSize;
3200  C->lhs = (WORD **)Malloc1(C->maxlhs * sizeof(WORD *), "compiler buffer");
3201  C->rhs = (WORD **)Malloc1(C->maxrhs * (sizeof(WORD *) + 2 * sizeof(LONG) + 2 * sizeof(WORD)), "compiler buffer");
3202  C->CanCommu = (LONG *)(C->rhs + C->maxrhs);
3203  C->NumTerms = C->CanCommu + C->maxrhs;
3204  C->numdum = (WORD *)(C->NumTerms + C->maxrhs);
3205  C->dimension = C->numdum + C->maxrhs;
3206  if ( C->MaxTreeSize > 0 )
3207  C->boomlijst = (COMPTREE *)Malloc1(C->MaxTreeSize * sizeof(COMPTREE), "compiler buffer");
3208  /* Unpack buffers. */
3209  PF_LongMultiUnpack(&l, 1, PF_LONG);
3210  PF_LongMultiUnpack(C->Buffer, l, PF_WORD);
3211  C->Pointer = C->Buffer + l;
3212  for ( i = 0; i < C->numlhs + 1; i++ ) {
3213  PF_LongMultiUnpack(&l, 1, PF_LONG);
3214  C->lhs[i] = C->Buffer + l;
3215  }
3216  for ( i = 0; i < C->numrhs + 1; i++ ) {
3217  PF_LongMultiUnpack(&l, 1, PF_LONG);
3218  C->rhs[i] = C->Buffer + l;
3219  }
3220  PF_LongMultiUnpack(C->CanCommu, C->numrhs + 1, PF_LONG);
3221  PF_LongMultiUnpack(C->NumTerms, C->numrhs + 1, PF_LONG);
3222  PF_LongMultiUnpack(C->numdum, C->numrhs + 1, PF_WORD);
3223  PF_LongMultiUnpack(C->dimension, C->numrhs + 1, PF_WORD);
3224  if ( C->MaxTreeSize > 0 )
3225  PF_LongMultiUnpack(C->boomlijst, (C->numtree + 1) * (sizeof(COMPTREE) / sizeof(int)), PF_INT);
3226 /*
3227  #] Slave :
3228 */
3229  }
3230  return 0;
3231 }
3232 
3233 /*
3234  #] PF_BroadcastCBuf :
3235  #[ PF_BroadcastExpFlags :
3236 */
3237 
3245 {
3246  WORD i;
3247  EXPRESSIONS e;
3248  if ( PF.me == MASTER ) {
3249 /*
3250  #[ Master :
3251 */
3253  PF_LongMultiPack(&AR.expflags, 1, PF_WORD);
3254  for ( i = 0; i < NumExpressions; i++ ) {
3255  e = &Expressions[i];
3256  PF_LongMultiPack(&e->counter, 1, PF_WORD);
3257  PF_LongMultiPack(&e->vflags, 1, PF_WORD);
3258  PF_LongMultiPack(&e->numdummies, 1, PF_WORD);
3259  PF_LongMultiPack(&e->numfactors, 1, PF_WORD);
3260 #ifdef PF_DEBUG_BCAST_EXPRFLAGS
3261  MesPrint(">> Broadcast ExprFlags: %s", AC.exprnames->namebuffer + e->name);
3262 #endif
3263  }
3264 /*
3265  #] Master :
3266 */
3267  }
3268  if ( PF_LongMultiBroadcast() ) return -1;
3269  if ( PF.me != MASTER ) {
3270 /*
3271  #[ Slave :
3272 */
3273  PF_LongMultiUnpack(&AR.expflags, 1, PF_WORD);
3274  for ( i = 0; i < NumExpressions; i++ ) {
3275  e = &Expressions[i];
3276  PF_LongMultiUnpack(&e->counter, 1, PF_WORD);
3277  PF_LongMultiUnpack(&e->vflags, 1, PF_WORD);
3278  PF_LongMultiUnpack(&e->numdummies, 1, PF_WORD);
3279  PF_LongMultiUnpack(&e->numfactors, 1, PF_WORD);
3280  }
3281 /*
3282  #] Slave :
3283 */
3284  }
3285  return 0;
3286 }
3287 
3288 /*
3289  #] PF_BroadcastExpFlags :
3290  #[ PF_SetScratch :
3291 */
3292 
3299 static void PF_SetScratch(FILEHANDLE *f,POSITION *position)
3300 {
3301  if(
3302  ( f->handle >= 0) && ISGEPOS(*position,f->POposition) &&
3303  ( ISGEPOSINC(*position,f->POposition,(f->POfull-f->PObuffer)*sizeof(WORD)) ==0 )
3304  )/*position is inside the buffer! SetScratch() will do nothing.*/
3305  f->POfull=f->PObuffer;/*force SetScratch() to re-read the position from the beginning:*/
3306  SetScratch(f,position);
3307 }
3308 
3309 /*
3310  #] PF_SetScratch :
3311  #[ PF_pushScratch :
3312 */
3313 
3320 static int PF_pushScratch(FILEHANDLE *f)
3321 {
3322  LONG size,RetCode;
3323  if ( f->handle < 0){
3324  /*Create the file*/
3325  if ( ( RetCode = CreateFile(f->name) ) >= 0 ) {
3326  f->handle = (WORD)RetCode;
3327  PUTZERO(f->filesize);
3328  PUTZERO(f->POposition);
3329  }
3330  else{
3331  MesPrint("Cannot create scratch file %s",f->name);
3332  return(-1);
3333  }
3334  }/*if ( f->handle < 0)*/
3335  size = (f->POfill-f->PObuffer)*sizeof(WORD);
3336  if( size > 0 ){
3337  SeekFile(f->handle,&(f->POposition),SEEK_SET);
3338  if ( WriteFile(f->handle,(UBYTE *)(f->PObuffer),size) != size ){
3339  MesPrint("Error while writing to disk. Disk full?");
3340  return(-1);
3341  }
3342  ADDPOS(f->filesize,size);
3343  ADDPOS(f->POposition,size);
3344  f->POfill = f->POfull=f->PObuffer;
3345  }/*if( size > 0 )*/
3346  return(0);
3347 }
3348 
3349 /*
3350  #] PF_pushScratch :
3351  #[ Broadcasting RHS expressions :
3352  #[ PF_WalkThroughExprMaster :
3353  Returns <=0 if the expression is ready, or dl+1;
3354 */
3355 
3356 static int PF_WalkThroughExprMaster(FILEHANDLE *curfile, int dl)
3357 {
3358  LONG l=0;
3359  for(;;){
3360  if(curfile->POfull-curfile->POfill < dl){
3361  POSITION pos;
3362  SeekScratch(curfile,&pos);
3363  PF_SetScratch(curfile,&pos);
3364  }/*if(curfile->POfull-curfile->POfill < dl)*/
3365  curfile->POfill+=dl;
3366  l+=dl;
3367  if( l >= PF.exprbufsize){
3368  if( l == PF.exprbufsize){
3369  if( *(curfile->POfill) == 0)/*expression is ready*/
3370  return(0);
3371  }
3372  l-=PF.exprbufsize;
3373  curfile->POfill-=l;
3374  return l+1;
3375  }
3376 
3377  dl=*(curfile->POfill);
3378  if(dl == 0)
3379  return l-PF.exprbufsize;
3380 
3381  if(dl<0){/*compressed term*/
3382  if(curfile->POfull-curfile->POfill < 1){
3383  POSITION pos;
3384  SeekScratch(curfile,&pos);
3385  PF_SetScratch(curfile,&pos);
3386  }/*if(curfile->POfull-curfile->POfill < 1)*/
3387  dl=*(curfile->POfill+1)+2;
3388  }/*if(*(curfile->POfill)<0)*/
3389  }/*for(;;)*/
3390 }
3391 
3392 /*
3393  #] PF_WalkThroughExprMaster :
3394  #[ PF_WalkThroughExprSlave :
3395  Returns <=0 if the expression is ready, or dl+1;
3396 */
3397 
3398 static int PF_WalkThroughExprSlave(FILEHANDLE *curfile, LONG *counter, int dl)
3399 {
3400  LONG l=0;
3401  for(;;){
3402  if(curfile->POstop-curfile->POfill < dl){
3403  if(PF_pushScratch(curfile))
3404  return(-PF.exprbufsize-1);
3405  }
3406  curfile->POfill+=dl;
3407  curfile->POfull=curfile->POfill;
3408  l+=dl;
3409  if( l >= PF.exprbufsize){
3410  if( l == PF.exprbufsize){
3411  /*
3412  * This access is valid because PF.exprbufsize+1 WORDs are
3413  * broadcasted, this shortcut is not mandatory though. (TU 15 Sep 2011)
3414  */
3415  if( *(curfile->POfill) == 0)/*expression is ready*/
3416  return(0);
3417  }
3418  l-=PF.exprbufsize;
3419  curfile->POfill-=l;
3420  curfile->POfull=curfile->POfill;
3421  return l+1;
3422  }
3423 
3424  dl=*(curfile->POfill);
3425  if(dl == 0)
3426  return l-PF.exprbufsize;
3427  (*counter)++;
3428  if(dl<0){/*compressed term*/
3429  if(curfile->POstop-curfile->POfill < 1){
3430  if(PF_pushScratch(curfile))
3431  return(-PF.exprbufsize-1);
3432  }
3433  /*
3434  * This access is always valid because PF.exprbufsize+1 WORDs are
3435  * broadcasted. (TU 15 Sep 2011)
3436  */
3437  dl=*(curfile->POfill+1)+2;
3438  }/*if(*(curfile->POfill)<0)*/
3439  }/*for(;;)*/
3440 }
3441 
3442 /*
3443  #] PF_WalkThroughExprSlave :
3444  #[ PF_rhsBCastMaster :
3445 */
3446 
3454 static int PF_rhsBCastMaster(FILEHANDLE *curfile, EXPRESSIONS e)
3455 {
3456  LONG l=1;/*PF_WalkThroughExpr returns length + 1*/
3457  SetScratch(curfile,&(e->onfile));
3458  do{
3459  /*
3460  * We need to broadcast PF.exprbufsize+1 WORDs because PF_WalkThroughExprSlave
3461  * may access to an additional 1 WORD. It is better to rewrite the routines
3462  * in such a way as to broadcast only PF.exprbufsize WORDs. (TU 15 Sep 2011)
3463  */
3464  if ( curfile->POfull - curfile->POfill < PF.exprbufsize + 1 ) {
3465  POSITION pos;
3466  SeekScratch(curfile,&pos);
3467  PF_SetScratch(curfile,&pos);
3468  }
3469  if ( PF_Bcast(curfile->POfill, (PF.exprbufsize + 1) * sizeof(WORD)) )
3470  return -1;
3471  l=PF_WalkThroughExprMaster(curfile,l-1);
3472  }while(l>0);
3473  if(l<0)/*The tail is extra, decrease POfill*/
3474  curfile->POfill-=l;
3475  return(0);
3476 }
3477 
3478 /*
3479  #] PF_rhsBCastMaster :
3480  #[ PF_rhsBCastSlave :
3481 */
3482 
3491 static int PF_rhsBCastSlave(FILEHANDLE *curfile, EXPRESSIONS e)
3492 {
3493  LONG l=1;/*PF_WalkThroughExpr returns length + 1*/
3494  LONG counter = 0;
3495  do{
3496  /*
3497  * We need to broadcast PF.exprbufsize+1 WORDs because PF_WalkThroughExprSlave
3498  * may access to an additional 1 WORD. It is better to rewrite the routines
3499  * in such a way as to broadcast only PF.exprbufsize WORDs. (TU 15 Sep 2011)
3500  */
3501  if ( curfile->POstop - curfile->POfill < PF.exprbufsize + 1 ) {
3502  if(PF_pushScratch(curfile))
3503  return(-1);
3504  }
3505  if ( PF_Bcast(curfile->POfill, (PF.exprbufsize + 1) * sizeof(WORD)) )
3506  return(-1);
3507  l = PF_WalkThroughExprSlave(curfile, &counter, l - 1);
3508  }while(l>0);
3509  if(l<0){/*The tail is extra, decrease POfill*/
3510  if(l<-PF.exprbufsize)/*error due to a PF_pushScratch() failure */
3511  return(-1);
3512  curfile->POfill-=l;
3513  }
3514  if ( curfile->handle >= 0 ) {
3515  if ( PF_pushScratch(curfile) ) return -1;
3516  }
3517  curfile->POfull=curfile->POfill;
3518  if ( curfile != AR.hidefile ) AR.InInBuf = curfile->POfull-curfile->PObuffer;
3519  else AR.InHiBuf = curfile->POfull-curfile->PObuffer;
3520  CHECK(counter == e->counter + 1); /* The first term is the prototype. */
3521  return(0);
3522 }
3523 
3524 /*
3525  #] PF_rhsBCastSlave :
3526  #[ PF_BroadcastExpr :
3527 */
3528 
3537 {
3538  if ( PF.me == MASTER ) {
3539  if ( PF_rhsBCastMaster(file, e) ) return -1;
3540 #ifdef PF_DEBUG_BCAST_RHSEXPR
3541  MesPrint(">> Broadcast RhsExpr: %s", AC.exprnames->namebuffer + e->name);
3542 #endif
3543  }
3544  else {
3545  POSITION pos;
3546  SetEndHScratch(file, &pos);
3547  e->onfile = pos;
3548  if ( PF_rhsBCastSlave(file, e) ) return -1;
3549  }
3550  return 0;
3551 }
3552 
3553 /*
3554  #] PF_BroadcastExpr :
3555  #[ PF_BroadcastRHS :
3556 */
3557 
3565 {
3566  int i;
3567  for ( i = 0; i < NumExpressions; i++ ) {
3568  EXPRESSIONS e = &Expressions[i];
3569  if ( !(e->vflags & ISINRHS) ) continue;
3570  switch ( e->status ) {
3571  case LOCALEXPRESSION:
3572  case SKIPLEXPRESSION:
3573  case DROPLEXPRESSION:
3574  case GLOBALEXPRESSION:
3575  case SKIPGEXPRESSION:
3576  case DROPGEXPRESSION:
3577  case HIDELEXPRESSION:
3578  case HIDEGEXPRESSION:
3579  case INTOHIDELEXPRESSION:
3580  case INTOHIDEGEXPRESSION:
3581  if ( PF_BroadcastExpr(e, AR.infile) ) return -1;
3582  break;
3583  case HIDDENLEXPRESSION:
3584  case HIDDENGEXPRESSION:
3585  case DROPHLEXPRESSION:
3586  case DROPHGEXPRESSION:
3587  case UNHIDELEXPRESSION:
3588  case UNHIDEGEXPRESSION:
3589  if ( PF_BroadcastExpr(e, AR.hidefile) ) return -1;
3590  break;
3591  }
3592  }
3593  if ( PF.me != MASTER )
3594  UpdatePositions();
3595  return 0;
3596 }
3597 
3598 /*
3599  #] PF_BroadcastRHS :
3600  #] Broadcasting RHS expressions :
3601  #[ InParallel mode :
3602  #[ PF_InParallelProcessor :
3603 */
3604 
3612 {
3613  GETIDENTITY
3614  int i, next,tag;
3615  EXPRESSIONS e;
3616  /*
3617  * Skip expressions with zero terms. All the master and slaves need to
3618  * change the "partodo" flag.
3619  */
3620  if ( PF.numtasks >= 3 ) {
3621  for ( i = 0; i < NumExpressions; i++ ) {
3622  e = Expressions + i;
3623  if ( e->partodo > 0 && e->counter == 0 ) {
3624  e->partodo = 0;
3625  }
3626  }
3627  }
3628  if(PF.me == MASTER){
3629  if ( PF.numtasks >= 3 ) {
3630  partodoexr = (WORD*)Malloc1(sizeof(WORD)*(PF.numtasks+1),"PF_InParallelProcessor");
3631  for ( i = 0; i < NumExpressions; i++ ) {
3632  e = Expressions+i;
3633  if ( e->partodo <= 0 ) continue;
3634  switch(e->status){
3635  case LOCALEXPRESSION:
3636  case GLOBALEXPRESSION:
3637  case UNHIDELEXPRESSION:
3638  case UNHIDEGEXPRESSION:
3639  case INTOHIDELEXPRESSION:
3640  case INTOHIDEGEXPRESSION:
3641  tag=PF_ANY_SOURCE;
3642  next=PF_Wait4SlaveIP(&tag);
3643  if(next<0)
3644  return(-1);
3645  if(tag == PF_DATA_MSGTAG){
3646  PF_Statistics(PF_stats,0);
3647  if(PF_Slave2MasterIP(next))
3648  return(-1);
3649  }
3650  if(PF_Master2SlaveIP(next,e))
3651  return(-1);
3652  partodoexr[next]=i;
3653  break;
3654  default:
3655  e->partodo = 0;
3656  continue;
3657  }/*switch(e->status)*/
3658  }/*for ( i = 0; i < NumExpressions; i++ )*/
3659  /*Here some slaves are working, other are waiting on PF_Send.
3660  Wait all of them.*/
3661  /*At this point no new slaves may be launched so PF_WaitAllSlaves()
3662  does not modify partodoexr[].*/
3663  if(PF_WaitAllSlaves())
3664  return(-1);
3665 
3666  if ( AC.CollectFun ) AR.DeferFlag = 0;
3667  if(partodoexr){
3668  M_free(partodoexr,"PF_InParallelProcessor");
3669  partodoexr=NULL;
3670  }/*if(partodoexr)*/
3671  }/*if ( PF.numtasks >= 3 ) */
3672  else {
3673  for ( i = 0; i < NumExpressions; i++ ) {
3674  Expressions[i].partodo = 0;
3675  }
3676  }
3677  return(0);
3678  }/*if(PF.me == MASTER)*/
3679  /*Slave:*/
3680  if(PF_Wait4MasterIP(PF_EMPTY_MSGTAG))
3681  return(-1);
3682  /*master is ready to listen to me*/
3683  do{
3684  WORD *oldwork= AT.WorkPointer;
3685  tag=PF_ReadMaster();/*reads directly to its scratch!*/
3686  if(tag<0)
3687  return(-1);
3688  if(tag == PF_DATA_MSGTAG){
3689  oldwork = AT.WorkPointer;
3690 
3691  /* For redefine statements. */
3692  if ( AC.numpfirstnum > 0 ) {
3693  int j;
3694  for ( j = 0; j < AC.numpfirstnum; j++ ) {
3695  AC.inputnumbers[j] = -1;
3696  }
3697  }
3698 
3699  if(PF_DoOneExpr())/*the processor*/
3700  return(-1);
3701  if(PF_Wait4MasterIP(PF_DATA_MSGTAG))
3702  return(-1);
3703  if(PF_Slave2MasterIP(PF.me))/*both master and slave*/
3704  return(-1);
3705  AT.WorkPointer=oldwork;
3706  }/*if(tag == PF_DATA_MSGTAG)*/
3707  }while(tag!=PF_EMPTY_MSGTAG);
3708  PF.exprtodo=-1;
3709  return(0);
3710 }/*PF_InParallelProcessor*/
3711 
3712 /*
3713  #] PF_InParallelProcessor :
3714  #[ PF_Wait4MasterIP :
3715 */
3716 
3717 static int PF_Wait4MasterIP(int tag)
3718 {
3719  int follow = 0;
3720  LONG cpu,space = 0;
3721 
3722  if(PF.log){
3723  fprintf(stderr,"[%d] Starting to send to Master\n",PF.me);
3724  fflush(stderr);
3725  }
3726 
3727  PF_PreparePack();
3728  cpu = TimeCPU(1);
3729  PF_Pack(&cpu ,1,PF_LONG);
3730  PF_Pack(&space ,1,PF_LONG);
3731  PF_Pack(&PF_linterms ,1,PF_LONG);
3732  PF_Pack(&(AM.S0->GenTerms) ,1,PF_LONG);
3733  PF_Pack(&(AM.S0->TermsLeft),1,PF_LONG);
3734  PF_Pack(&follow ,1,PF_INT );
3735 
3736  if(PF.log){
3737  fprintf(stderr,"[%d] Now sending with tag = %d\n",PF.me,tag);
3738  fflush(stderr);
3739  }
3740 
3741  PF_Send(MASTER, tag);
3742 
3743  if(PF.log){
3744  fprintf(stderr,"[%d] returning from send\n",PF.me);
3745  fflush(stderr);
3746  }
3747  return(0);
3748 }
3749 /*
3750  #] PF_Wait4MasterIP :
3751  #[ PF_DoOneExpr :
3752 */
3753 
3761 static int PF_DoOneExpr(void)/*the processor*/
3762 {
3763  GETIDENTITY
3764  EXPRESSIONS e;
3765  int i;
3766  WORD *term;
3767  POSITION position, outposition;
3768  FILEHANDLE *fi, *fout;
3769  LONG dd = 0;
3770  WORD oldBracketOn = AR.BracketOn;
3771  WORD *oldBrackBuf = AT.BrackBuf;
3772  WORD oldbracketindexflag = AT.bracketindexflag;
3773  e = Expressions + PF.exprtodo;
3774  i = PF.exprtodo;
3775  AR.CurExpr = i;
3776  AR.SortType = AC.SortType;
3777  AR.expchanged = 0;
3778  if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
3779  AR.BracketOn = 1;
3780  AT.BrackBuf = AM.BracketFactors;
3781  AT.bracketindexflag = 1;
3782  }
3783 
3784  position = AS.OldOnFile[i];
3785  if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION ) {
3786  AR.GetFile = 2; fi = AR.hidefile;
3787  }
3788  else {
3789  AR.GetFile = 0; fi = AR.infile;
3790  }
3791 /*
3792  PUTZERO(fi->POposition);
3793  if ( fi->handle >= 0 ) {
3794  fi->POfill = fi->POfull = fi->PObuffer;
3795  }
3796 */
3797  SetScratch(fi,&position);
3798  term = AT.WorkPointer;
3799  AR.CompressPointer = AR.CompressBuffer;
3800  AR.CompressPointer[0] = 0;
3801  AR.KeptInHold = 0;
3802  if ( GetTerm(BHEAD term) <= 0 ) {
3803  MesPrint("Expression %d has problems in scratchfile",i);
3804  Terminate(-1);
3805  }
3806  if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
3807  term[3] = i;
3808  PUTZERO(outposition);
3809  fout = AR.outfile;
3810  fout->POfill = fout->POfull = fout->PObuffer;
3811  fout->POposition = outposition;
3812  if ( fout->handle >= 0 ) {
3813  fout->POposition = outposition;
3814  }
3815 /*
3816  The next statement is needed because we need the system
3817  to believe that the expression is at position zero for
3818  the moment. In this worker, with no memory of other expressions,
3819  it is. This is needed for when a bracket index is made
3820  because there e->onfile is an offset. Afterwards, when the
3821  expression is written to its final location in the masters
3822  output e->onfile will get its real value.
3823 */
3824  PUTZERO(e->onfile);
3825  if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) return -1;
3826 
3827  AR.DeferFlag = AC.ComDefer;
3828 
3829 /* AR.sLevel = AB[0]->R.sLevel;*/
3830  term = AT.WorkPointer;
3831  NewSort(BHEAD0);
3832  AR.MaxDum = AM.IndDum;
3833  AN.ninterms = 0;
3834  while ( GetTerm(BHEAD term) ) {
3835  SeekScratch(fi,&position);
3836  AN.ninterms++; dd = AN.deferskipped;
3837  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
3838  StoreTerm(BHEAD term);
3839  }
3840  else {
3841  if ( AC.CollectFun && *term <= (AM.MaxTer/(2*(LONG)sizeof(WORD))) ) {
3842  if ( GetMoreTerms(term) < 0 ) {
3843  LowerSortLevel(); return(-1);
3844  }
3845  SeekScratch(fi,&position);
3846  }
3847  AT.WorkPointer = term + *term;
3848  AN.RepPoint = AT.RepCount + 1;
3849  if ( AR.DeferFlag ) {
3850  AR.CurDum = AN.IndDum = Expressions[PF.exprtodo].numdummies;
3851  }
3852  else {
3853  AN.IndDum = AM.IndDum;
3854  AR.CurDum = ReNumber(BHEAD term);
3855  }
3856  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
3857  if ( AN.ncmod ) {
3858  if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
3859  else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
3860  }
3861  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
3862  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
3863  && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
3864  PolyFunClean(BHEAD term);
3865  }
3866  if ( Generator(BHEAD term,0) ) {
3867  LowerSortLevel(); return(-1);
3868  }
3869  AN.ninterms += dd;
3870  }
3871  SetScratch(fi,&position);
3872  if ( fi == AR.hidefile ) {
3873  AR.InHiBuf = (fi->POfull-fi->PObuffer)
3874  -DIFBASE(position,fi->POposition)/sizeof(WORD);
3875  }
3876  else {
3877  AR.InInBuf = (fi->POfull-fi->PObuffer)
3878  -DIFBASE(position,fi->POposition)/sizeof(WORD);
3879  }
3880  }
3881  AN.ninterms += dd;
3882  if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) return(-1);
3883  e->numdummies = AR.MaxDum - AM.IndDum;
3884  AR.BracketOn = oldBracketOn;
3885  AT.BrackBuf = oldBrackBuf;
3886  if ( ( e->vflags & TOBEFACTORED ) != 0 )
3888  else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
3889  && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
3890  poly_unfactorize_expression(e);
3891  if ( AM.S0->TermsLeft ) e->vflags &= ~ISZERO;
3892  else e->vflags |= ISZERO;
3893  if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
3894 /* if ( AM.S0->TermsLeft ) AR.expflags |= ISZERO;
3895  if ( AR.expchanged ) AR.expflags |= ISUNMODIFIED;*/
3896  AR.GetFile = 0;
3897  AT.bracketindexflag = oldbracketindexflag;
3898 
3899  fout->POfull = fout->POfill;
3900  return(0);
3901 }
3902 
3903 /*
3904  #] PF_DoOneExpr :
3905  #[ PF_Slave2MasterIP :
3906 */
3907 
3908 typedef struct bufIPstruct {
3909  LONG i;
3910  struct ExPrEsSiOn e;
3911 } bufIPstruct_t;
3912 
3913 static int PF_Slave2MasterIP(int src)/*both master and slave*/
3914 {
3915  EXPRESSIONS e;
3916  bufIPstruct_t exprData;
3917  int i,l;
3918  FILEHANDLE *fout=AR.outfile;
3919  POSITION pos;
3920  /*Here we know the length of data to send in advance:
3921  slave has the only one expression in its scratch file, and it sends
3922  this information to the master.*/
3923  if(PF.me != MASTER){/*slave*/
3924  e = Expressions + PF.exprtodo;
3925  /*Fill in the expression data:*/
3926  memcpy(&(exprData.e), e, sizeof(struct ExPrEsSiOn));
3927  SeekScratch(fout,&pos);
3928  exprData.i=BASEPOSITION(pos);
3929  /*Send the metadata:*/
3930  if(PF_RawSend(MASTER,&exprData,sizeof(bufIPstruct_t),0))
3931  return(-1);
3932  i=exprData.i;
3933  SETBASEPOSITION(pos,0);
3934  do{
3935  int blen=PF.exprbufsize*sizeof(WORD);
3936  if(i<blen)
3937  blen=i;
3938  l=PF_SendChunkIP(fout,&pos, MASTER, blen);
3939  /*Here always l == blen!*/
3940  if(l<0)
3941  return(-1);
3942  ADDPOS(pos,l);
3943  i-=l;
3944  }while(i>0);
3945  if ( fout->handle >= 0 ) { /* Now get rid of the file */
3946  CloseFile(fout->handle);
3947  fout->handle = -1;
3948  remove(fout->name);
3949  PUTZERO(fout->POposition);
3950  PUTZERO(fout->filesize);
3951  fout->POfill = fout->POfull = fout->PObuffer;
3952  }
3953  /* Now handle redefined preprocessor variables. */
3954  if ( AC.numpfirstnum > 0 ) {
3956  PF_PackRedefinedPreVars();
3957  PF_LongSingleSend(MASTER, PF_MISC_MSGTAG);
3958  }
3959  return(0);
3960  }/*if(PF.me != MASTER)*/
3961  /*Master*/
3962  /*partodoexr[src] is the number of expression.*/
3963  e = Expressions +partodoexr[src];
3964  /*Get metadata:*/
3965  if (PF_RawRecv(&src, &exprData,sizeof(bufIPstruct_t),&i)!= sizeof(bufIPstruct_t))
3966  return(-1);
3967  /*Fill in the expression data:*/
3968 /* memcpy(e, &(exprData.e), sizeof(struct ExPrEsSiOn)); */
3969  e->counter = exprData.e.counter;
3970  e->vflags = exprData.e.vflags;
3971  e->numdummies = exprData.e.numdummies;
3972  e->numfactors = exprData.e.numfactors;
3973  if ( !(e->vflags & ISZERO) ) AR.expflags |= ISZERO;
3974  if ( !(e->vflags & ISUNMODIFIED) ) AR.expflags |= ISUNMODIFIED;
3975  SeekScratch(fout,&pos);
3976  e->onfile = pos;
3977  i=exprData.i;
3978  while(i>0){
3979  int blen=PF.exprbufsize*sizeof(WORD);
3980  if(i<blen)
3981  blen=i;
3982  l=PF_RecvChunkIP(fout,src,blen);
3983  /*Here always l == blen!*/
3984  if(l<0)
3985  return(-1);
3986  i-=l;
3987  }
3988  /* Now handle redefined preprocessor variables. */
3989  if ( AC.numpfirstnum > 0 ) {
3990  PF_LongSingleReceive(src, PF_MISC_MSGTAG, NULL, NULL);
3991  PF_UnpackRedefinedPreVars();
3992  }
3993  return(0);
3994 }
3995 
3996 /*
3997  #] PF_Slave2MasterIP :
3998  #[ PF_Master2SlaveIP :
3999 */
4000 
4001 static int PF_Master2SlaveIP(int dest, EXPRESSIONS e)
4002 {
4003  bufIPstruct_t exprData;
4004  FILEHANDLE *fi;
4005  POSITION pos;
4006  int l;
4007  LONG ll=0,count=0;
4008  WORD *t;
4009  if(e==NULL){/*Say to the slave that no more job:*/
4010  if(PF_RawSend(dest,&exprData,sizeof(bufIPstruct_t),PF_EMPTY_MSGTAG))
4011  return(-1);
4012  return(0);
4013  }
4014  memcpy(&(exprData.e), e, sizeof(struct ExPrEsSiOn));
4015  exprData.i=e-Expressions;
4016  if ( AC.StatsFlag && AC.OldParallelStats ) {
4017  MesPrint("");
4018  MesPrint(" Sending expression %s to slave %d",EXPRNAME(exprData.i),dest);
4019  }
4020  if(PF_RawSend(dest,&exprData,sizeof(bufIPstruct_t),PF_DATA_MSGTAG))
4021  return(-1);
4022  if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION )
4023  fi = AR.hidefile;
4024  else
4025  fi = AR.infile;
4026  pos=e->onfile;
4027  SetScratch(fi,&pos);
4028  do{
4029  l=PF_SendChunkIP(fi, &pos, dest, PF.exprbufsize*sizeof(WORD));
4030  if(l<0)
4031  return(-1);
4032  t=fi->PObuffer+ (DIFBASE(pos,fi->POposition))/sizeof(WORD);
4033  ll=PF_WalkThrough(t,ll,l/sizeof(WORD),&count);
4034  ADDPOS(pos,l);
4035  }while(ll>-2);
4036  return(0);
4037 }
4038 
4039 /*
4040  #] PF_Master2SlaveIP :
4041  #[ PF_ReadMaster :
4042 */
4043 
4044 static int PF_ReadMaster(void)/*reads directly to its scratch!*/
4045 {
4046  bufIPstruct_t exprData;
4047  int tag,m=MASTER;
4048  EXPRESSIONS e;
4049  FILEHANDLE *fi;
4050  POSITION pos;
4051  LONG count=0;
4052  WORD *t;
4053  LONG ll=0;
4054  int l;
4055  /*Get metadata:*/
4056  if (PF_RawRecv(&m, &exprData,sizeof(bufIPstruct_t),&tag)!= sizeof(bufIPstruct_t))
4057  return(-1);
4058 
4059  if(tag == PF_EMPTY_MSGTAG)/*No data, no job*/
4060  return(tag);
4061 
4062  /*data expected, tag must be == PF_DATA_MSTAG!*/
4063  PF.exprtodo=exprData.i;
4064  e=Expressions + PF.exprtodo;
4065  /*Fill in the expression data:*/
4066 /* memcpy(e, &(exprData.e), sizeof(struct ExPrEsSiOn)); */
4067  if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION )
4068  fi = AR.hidefile;
4069  else
4070  fi = AR.infile;
4071  SetEndHScratch(fi,&pos);
4072  e->onfile=AS.OldOnFile[PF.exprtodo]=pos;
4073 
4074  do{
4075  l=PF_RecvChunkIP(fi,MASTER,PF.exprbufsize*sizeof(WORD));
4076  if(l<0)
4077  return(-1);
4078  t=fi->POfull-l/sizeof(WORD);
4079  ll=PF_WalkThrough(t,ll,l/sizeof(WORD),&count);
4080  }while(ll>-2);
4081  /*Now -ll-2 is the number of "extra" elements transferred from the master.*/
4082  fi->POfull-=-ll-2;
4083  fi->POfill=fi->POfull;
4084  return(PF_DATA_MSGTAG);
4085 }
4086 
4087 /*
4088  #] PF_ReadMaster :
4089  #[ PF_SendChunkIP :
4090  thesize is in bytes. Returns the number of sent bytes or <0 on error:
4091 */
4092 
4093 static int PF_SendChunkIP(FILEHANDLE *curfile, POSITION *position, int to, LONG thesize)
4094 {
4095  LONG l=thesize;
4096  if(
4097  ISLESSPOS(*position,curfile->POposition) ||
4098  ISGEPOSINC(*position,curfile->POposition,
4099  ((curfile->POfull-curfile->PObuffer)*sizeof(WORD)-thesize) )
4100  ){
4101  if(curfile->handle< 0)
4102  l=(curfile->POfull-curfile->PObuffer)*sizeof(WORD) - (LONG)(position->p1);
4103  else{
4104  PF_SetScratch(curfile,position);
4105  if(
4106  ISGEPOSINC(*position,curfile->POposition,
4107  ((curfile->POfull-curfile->PObuffer)*sizeof(WORD)-thesize) )
4108  )
4109  l=(curfile->POfull-curfile->PObuffer)*sizeof(WORD) - (LONG)position->p1;
4110  }
4111  }
4112  /*Now we are able to sent l bytes from the
4113  curfile->PObuffer[position-curfile->POposition]*/
4114  if(PF_RawSend(to,curfile->PObuffer+ (DIFBASE(*position,curfile->POposition))/sizeof(WORD),l,0))
4115  return(-1);
4116  return(l);
4117 }
4118 
4119 /*
4120  #] PF_SendChunkIP :
4121  #[ PF_RecvChunkIP :
4122  thesize is in bytes. Returns the number of sent bytes or <0 on error:
4123 */
4124 
4125 static int PF_RecvChunkIP(FILEHANDLE *curfile, int from, LONG thesize)
4126 {
4127  LONG receivedBytes;
4128 
4129  if( (LONG)((curfile->POstop - curfile->POfull)*sizeof(WORD)) < thesize )
4130  if(PF_pushScratch(curfile))
4131  return(-1);
4132  /*Now there is enough space from curfile->POfill to curfile->POstop*/
4133  {/*Block:*/
4134  int tag=0;
4135  receivedBytes=PF_RawRecv(&from,curfile->POfull,thesize,&tag);
4136  }/*:Block*/
4137  if(receivedBytes >= 0 ){
4138  curfile->POfull+=receivedBytes/sizeof(WORD);
4139  curfile->POfill=curfile->POfull;
4140  }/*if(receivedBytes >= 0 )*/
4141  return(receivedBytes);
4142 }
4143 
4144 /*
4145  #] PF_RecvChunkIP :
4146  #[ PF_WalkThrough :
4147  Returns:
4148  >= 0 -- initial offset,
4149  -1 -- the first element of t contains the length of the tail of compressed term,
4150  <= -2 -- -(d+2), where d is the number of extra transferred elements.
4151  Expects:
4152  l -- initial offset or -1,
4153  chunk -- number of transferred elements (not bytes!)
4154  *count -- incremented each time a new term is found
4155 */
4156 
4157 static int PF_WalkThrough(WORD *t, LONG l, LONG chunk, LONG *count)
4158 {
4159  if(l<0) /*==-1!*/
4160  l=(*t)+1;/*the first element of t contains the length of
4161  the tail of compressed term*/
4162  else{
4163  if(l>=chunk)/*next term is out of the chunk*/
4164  return(l-chunk);
4165  t+=l;
4166  chunk-=l;/*note, l was less than chunk so chunk >0!*/
4167  l=*t;
4168  }
4169  /*Main loop:*/
4170  while(l!=0){
4171  if(l>0){/*an offset to the next term*/
4172  if(l<chunk){
4173  t+=l;
4174  chunk-=l;/*note, l was less than chunk so chunk >0!*/
4175  l=*t;
4176  (*count)++;
4177  }/*if(l<chunk)*/
4178  else
4179  return(l-chunk);
4180  }/*if(l>0)*/
4181  else{ /* l<0 */
4182  if(chunk < 2)/*i.e., chunk == 1*/
4183  return(-1);/*the first WORD in the next chunk is length of the tail of the compressed term*/
4184  l=*(t+1)+2;/*+2 since
4185  1. t points to the length field -1,
4186  2. the size of a tail of compressed term is equal to the number of WORDs in this tail*/
4187  }
4188  }/*while(l!=0)*/
4189  return(-1-chunk);/* -(2+(chunk-1)), chunk>0 ! */
4190 }
4191 
4192 /*
4193  #] PF_WalkThrough :
4194  #] InParallel mode :
4195  #[ PF_SendFile :
4196 */
4197 
4198 #define PF_SNDFILEBUFSIZE 4096
4199 
4207 int PF_SendFile(int to, FILE *fd)
4208 {
4209  size_t len=0;
4210  if(fd == NULL){
4211  if(PF_RawSend(to,&to,sizeof(int),PF_EMPTY_MSGTAG))
4212  return(-1);
4213  return(0);
4214  }
4215  for(;;){
4216  char buf[PF_SNDFILEBUFSIZE];
4217  size_t l;
4218  l=fread(buf, 1, PF_SNDFILEBUFSIZE, fd);
4219  len+=l;
4220  if(l==PF_SNDFILEBUFSIZE){
4221  if(PF_RawSend(to,buf,PF_SNDFILEBUFSIZE,PF_BUFFER_MSGTAG))
4222  return(-1);
4223  }
4224  else{
4225  if(PF_RawSend(to,buf,l,PF_ENDBUFFER_MSGTAG))
4226  return(-1);
4227  break;
4228  }
4229  }/*for(;;)*/
4230  return(len);
4231 }
4232 
4233 /*
4234  #] PF_SendFile :
4235  #[ PF_RecvFile :
4236 */
4237 
4245 int PF_RecvFile(int from, FILE *fd)
4246 {
4247  size_t len=0;
4248  int tag;
4249  do{
4250  char buf[PF_SNDFILEBUFSIZE];
4251  int l;
4252  l=PF_RawRecv(&from,buf,PF_SNDFILEBUFSIZE,&tag);
4253  if(l<0)
4254  return(-1);
4255  if(tag == PF_EMPTY_MSGTAG)
4256  return(-1);
4257 
4258  if( fwrite(buf,l,1,fd)!=1 )
4259  return(-1);
4260  len+=l;
4261  }while(tag!=PF_ENDBUFFER_MSGTAG);
4262  return(len);
4263 }
4264 
4265 /*
4266  #] PF_RecvFile :
4267  #[ Synchronised output :
4268  #[ Explanations :
4269 */
4270 
4271 /*
4272  * If the master and slaves output statistics or error messages to the same stream
4273  * or file (e.g., the standard output or the log file) simultaneously, then
4274  * a mixing of their outputs can occur. To avoid this, TFORM uses a lock of
4275  * ErrorMessageLock, but there is no locking functionality in the original MPI
4276  * specification. We need to synchronise the output from the master and slaves.
4277  *
4278  * The idea of the synchronised output (by, e.g., MesPrint()) implemented here is
4279  * Slaves:
4280  * 1. Save the output by WriteFile() (set to PF_WriteFileToFile())
4281  * into some buffers between MLOCK(ErrorMessageLock) and
4282  * MUNLOCK(ErrorMessageLock), which call PF_MLock() and PF_MUnlock(),
4283  * respectively. The output for AM.StdOut and AC.LogHandle are saved to
4284  * the buffers.
4285  * 2. At MUNLOCK(ErrorMessageLock), send the output in the buffer to the master,
4286  * with PF_STDOUT_MSGTAG or PF_LOG_MSGTAG.
4287  * Master:
4288  * 1. Receive the buffered output from slaves, and write them by
4289  * WriteFileToFile().
4290  * The main problem is how and where the master receives messages from
4291  * the slaves (PF_ReceiveErrorMessage()). For this purpose there are three
4292  * helper functions: PF_CatchErrorMessages() and PF_CatchErrorMessagesForAll()
4293  * which remove messages with PF_STDOUT_MSGTAG or PF_LOG_MSGTAG from the top
4294  * of the message queue, and PF_ProbeWithCatchingErrorMessages() which is same as
4295  * PF_Probe() except removing these messages.
4296  */
4297 
4298 /*
4299  #] Explanations :
4300  #[ Variables :
4301 */
4302 
4303 static int errorMessageLock = 0; /* (slaves) The lock count. See PF_MLock() and PF_MUnlock(). */
4304 static Vector(UBYTE, stdoutBuffer); /* (slaves) The buffer for AM.StdOut. */
4305 static Vector(UBYTE, logBuffer); /* (slaves) The buffer for AC.LogHandle. */
4306 #define recvBuffer logBuffer /* (master) The buffer for receiving messages. */
4307 
4308 /*
4309  * If PF_ENABLE_STDOUT_BUFFERING is defined, the master performs the line buffering
4310  * (using stdoutBuffer) at PF_WriteFileToFile().
4311  */
4312 #ifndef PF_ENABLE_STDOUT_BUFFERING
4313 #ifdef UNIX
4314 #define PF_ENABLE_STDOUT_BUFFERING
4315 #endif
4316 #endif
4317 
4318 /*
4319  #] Variables :
4320  #[ PF_MLock :
4321 */
4322 
4326 void PF_MLock(void)
4327 {
4328  /* Only on slaves. */
4329  if ( errorMessageLock++ > 0 ) return;
4330  VectorClear(stdoutBuffer);
4331  VectorClear(logBuffer);
4332 }
4333 
4334 /*
4335  #] PF_MLock :
4336  #[ PF_MUnlock :
4337 */
4338 
4342 void PF_MUnlock(void)
4343 {
4344  /* Only on slaves. */
4345  if ( --errorMessageLock > 0 ) return;
4346  if ( !VectorEmpty(stdoutBuffer) ) {
4347  PF_RawSend(MASTER, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer), PF_STDOUT_MSGTAG);
4348  }
4349  if ( !VectorEmpty(logBuffer) ) {
4350  PF_RawSend(MASTER, VectorPtr(logBuffer), VectorSize(logBuffer), PF_LOG_MSGTAG);
4351  }
4352 }
4353 
4354 /*
4355  #] PF_MUnlock :
4356  #[ PF_WriteFileToFile :
4357 */
4358 
4371 LONG PF_WriteFileToFile(int handle, UBYTE *buffer, LONG size)
4372 {
4373  if ( PF.me != MASTER && errorMessageLock > 0 ) {
4374  if ( handle == AM.StdOut ) {
4375  VectorPushBacks(stdoutBuffer, buffer, size);
4376  return size;
4377  }
4378  else if ( handle == AC.LogHandle ) {
4379  VectorPushBacks(logBuffer, buffer, size);
4380  return size;
4381  }
4382  }
4383 #ifdef PF_ENABLE_STDOUT_BUFFERING
4384  /*
4385  * On my computer, sometimes a single linefeed "\n" sent to the standard
4386  * output is ignored on the execution of mpiexec. A typical example is:
4387  * $ cat foo.c
4388  * #include <unistd.h>
4389  * int main() {
4390  * write(1, " ", 4);
4391  * write(1, "\n", 1);
4392  * write(1, " ", 4);
4393  * write(1, "123\n", 4);
4394  * return 0;
4395  * }
4396  * or even as a shell script:
4397  * $ cat foo.sh
4398  * #! bin/sh
4399  * printf " "
4400  * printf "\n"
4401  * printf " "
4402  * printf "123\n"
4403  * When I ran it on mpiexec
4404  * $ while :; do mpiexec -np 1 ./foo.sh; done
4405  * I observed the single linefeed (printf "\n") was sometimes ignored. Even
4406  * though this phenomenon might be specific to my environment, I added this
4407  * code because someone may encounter a similar phenomenon and feel it
4408  * frustrating. (TU 16 Jun 2011)
4409  *
4410  * Phenomenon:
4411  * A single linefeed sent to the standard output occasionally ignored
4412  * on mpiexec.
4413  *
4414  * Environment:
4415  * openSUSE 11.4 (x86_64)
4416  * kernel: 2.6.37.6-0.5-desktop
4417  * gcc: 4.5.1 20101208
4418  * mpich2-1.3.2p1 configured with '--enable-shared --with-pm=smpd'
4419  *
4420  * Solution:
4421  * In Unix (in which Uwrite() calls write() system call without any buffering),
4422  * we perform the line buffering here. A single linefeed is also buffered.
4423  *
4424  * XXX:
4425  * At the end of the program the buffered output (text without LF) will not be flushed,
4426  * i.e., will not be written to the standard output. This is not problematic at a normal run.
4427  * The buffer can be explicitly flushed by PF_FlushStdOutBuffer().
4428  */
4429  if ( PF.me == MASTER && handle == AM.StdOut ) {
4430  size_t oldsize;
4431  /* Assume the newline character is LF (when UNIX is defined). */
4432  if ( (size > 0 && buffer[size - 1] != LINEFEED) || (size == 1 && buffer[0] == LINEFEED) ) {
4433  VectorPushBacks(stdoutBuffer, buffer, size);
4434  return size;
4435  }
4436  if ( (oldsize = VectorSize(stdoutBuffer)) > 0 ) {
4437  LONG ret;
4438  VectorPushBacks(stdoutBuffer, buffer, size);
4439  ret = WriteFileToFile(handle, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer));
4440  VectorClear(stdoutBuffer);
4441  if ( ret < 0 ) {
4442  return ret;
4443  }
4444  else if ( ret < (LONG)oldsize ) {
4445  return 0; /* This means the buffered output in previous calls is lost. */
4446  }
4447  else {
4448  return ret - (LONG)oldsize;
4449  }
4450  }
4451  }
4452 #endif
4453  return WriteFileToFile(handle, buffer, size);
4454 }
4455 
4456 /*
4457  #] PF_WriteFileToFile :
4458  #[ PF_FlushStdOutBuffer :
4459 */
4460 
4466 {
4467 #ifdef PF_ENABLE_STDOUT_BUFFERING
4468  if ( PF.me == MASTER && VectorSize(stdoutBuffer) > 0 ) {
4469  WriteFileToFile(AM.StdOut, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer));
4470  VectorClear(stdoutBuffer);
4471  }
4472 #endif
4473 }
4474 
4475 /*
4476  #] PF_FlushStdOutBuffer :
4477  #[ PF_ReceiveErrorMessage :
4478 */
4479 
4488 static void PF_ReceiveErrorMessage(int src, int tag)
4489 {
4490  /* Only on the master. */
4491  int size;
4492  int ret = PF_RawProbe(&src, &tag, &size);
4493  CHECK(ret == 0);
4494  switch ( tag ) {
4495  case PF_STDOUT_MSGTAG:
4496  case PF_LOG_MSGTAG:
4497  VectorReserve(recvBuffer, size);
4498  ret = PF_RawRecv(&src, VectorPtr(recvBuffer), size, &tag);
4499  CHECK(ret == size);
4500  if ( size > 0 ) {
4501  int handle = (tag == PF_STDOUT_MSGTAG) ? AM.StdOut : AC.LogHandle;
4502 #ifdef PF_ENABLE_STDOUT_BUFFERING
4503  if ( handle == AM.StdOut ) PF_WriteFileToFile(handle, VectorPtr(recvBuffer), size);
4504  else
4505 #endif
4506  WriteFileToFile(handle, VectorPtr(recvBuffer), size);
4507  }
4508  break;
4509  }
4510 }
4511 
4512 /*
4513  #] PF_ReceiveErrorMessage :
4514  #[ PF_CatchErrorMessages :
4515 */
4516 
4525 static void PF_CatchErrorMessages(int *src, int *tag)
4526 {
4527  /* Only on the master. */
4528  for (;;) {
4529  int asrc = *src;
4530  int atag = *tag;
4531  int ret = PF_RawProbe(&asrc, &atag, NULL);
4532  CHECK(ret == 0);
4533  if ( atag == PF_STDOUT_MSGTAG || atag == PF_LOG_MSGTAG ) {
4534  PF_ReceiveErrorMessage(asrc, atag);
4535  continue;
4536  }
4537  *src = asrc;
4538  *tag = atag;
4539  break;
4540  }
4541 }
4542 
4543 /*
4544  #] PF_CatchErrorMessages :
4545  #[ PF_CatchErrorMessagesForAll :
4546 */
4547 
4552 static void PF_CatchErrorMessagesForAll(void)
4553 {
4554  /* Only on the master. */
4555  int i;
4556  for ( i = 1; i < PF.numtasks; i++ ) {
4557  int src = i;
4558  int tag = PF_ANY_MSGTAG;
4559  PF_CatchErrorMessages(&src, &tag);
4560  }
4561 }
4562 
4563 /*
4564  #] PF_CatchErrorMessagesForAll :
4565  #[ PF_ProbeWithCatchingErrorMessages :
4566 */
4567 
4577 static int PF_ProbeWithCatchingErrorMessages(int *src)
4578 {
4579  for (;;) {
4580  int newsrc = *src;
4581  int tag = PF_Probe(&newsrc);
4582  if ( tag == PF_STDOUT_MSGTAG || tag == PF_LOG_MSGTAG ) {
4583  PF_ReceiveErrorMessage(newsrc, tag);
4584  continue;
4585  }
4586  if ( tag > 0 ) *src = newsrc;
4587  return tag;
4588  }
4589 }
4590 
4591 /*
4592  #] PF_ProbeWithCatchingErrorMessages :
4593  #[ PF_FreeErrorMessageBuffers :
4594 */
4595 
4602 {
4603  VectorFree(stdoutBuffer);
4604  VectorFree(logBuffer);
4605 }
4606 
4607 /*
4608  #] PF_FreeErrorMessageBuffers :
4609  #] Synchronised output :
4610 */
int NormalModulus(UWORD *, WORD *)
Definition: reken.c:1393
LONG * NumTerms
Definition: structs.h:945
VOID AddArgs(PHEAD WORD *, WORD *, WORD *)
Definition: sort.c:2251
int PF_Init(int *argc, char ***argv)
Definition: parallel.c:1953
void finishcbuf(WORD num)
Definition: comtool.c:89
int PF_LongSingleUnpack(void *buffer, size_t count, MPI_Datatype type)
Definition: mpi.c:1503
#define VectorInit(X)
Definition: vector.h:113
#define VectorStruct(T)
Definition: vector.h:65
int PutPreVar(UBYTE *, UBYTE *, UBYTE *, int)
Definition: pre.c:642
int PF_Pack(const void *buffer, size_t count, MPI_Datatype type)
Definition: mpi.c:642
int PF_LongSingleReceive(int src, int tag, int *psrc, int *ptag)
Definition: mpi.c:1583
int PF_BroadcastCBuf(int bufnum)
Definition: parallel.c:3133
#define VectorReserve(X, newcapacity)
Definition: vector.h:249
#define PACK_LONG(p, n)
Definition: parallel.c:135
#define Vector(T, X)
Definition: vector.h:84
void PF_BroadcastBuffer(WORD **buffer, LONG *length)
Definition: parallel.c:2110
LONG PF_RealTime(int)
Definition: mpi.c:101
int PF_Unpack(void *buffer, size_t count, MPI_Datatype type)
Definition: mpi.c:671
#define VectorPushBacks(X, src, n)
Definition: vector.h:295
int PF_IRecvRbuf(PF_BUFFER *, int, int)
Definition: mpi.c:366
Definition: structs.h:633
LONG PF_RawRecv(int *src, void *buf, LONG thesize, int *tag)
Definition: mpi.c:484
VOID WriteStats(POSITION *, WORD)
Definition: sort.c:93
void PF_MLock(void)
Definition: parallel.c:4326
Definition: parallel.c:265
int PF_BroadcastString(UBYTE *str)
Definition: parallel.c:2152
int PF_BroadcastExpFlags(void)
Definition: parallel.c:3244
int PF_PackString(const UBYTE *str)
Definition: mpi.c:706
WORD PF_Deferred(WORD *term, WORD level)
Definition: parallel.c:1208
int PF_LongMultiBroadcast(void)
Definition: mpi.c:1807
int PF_EndSort(void)
Definition: parallel.c:864
#define VectorFree(X)
Definition: vector.h:130
int PF_LibTerminate(int)
Definition: mpi.c:209
int PF_InParallelProcessor(void)
Definition: parallel.c:3611
void PF_FreeErrorMessageBuffers(void)
Definition: parallel.c:4601
LONG PF_GetSlaveTimes(void)
Definition: parallel.c:2063
WORD ** lhs
Definition: structs.h:942
int PF_BroadcastExpr(EXPRESSIONS e, FILEHANDLE *file)
Definition: parallel.c:3536
#define VectorEmpty(X)
Definition: vector.h:222
#define SWAP(x, y)
Definition: parallel.c:124
int PF_RecvWbuf(WORD *, LONG *, int *)
Definition: mpi.c:337
Definition: structs.h:938
WORD InsertTerm(PHEAD WORD *, WORD, WORD, WORD *, WORD *, WORD)
Definition: proces.c:2579
#define VectorClear(X)
Definition: vector.h:235
Definition: structs.h:293
WORD * Pointer
Definition: structs.h:941
int PF_SendFile(int to, FILE *fd)
Definition: parallel.c:4207
int PF_BroadcastRedefinedPreVars(void)
Definition: parallel.c:2991
WORD StoreTerm(PHEAD WORD *)
Definition: sort.c:4333
WORD * dimension
Definition: structs.h:947
WORD * poly_ratfun_add(PHEAD WORD *, WORD *)
Definition: polywrap.cc:600
int PF_ISendSbuf(int to, int tag)
Definition: mpi.c:261
int PF_PrepareLongMultiPack(void)
Definition: mpi.c:1643
#define UNPACK_LONG(p, n)
Definition: parallel.c:144
int PF_LongSingleSend(int to, int tag)
Definition: mpi.c:1540
LONG PF_BroadcastNumber(LONG x)
Definition: parallel.c:2083
int PF_RawProbe(int *src, int *tag, int *bytesize)
Definition: mpi.c:508
WORD ** rhs
Definition: structs.h:943
int PF_Probe(int *)
Definition: mpi.c:230
int PF_LibInit(int *, char ***)
Definition: mpi.c:123
int PF_Broadcast(void)
Definition: mpi.c:883
int PF_Bcast(void *buffer, int count)
Definition: mpi.c:440
int PF_PreparePack(void)
Definition: mpi.c:624
Definition: structs.h:1086
WORD * numdum
Definition: structs.h:946
COMPTREE * boomlijst
Definition: structs.h:948
int PF_LongSinglePack(const void *buffer, size_t count, MPI_Datatype type)
Definition: mpi.c:1469
VOID LowerSortLevel()
Definition: sort.c:4727
int PF_CollectModifiedDollars(void)
Definition: parallel.c:2495
int PF_Terminate(int errorcode)
Definition: parallel.c:2047
int PF_BroadcastPreDollar(WORD **dbuffer, LONG *newsize, int *numterms)
Definition: parallel.c:2207
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition: sort.c:1405
WORD * Buffer
Definition: structs.h:939
int PF_RawSend(int dest, void *buf, LONG l, int tag)
Definition: mpi.c:463
LONG BufferSize
Definition: structs.h:949
struct NoDe NODE
int PF_Send(int to, int tag)
Definition: mpi.c:822
WORD NewSort(PHEAD0)
Definition: sort.c:592
WORD Generator(PHEAD WORD *, WORD)
Definition: proces.c:3101
WORD * Top
Definition: structs.h:940
LONG PF_WriteFileToFile(int handle, UBYTE *buffer, LONG size)
Definition: parallel.c:4371
#define CHECK(condition)
Definition: parallel.c:153
int poly_factorize_expression(EXPRESSIONS)
Definition: polywrap.cc:1100
#define VectorSize(X)
Definition: vector.h:194
WORD FlushOut(POSITION *, FILEHANDLE *, int)
Definition: sort.c:1748
void PF_FlushStdOutBuffer(void)
Definition: parallel.c:4465
LONG TimeCPU(WORD)
Definition: tools.c:3550
int PF_PrepareLongSinglePack(void)
Definition: mpi.c:1451
int PF_UnpackString(UBYTE *str)
Definition: mpi.c:774
int PF_Processor(EXPRESSIONS e, WORD i, WORD LastExpression)
Definition: parallel.c:1540
WORD CompCoef(WORD *, WORD *)
Definition: reken.c:3037
int PF_BroadcastModifiedDollars(void)
Definition: parallel.c:2774
int PF_RecvFile(int from, FILE *fd)
Definition: parallel.c:4245
int PF_Receive(int src, int tag, int *psrc, int *ptag)
Definition: mpi.c:848
void PF_MUnlock(void)
Definition: parallel.c:4342
#define VectorPtr(X)
Definition: vector.h:150
int handle
Definition: structs.h:661
LONG EndSort(PHEAD WORD *, int)
Definition: sort.c:682
LONG * CanCommu
Definition: structs.h:944
int PF_WaitRbuf(PF_BUFFER *, int, LONG *)
Definition: mpi.c:400
int PF_BroadcastRHS(void)
Definition: parallel.c:3564
#define VectorPushBack(X, x)
Definition: vector.h:277