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 */
56LONG PF_RealTime(int);
57int PF_LibInit(int*, char***);
58int PF_LibTerminate(int);
59int PF_Probe(int*);
60int PF_RecvWbuf(WORD*,LONG*,int*);
61int PF_IRecvRbuf(PF_BUFFER*,int,int);
62int PF_WaitRbuf(PF_BUFFER *,int,LONG *);
63int PF_RawSend(int dest, void *buf, LONG l, int tag);
64LONG PF_RawRecv(int *src,void *buf,LONG thesize,int *tag);
65int PF_RawProbe(int *src, int *tag, int *bytesize);
66
67/* Private functions */
68
69static int PF_WaitAllSlaves(void);
70
71static void PF_PackRedefinedPreVars(void);
72static void PF_UnpackRedefinedPreVars(void);
73
74static int PF_Wait4MasterIP(int tag);
75static int PF_DoOneExpr(void);
76static int PF_ReadMaster(void);/*reads directly to its scratch!*/
77static int PF_Slave2MasterIP(int src);/*both master and slave*/
78static int PF_Master2SlaveIP(int dest, EXPRESSIONS e);
79static int PF_WalkThrough(WORD *t, LONG l, LONG chunk, LONG *count);
80static int PF_SendChunkIP(FILEHANDLE *curfile, POSITION *position, int to, LONG thesize);
81static int PF_RecvChunkIP(FILEHANDLE *curfile, int from, LONG thesize);
82
83static void PF_ReceiveErrorMessage(int src, int tag);
84static void PF_CatchErrorMessages(int *src, int *tag);
85static void PF_CatchErrorMessagesForAll(void);
86static int PF_ProbeWithCatchingErrorMessages(int *src);
87
88/* Variables */
89
90PARALLELVARS PF;
91#ifdef MPI2
92 WORD *PF_shared_buff;
93#endif
94
95static LONG PF_goutterms; /* (master) Total out terms at PF_EndSort(), used in PF_Statistics(). */
96static 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*/
177static LONG PF_linterms; /* local interms on this proces: PF_Proces */
178#define PF_STATS_SIZE 5
179static LONG **PF_stats = NULL;/* space for collecting statistics of all procs */
180static LONG PF_laststat; /* last realtime when statistics were printed */
181static LONG PF_statsinterval;/* timeinterval for printing statistics */
182/*
183 #] variables :
184 #[ PF_Statistics :
185*/
186
195static 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
265typedef 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*/
277static NODE *PF_root; /* root of tree of losers */
278static WORD PF_loser; /* this is the last loser */
279static WORD **PF_term; /* these point to the active terms */
280static WORD **PF_newcpos; /* new coeffs of merged terms */
281static WORD *PF_newclen; /* length of new coefficients */
282
283/*
284 preliminary: could also write somewhere else?
285*/
286
287static WORD *PF_WorkSpace; /* used in PF_EndSort() */
288static UWORD *PF_ScratchSpace; /* used in PF_GetLoser() */
289
290/*
291 #] sort variables :
292 #[ PF_AllocBuf :
293*/
294
311static 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
380static 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
524static 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] ) {
559newterms:
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
648static 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 ) {
678newright:
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*/
797cancelled:
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
864int 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
981static WORD *PF_CurrentBracket;
982
983/*
984 #] variables :
985 #[ PF_GetTerm :
986*/
987
1006static 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 ) {
1017ReceiveNew:
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);
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*/
1159strip:
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++;
1190RegRet:
1191 PRINTFBUF("PF_GetTerm returns",term,*term);
1192 return(*term);
1193}
1194
1195/*
1196 #] PF_GetTerm :
1197 #[ PF_Deferred :
1198*/
1199
1208WORD 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
1281ThatsIt:
1282/*
1283 AT.WorkPointer = oldwork;
1284*/
1285 AR.DeferFlag = 1;
1286 return(0);
1287DefCall:
1288 MesCall("PF_Deferred");
1289 SETERROR(-1);
1290}
1291
1292/*
1293 #] PF_Deferred :
1294 #[ PF_Wait4Slave :
1295*/
1296
1297static LONG **PF_W4Sstats = 0;
1298
1305static 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*/
1343static WORD *partodoexr=NULL;
1344
1352static 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
1391static 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
1540int 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 ) )
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
1953int 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 ) {
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
2047int 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
2110void 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
2152int 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
2207int 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;
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
2316static 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
2332static 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
2356static 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
2377static 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
2411static 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
2468typedef 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. */
2476static 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) ) {
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 ) {
2647 err = -1;
2648 goto cleanup;
2649 }
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");
2678cleanup:
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
2748static 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. */
2895static Vector(UBYTE, prevarbuf);
2896
2897/*
2898 #] Variables :
2899 #[ PF_PackRedefinedPreVars :
2900*/
2901
2910static 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
2945static 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. */
3064static WORD oldRhsExprInModuleFlag;
3065static Vector(WORD, oldPotModdollars);
3066static 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 */
3081int 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 */
3107int 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
3133int 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
3299static 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
3320static 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
3356static 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
3398static 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
3454static 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
3491static 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
3536int PF_BroadcastExpr(EXPRESSIONS e, FILEHANDLE *file)
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
3717static 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
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
3761static 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 ) )
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
3908typedef struct bufIPstruct {
3909 LONG i;
3910 struct ExPrEsSiOn e;
3911} bufIPstruct_t;
3912
3913static 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
4001static 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
4044static 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
4093static 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
4125static 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
4157static 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
4207int 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
4245int 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
4303static int errorMessageLock = 0; /* (slaves) The lock count. See PF_MLock() and PF_MUnlock(). */
4304static Vector(UBYTE, stdoutBuffer); /* (slaves) The buffer for AM.StdOut. */
4305static 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
4326void 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
4342void 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
4371LONG 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
4488static 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
4525static 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
4552static 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
4577static 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*/
void finishcbuf(WORD num)
Definition comtool.c:89
WORD * poly_ratfun_add(PHEAD WORD *, WORD *)
Definition polywrap.cc:600
int poly_unfactorize_expression(EXPRESSIONS)
Definition polywrap.cc:1457
WORD CompCoef(WORD *, WORD *)
Definition reken.c:3037
VOID WriteStats(POSITION *, WORD)
Definition sort.c:93
WORD NewSort(PHEAD0)
Definition sort.c:592
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition sort.c:1405
LONG EndSort(PHEAD WORD *, int)
Definition sort.c:682
WORD InsertTerm(PHEAD WORD *, WORD, WORD, WORD *, WORD *, WORD)
Definition proces.c:2579
WORD Generator(PHEAD WORD *, WORD)
Definition proces.c:3101
WORD StoreTerm(PHEAD WORD *)
Definition sort.c:4333
int poly_factorize_expression(EXPRESSIONS)
Definition polywrap.cc:1100
VOID AddArgs(PHEAD WORD *, WORD *, WORD *)
Definition sort.c:2251
int NormalModulus(UWORD *, WORD *)
Definition reken.c:1393
WORD FlushOut(POSITION *, FILEHANDLE *, int)
Definition sort.c:1748
LONG TimeCPU(WORD)
Definition tools.c:3550
int PutPreVar(UBYTE *, UBYTE *, UBYTE *, int)
Definition pre.c:642
int PF_LongSingleReceive(int src, int tag, int *psrc, int *ptag)
Definition mpi.c:1583
int PF_PackString(const UBYTE *str)
Definition mpi.c:706
int PF_LongSingleSend(int to, int tag)
Definition mpi.c:1540
int PF_PrepareLongSinglePack(void)
Definition mpi.c:1451
int PF_Unpack(void *buffer, size_t count, MPI_Datatype type)
Definition mpi.c:671
int PF_Receive(int src, int tag, int *psrc, int *ptag)
Definition mpi.c:848
int PF_Send(int to, int tag)
Definition mpi.c:822
int PF_PreparePack(void)
Definition mpi.c:624
int PF_LongSingleUnpack(void *buffer, size_t count, MPI_Datatype type)
Definition mpi.c:1503
int PF_Pack(const void *buffer, size_t count, MPI_Datatype type)
Definition mpi.c:642
int PF_PrepareLongMultiPack(void)
Definition mpi.c:1643
int PF_Broadcast(void)
Definition mpi.c:883
int PF_LongMultiBroadcast(void)
Definition mpi.c:1807
int PF_UnpackString(UBYTE *str)
Definition mpi.c:774
int PF_LongSinglePack(const void *buffer, size_t count, MPI_Datatype type)
Definition mpi.c:1469
int PF_Bcast(void *buffer, int count)
Definition mpi.c:440
int PF_ISendSbuf(int to, int tag)
Definition mpi.c:261
int PF_WaitRbuf(PF_BUFFER *, int, LONG *)
Definition mpi.c:400
void PF_MUnlock(void)
Definition parallel.c:4342
void PF_FreeErrorMessageBuffers(void)
Definition parallel.c:4601
WORD PF_Deferred(WORD *term, WORD level)
Definition parallel.c:1208
int PF_BroadcastRedefinedPreVars(void)
Definition parallel.c:2991
int PF_Init(int *argc, char ***argv)
Definition parallel.c:1953
int PF_BroadcastRHS(void)
Definition parallel.c:3564
#define CHECK(condition)
Definition parallel.c:153
LONG PF_GetSlaveTimes(void)
Definition parallel.c:2063
int PF_BroadcastExpFlags(void)
Definition parallel.c:3244
int PF_BroadcastPreDollar(WORD **dbuffer, LONG *newsize, int *numterms)
Definition parallel.c:2207
#define SWAP(x, y)
Definition parallel.c:124
int PF_BroadcastModifiedDollars(void)
Definition parallel.c:2774
int PF_RecvWbuf(WORD *, LONG *, int *)
Definition mpi.c:337
int PF_BroadcastCBuf(int bufnum)
Definition parallel.c:3133
void PF_BroadcastBuffer(WORD **buffer, LONG *length)
Definition parallel.c:2110
LONG PF_RawRecv(int *src, void *buf, LONG thesize, int *tag)
Definition mpi.c:484
int PF_CollectModifiedDollars(void)
Definition parallel.c:2495
LONG PF_WriteFileToFile(int handle, UBYTE *buffer, LONG size)
Definition parallel.c:4371
int PF_RawProbe(int *src, int *tag, int *bytesize)
Definition mpi.c:508
int PF_RecvFile(int from, FILE *fd)
Definition parallel.c:4245
int PF_IRecvRbuf(PF_BUFFER *, int, int)
Definition mpi.c:366
int PF_BroadcastString(UBYTE *str)
Definition parallel.c:2152
int PF_Terminate(int errorcode)
Definition parallel.c:2047
int PF_LibTerminate(int)
Definition mpi.c:209
void PF_FlushStdOutBuffer(void)
Definition parallel.c:4465
int PF_RawSend(int dest, void *buf, LONG l, int tag)
Definition mpi.c:463
int PF_Probe(int *)
Definition mpi.c:230
LONG PF_BroadcastNumber(LONG x)
Definition parallel.c:2083
int PF_EndSort(void)
Definition parallel.c:864
int PF_LibInit(int *, char ***)
Definition mpi.c:123
void PF_MLock(void)
Definition parallel.c:4326
int PF_SendFile(int to, FILE *fd)
Definition parallel.c:4207
int PF_Processor(EXPRESSIONS e, WORD i, WORD LastExpression)
Definition parallel.c:1540
#define PACK_LONG(p, n)
Definition parallel.c:135
int PF_BroadcastExpr(EXPRESSIONS e, FILEHANDLE *file)
Definition parallel.c:3536
#define UNPACK_LONG(p, n)
Definition parallel.c:144
LONG PF_RealTime(int)
Definition mpi.c:101
int PF_InParallelProcessor(void)
Definition parallel.c:3611
VOID LowerSortLevel()
Definition sort.c:4727
LONG BufferSize
Definition structs.h:949
WORD * numdum
Definition structs.h:946
LONG * NumTerms
Definition structs.h:945
WORD * Top
Definition structs.h:940
COMPTREE * boomlijst
Definition structs.h:948
WORD * dimension
Definition structs.h:947
WORD ** rhs
Definition structs.h:943
WORD ** lhs
Definition structs.h:942
WORD * Buffer
Definition structs.h:939
WORD * Pointer
Definition structs.h:941
LONG * CanCommu
Definition structs.h:944
int handle
Definition structs.h:661
struct CbUf CBUF
struct FiLe FILEHANDLE
struct sOrT SORTING
struct tree COMPTREE
#define Vector(T, X)
Definition vector.h:84
#define VectorStruct(T)
Definition vector.h:65
#define VectorClear(X)
Definition vector.h:235
#define VectorReserve(X, newcapacity)
Definition vector.h:249
#define VectorFree(X)
Definition vector.h:130
#define VectorSize(X)
Definition vector.h:194
#define VectorPushBack(X, x)
Definition vector.h:277
#define VectorInit(X)
Definition vector.h:113
#define VectorPtr(X)
Definition vector.h:150
#define VectorEmpty(X)
Definition vector.h:222
#define VectorPushBacks(X, src, n)
Definition vector.h:295